@openrails/contentkit-ui 0.104.0-rc.1 → 0.104.0-rc.3
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.
- package/README.md +6 -6
- package/dist/client/beacons.js +4 -1
- package/dist/client/beacons.js.map +1 -1
- package/dist/client/contents.d.ts +9 -1
- package/dist/client/contents.js +73 -55
- package/dist/client/contents.js.map +1 -1
- package/dist/client/discovery.d.ts +6 -2
- package/dist/client/discovery.js +1 -1
- package/dist/client/discovery.js.map +1 -1
- package/dist/client/generated/error-codes.d.ts +1 -1
- package/dist/client/generated/error-codes.js +4 -0
- package/dist/client/generated/error-codes.js.map +1 -1
- package/dist/client/generated/routes.d.ts +43 -30
- package/dist/client/generated/routes.js +70 -63
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +36 -74
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/media/windows.d.ts +2 -0
- package/dist/client/media/windows.js +4 -1
- package/dist/client/media/windows.js.map +1 -1
- package/dist/client/stats.d.ts +4 -20
- package/dist/client/stats.js +0 -11
- package/dist/client/stats.js.map +1 -1
- package/dist/client/versions.d.ts +8 -6
- package/dist/client/versions.js +15 -10
- package/dist/client/versions.js.map +1 -1
- package/dist/components/admin/bulk-drafts.d.ts +17 -0
- package/dist/components/admin/bulk-drafts.js +41 -0
- package/dist/components/admin/bulk-drafts.js.map +1 -0
- package/dist/components/admin/content-admin.d.ts +1 -1
- package/dist/components/admin/content-admin.js.map +1 -1
- package/dist/components/admin/content-manager.d.ts +11 -3
- package/dist/components/admin/content-manager.js +739 -380
- package/dist/components/admin/content-manager.js.map +1 -1
- package/dist/components/admin/group-manager.d.ts +8 -3
- package/dist/components/admin/group-manager.js +218 -146
- package/dist/components/admin/group-manager.js.map +1 -1
- package/dist/components/admin/page-notices.d.ts +16 -0
- package/dist/components/admin/page-notices.js +113 -0
- package/dist/components/admin/page-notices.js.map +1 -0
- package/dist/components/admin/page-picker.d.ts +38 -0
- package/dist/components/admin/page-picker.js +159 -0
- package/dist/components/admin/page-picker.js.map +1 -0
- package/dist/components/admin/reader-content-editor.js +537 -500
- package/dist/components/admin/reader-content-editor.js.map +1 -1
- package/dist/components/admin/reader-manifest.js +181 -179
- package/dist/components/admin/reader-manifest.js.map +1 -1
- package/dist/components/admin/shell.d.ts +10 -2
- package/dist/components/admin/shell.js +114 -42
- package/dist/components/admin/shell.js.map +1 -1
- package/dist/components/admin/stats-dashboard.d.ts +4 -9
- package/dist/components/admin/stats-dashboard.js +300 -202
- package/dist/components/admin/stats-dashboard.js.map +1 -1
- package/dist/components/admin/upload-queue.d.ts +14 -0
- package/dist/components/admin/upload-queue.js +115 -98
- package/dist/components/admin/upload-queue.js.map +1 -1
- package/dist/components/content/card.d.ts +31 -3
- package/dist/components/content/card.js +324 -158
- package/dist/components/content/card.js.map +1 -1
- package/dist/components/content/daily-releases.js +14 -12
- package/dist/components/content/daily-releases.js.map +1 -1
- package/dist/components/content/editor-save.js +27 -25
- package/dist/components/content/editor-save.js.map +1 -1
- package/dist/components/content/editors.js +274 -253
- package/dist/components/content/editors.js.map +1 -1
- package/dist/components/content/favorites.d.ts +1 -1
- package/dist/components/content/favorites.js +36 -22
- package/dist/components/content/favorites.js.map +1 -1
- package/dist/components/content/grid.d.ts +11 -4
- package/dist/components/content/grid.js +52 -43
- package/dist/components/content/grid.js.map +1 -1
- package/dist/components/content/history.js +83 -63
- package/dist/components/content/history.js.map +1 -1
- package/dist/components/content/index.d.ts +5 -3
- package/dist/components/content/listing.d.ts +14 -3
- package/dist/components/content/listing.js +65 -56
- package/dist/components/content/listing.js.map +1 -1
- package/dist/components/content/offer-fields.js +6 -6
- package/dist/components/content/paged-grid.d.ts +10 -0
- package/dist/components/content/paged-grid.js +116 -0
- package/dist/components/content/paged-grid.js.map +1 -0
- package/dist/components/content/pagination.d.ts +19 -0
- package/dist/components/content/pagination.js +97 -0
- package/dist/components/content/pagination.js.map +1 -0
- package/dist/components/content/paywall.d.ts +9 -0
- package/dist/components/content/paywall.js +27 -3
- package/dist/components/content/paywall.js.map +1 -1
- package/dist/components/content/post-list.d.ts +37 -0
- package/dist/components/content/post-list.js +203 -0
- package/dist/components/content/post-list.js.map +1 -0
- package/dist/components/content/reader-settings.d.ts +2 -0
- package/dist/components/content/reader-settings.js +1 -1
- package/dist/components/content/reader-settings.js.map +1 -1
- package/dist/components/groups/banner.d.ts +6 -2
- package/dist/components/groups/banner.js +79 -61
- package/dist/components/groups/banner.js.map +1 -1
- package/dist/components/groups/directory.d.ts +12 -2
- package/dist/components/groups/directory.js +168 -105
- package/dist/components/groups/directory.js.map +1 -1
- package/dist/components/groups/editor.js +10 -10
- package/dist/components/groups/editor.js.map +1 -1
- package/dist/components/groups/entity-chips.d.ts +61 -0
- package/dist/components/groups/entity-chips.js +382 -0
- package/dist/components/groups/entity-chips.js.map +1 -0
- package/dist/components/groups/group-members.d.ts +29 -0
- package/dist/components/groups/group-members.js +474 -0
- package/dist/components/groups/group-members.js.map +1 -0
- package/dist/components/groups/header.js +53 -45
- package/dist/components/groups/header.js.map +1 -1
- package/dist/components/groups/index.d.ts +3 -1
- package/dist/components/groups/memberships.d.ts +3 -36
- package/dist/components/groups/memberships.js +105 -480
- package/dist/components/groups/memberships.js.map +1 -1
- package/dist/components/groups/scoped.d.ts +23 -0
- package/dist/components/groups/scoped.js +92 -0
- package/dist/components/groups/scoped.js.map +1 -0
- package/dist/components/media-folder-editor.d.ts +5 -0
- package/dist/components/media-folder-editor.js +418 -230
- package/dist/components/media-folder-editor.js.map +1 -1
- package/dist/components/social/poll.js +57 -48
- package/dist/components/social/poll.js.map +1 -1
- package/dist/components/sortable-list.d.ts +5 -1
- package/dist/components/sortable-list.js +97 -81
- package/dist/components/sortable-list.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +41 -37
- package/dist/locales/admin/de.js +78 -45
- package/dist/locales/admin/de.js.map +1 -1
- package/dist/locales/admin/en.d.ts +74 -41
- package/dist/locales/admin/en.js +78 -45
- package/dist/locales/admin/en.js.map +1 -1
- package/dist/locales/admin/es.js +78 -45
- package/dist/locales/admin/es.js.map +1 -1
- package/dist/locales/admin/ja.js +78 -45
- package/dist/locales/admin/ja.js.map +1 -1
- package/dist/locales/admin/ko.js +78 -45
- package/dist/locales/admin/ko.js.map +1 -1
- package/dist/locales/admin/zh.js +78 -45
- package/dist/locales/admin/zh.js.map +1 -1
- package/dist/locales/de.js +2 -0
- package/dist/locales/de.js.map +1 -1
- package/dist/locales/discovery/de.js +25 -1
- package/dist/locales/discovery/de.js.map +1 -1
- package/dist/locales/discovery/en.d.ts +24 -0
- package/dist/locales/discovery/en.js +25 -1
- package/dist/locales/discovery/en.js.map +1 -1
- package/dist/locales/discovery/es.js +25 -1
- package/dist/locales/discovery/es.js.map +1 -1
- package/dist/locales/discovery/ja.js +25 -1
- package/dist/locales/discovery/ja.js.map +1 -1
- package/dist/locales/discovery/ko.js +25 -1
- package/dist/locales/discovery/ko.js.map +1 -1
- package/dist/locales/discovery/zh.js +25 -1
- package/dist/locales/discovery/zh.js.map +1 -1
- package/dist/locales/en.d.ts +120 -43
- package/dist/locales/en.js +2 -0
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +2 -0
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/groups/de.js +22 -4
- package/dist/locales/groups/de.js.map +1 -1
- package/dist/locales/groups/en.d.ts +20 -2
- package/dist/locales/groups/en.js +22 -4
- package/dist/locales/groups/en.js.map +1 -1
- package/dist/locales/groups/es.js +22 -4
- package/dist/locales/groups/es.js.map +1 -1
- package/dist/locales/groups/ja.js +22 -4
- package/dist/locales/groups/ja.js.map +1 -1
- package/dist/locales/groups/ko.js +22 -4
- package/dist/locales/groups/ko.js.map +1 -1
- package/dist/locales/groups/zh.js +22 -4
- package/dist/locales/groups/zh.js.map +1 -1
- package/dist/locales/ja.js +2 -0
- package/dist/locales/ja.js.map +1 -1
- package/dist/locales/ko.js +2 -0
- package/dist/locales/ko.js.map +1 -1
- package/dist/locales/zh.js +2 -0
- package/dist/locales/zh.js.map +1 -1
- package/dist/react/contents.js +1 -1
- package/dist/react/contents.js.map +1 -1
- package/dist/react/discovery.d.ts +16 -0
- package/dist/react/discovery.js +69 -37
- package/dist/react/discovery.js.map +1 -1
- package/dist/react/groups.d.ts +19 -3
- package/dist/react/groups.js +49 -22
- package/dist/react/groups.js.map +1 -1
- package/dist/react/index.d.ts +6 -4
- package/dist/react/page-notices.d.ts +13 -0
- package/dist/react/page-notices.js +38 -0
- package/dist/react/page-notices.js.map +1 -0
- package/dist/react/post-reads.d.ts +23 -0
- package/dist/react/post-reads.js +90 -0
- package/dist/react/post-reads.js.map +1 -0
- package/dist/react/remembered-sort.d.ts +5 -0
- package/dist/react/remembered-sort.js +29 -0
- package/dist/react/remembered-sort.js.map +1 -0
- package/dist/react/resources.js +2 -2
- package/dist/react/resources.js.map +1 -1
- package/dist/react/stats.d.ts +3 -7
- package/dist/react/stats.js +2 -6
- package/dist/react/stats.js.map +1 -1
- package/dist/react/use-engagement.d.ts +2 -0
- package/dist/react/use-engagement.js +40 -34
- package/dist/react/use-engagement.js.map +1 -1
- package/dist/react.js +29 -27
- package/dist/styles.css +1 -1
- package/dist/urls/index.d.ts +1 -1
- package/dist/urls.js +2 -2
- package/dist/urls.js.map +1 -1
- package/package.json +1 -1
- package/dist/components/admin/page-review.d.ts +0 -13
- package/dist/components/admin/page-review.js +0 -225
- package/dist/components/admin/page-review.js.map +0 -1
- package/dist/react/page-review.d.ts +0 -14
- package/dist/react/page-review.js +0 -37
- package/dist/react/page-review.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contents.js","names":[],"sources":["../../src/react/contents.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { ContentKitError } from \"../client/errors.js\";\nimport type { CatalogText, Content, ContentInput, ContentPatch, Version } from \"../client/generated/wire.js\";\nimport { IMAGE_SCHEME, imageRef, imageRefs, type ManageQuery } from \"../client/contents.js\";\nimport { useMediaRead } from \"./read.js\";\nimport { useGuarded } from \"./context.js\";\nimport { keyOf, offsetPages, useContentScope, useList, useResource, type UseList } from \"./use-resource.js\";\n\nexport interface ManageFilter extends Omit<ManageQuery, \"limit\" | \"offset\"> {\n pageSize?: number;\n}\n\n/** The content items the caller manages, newest first, a page at a time. */\nexport function useManagedContents(f: ManageFilter = {}, o: { client?: ContentKitClient } = {}): UseList<Content> {\n const { client, store, scope } = useContentScope(o.client);\n const { pageSize, ...q } = f;\n const size = pageSize ?? 20;\n return useList(\n store,\n keyOf(\"contents\", scope, q.kind, q.state, q.owner_group, q.q, q.language, size),\n { type: \"contents\", scope: q.state === \"deleted\" ? \"deleted\" : undefined },\n offsetPages(size, (page, signal) => client.contents.manage({ ...q, ...page }, signal)),\n );\n}\n\nexport interface UseContent {\n /** null before create (or while loading). */\n content: Content | null;\n loading: boolean;\n error?: ContentKitError;\n /** Writes in flight. */\n saving: boolean;\n /** Reads the item again. */\n reload: () => void;\n /** Creates the item as a draft; the hook then edits it. */\n create: (input: ContentInput) => Promise<Content>;\n update: (patch: ContentPatch) => Promise<Content>;\n /** Sets the text in the hook's language; a body from the editor is stored with image references (storedBody). */\n putText: (text: CatalogText) => Promise<Content>;\n /** Publishes now, or schedules for at. */\n publish: (at?: string) => Promise<Content>;\n unpublish: () => Promise<Content>;\n remove: () => Promise<void>;\n restore: () => Promise<Content>;\n /**\n * The version whose cover and body images the hook edits: the one asked\n * for, else the first. Every version has its own cover and its own copy of\n * the body's images.\n */\n version: Version | null;\n /** Uploads the version's cover (null returns to its first upload); resolves with a URL that shows it now. */\n setCover: (file: Blob | null) => Promise<string | null>;\n /** Uploads an image for the body into the version, copied into the others; resolves with a URL that shows it now, to place in the editor. */\n uploadImage: (file: Blob) => Promise<string>;\n /**\n * A URL that shows one of the item's images now, by name (\"i-{uuid}\") or\n * reference: a fresh upload from its file, else its public file\n * (`content.images`), else, while it has none (an unpublished item's), its\n * signed editor view from an editor read. Anything else is returned as is.\n */\n imageSrc: (image: string | null | undefined) => string | undefined;\n /** The version's cover through imageSrc. */\n coverSrc: string | undefined;\n /** The language's stored text, its body's images through imageSrc: what an editor shows. */\n text: CatalogText | undefined;\n /** HTML from the editor with every image URL this hook showed turned back into the image's reference. */\n storedBody: (html: string) => string;\n}\n\n/** The names of the images a body references, once each. */\nconst refNames = (body: string | undefined) => [...new Set([...(body ?? \"\").matchAll(imageRefs())].map((m) => m[1]!))];\nconst uploadName = (path: string) => {\n const base = path.slice(path.lastIndexOf(\"/\") + 1);\n const dot = base.lastIndexOf(\".\");\n return dot > 0 ? base.slice(0, dot) : base;\n};\n\n/**\n * One content item of kind for its editors: read, create, text in language,\n * publish, delete, restore, a version's cover and the body's images. null\n * creates a new item.\n */\nexport function useContent(\n id: string | null | undefined,\n kind: string,\n language: string,\n o: { initial?: Content; client?: ContentKitClient; version?: string } = {},\n): UseContent {\n const { client, store, scope } = useContentScope(o.client);\n const [created, setCreated] = useState<string | null>(null);\n const cid = id ?? created;\n const key = cid ? keyOf(\"content\", scope, cid) : null;\n const r = useResource<Content | null>(store, key, { type: \"content\", id: cid ?? undefined }, (s) => client.contents.get(cid!, language, s), { initial: o.initial });\n const content = r.data ?? null;\n const [inflight, setInflight] = useState(0);\n const guarded = useGuarded();\n const run = useCallback(async <T>(fn: () => Promise<T>): Promise<T> => {\n setInflight((n) => n + 1);\n try {\n return await guarded(fn);\n } finally {\n setInflight((n) => n - 1);\n }\n }, [guarded]);\n const need = useCallback(() => {\n if (!cid) throw new Error(\"contentkit-ui: create the item first\");\n return cid;\n }, [cid]);\n const stored = content?.text?.[language];\n const body = stored?.body;\n const version = useMemo(() => {\n const vs = [...(content?.versions ?? [])].sort((a, b) => a.position - b.position);\n return vs.find((v) => v.id === o.version) ?? vs[0] ?? null;\n }, [content?.versions, o.version]);\n const vid = version?.id;\n const cover = version?.cover;\n const needVersion = useCallback(() => {\n if (!vid) throw new Error(\"contentkit-ui: the item has no version yet\");\n return vid;\n }, [vid]);\n\n // Images: fresh uploads show from their file, published ones from\n // content.images, the rest (an unpublished item's) from an editor read.\n const [previews, setPreviews] = useState<ReadonlyMap<string, string>>(new Map());\n const blobs = useRef<string[]>([]);\n useEffect(() => {\n const urls = blobs.current;\n return () => {\n for (const u of urls) URL.revokeObjectURL(u);\n };\n }, []);\n const published = useMemo(() => {\n const out = new Map(Object.entries(content?.images ?? {}));\n if (cover?.image && cover.url) out.set(cover.image, cover.url);\n return out;\n }, [content?.images, cover?.image, cover?.url]);\n // The cover and the body's images are the version's.\n const coverPending = !!cover?.image && !cover.url && !previews.has(cover.image) && !published.has(cover.image);\n const bodyPending = useMemo(() => refNames(body).filter((n) => !previews.has(n) && !published.has(n)), [body, previews, published]);\n const pending = useMemo(() => (coverPending ? [...bodyPending, cover!.image!] : bodyPending), [coverPending, bodyPending, cover]);\n const folder = useMemo(() => ({ kind, id: cid ?? \"none\", version: vid }), [kind, cid, vid]);\n const folderRead = useMediaRead(folder, { editor: true, read: pending.length && vid ? undefined : null, client });\n const files = useMemo(() => folderRead.read?.files ?? [], [folderRead.read]);\n const views = useMemo(() => {\n const out = new Map<string, string>();\n for (const f of files) if (f.upload && f.editor_url) out.set(uploadName(f.path), f.editor_url);\n return out;\n }, [files]);\n // Editor views render on the first editor read that misses them: read again, backing off.\n const failed = (n: string) => files.some((f) => f.failed && uploadName(f.path) === n);\n const missing = !!folderRead.read && pending.some((n) => !views.has(n) && !failed(n));\n const tries = useRef(0);\n const reload = folderRead.reload;\n useEffect(() => {\n if (!missing) {\n tries.current = 0;\n return;\n }\n if (tries.current >= 6) return;\n const t = setTimeout(() => {\n tries.current++;\n reload();\n }, 1000 * 2 ** tries.current);\n return () => clearTimeout(t);\n }, [missing, files, reload]);\n\n // Every URL shown for an image, of this and earlier reads, back to its name.\n const shown = useRef(new Map<string, string>());\n useEffect(() => {\n for (const m of [previews, published, views]) for (const [n, u] of m) shown.current.set(u, n);\n }, [previews, published, views]);\n\n const imageSrc = useCallback(\n (image: string | null | undefined) => {\n if (!image) return undefined;\n const n = image.startsWith(IMAGE_SCHEME) ? image.slice(IMAGE_SCHEME.length) : image;\n return previews.get(n) ?? published.get(n) ?? views.get(n) ?? image;\n },\n [previews, published, views],\n );\n const text = useMemo(\n () => (stored ? { ...stored, body: (stored.body ?? \"\").replace(imageRefs(), (ref, n: string) => previews.get(n) ?? published.get(n) ?? views.get(n) ?? ref) } : undefined),\n [stored, previews, published, views],\n );\n const storedBody = useCallback(\n (html: string) => {\n const back = new Map(shown.current);\n for (const m of [previews, published, views]) for (const [n, u] of m) back.set(u, n);\n let out = html;\n for (const [u, n] of back) out = out.split(u).join(imageRef(n)).split(u.replaceAll(\"&\", \"&\")).join(imageRef(n));\n return out;\n },\n [previews, published, views],\n );\n const preview = useCallback((name: string, file: Blob): string | undefined => {\n if (typeof URL.createObjectURL !== \"function\") return undefined;\n const url = URL.createObjectURL(file);\n blobs.current.push(url);\n setPreviews((m) => new Map(m).set(name, url));\n return url;\n }, []);\n\n const create = useCallback(\n (input: ContentInput) =>\n run(async () => {\n const c = await client.contents.create(input);\n setCreated(c.id);\n return c;\n }),\n [client, run],\n );\n const update = useCallback((patch: ContentPatch) => run(() => client.contents.update(need(), patch)), [client, run, need]);\n const putText = useCallback(\n (t: CatalogText) => run(() => client.contents.putText(need(), language, t.body === undefined ? t : { ...t, body: storedBody(t.body) })),\n [client, run, need, language, storedBody],\n );\n const publish = useCallback((at?: string) => run(() => client.contents.publish(need(), at)), [client, run, need]);\n const unpublish = useCallback(() => run(() => client.contents.unpublish(need())), [client, run, need]);\n const remove = useCallback(() => run(() => client.contents.remove(need())), [client, run, need]);\n const restore = useCallback(() => run(() => client.contents.restore(need())), [client, run, need]);\n const setCover = useCallback(\n (file: Blob | null) =>\n run(async () => {\n if (!file) {\n await client.contents.setCover(need(), needVersion(), null);\n return null;\n }\n const ref = { kind, id: need(), version: needVersion() };\n const up = await client.media.uploadNamed(ref, file, { path: await client.media.presetPath(kind, \"cover\", file) });\n const saved = await client.contents.setCover(ref.id, ref.version, up.name);\n const url = preview(up.name, file) ?? saved.cover?.url ?? null;\n if (url) shown.current.set(url, up.name);\n return url;\n }),\n [client, run, need, needVersion, kind, preview],\n );\n const uploadImage = useCallback(\n (file: Blob) =>\n run(async () => {\n const up = await client.media.uploadInline({ kind, id: need(), version: needVersion() }, file);\n const url = preview(up.name, file) ?? up.url ?? up.ref;\n shown.current.set(url, up.name);\n return url;\n }),\n [client, run, need, needVersion, kind, preview],\n );\n return {\n content,\n reload: r.reload,\n loading: !!key && (r.loading || (!r.loaded && o.initial === undefined)),\n error: r.error,\n saving: inflight > 0,\n create,\n update,\n putText,\n publish,\n unpublish,\n remove,\n restore,\n version,\n setCover,\n uploadImage,\n imageSrc,\n coverSrc: cover?.image ? imageSrc(cover.image) : (cover?.url ?? undefined),\n text,\n storedBody,\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"contents.js","names":[],"sources":["../../src/react/contents.ts"],"sourcesContent":["import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { ContentKitError } from \"../client/errors.js\";\nimport type { CatalogText, Content, ContentInput, ContentPatch, Version } from \"../client/generated/wire.js\";\nimport { IMAGE_SCHEME, imageRef, imageRefs, type ManageQuery } from \"../client/contents.js\";\nimport { useMediaRead } from \"./read.js\";\nimport { useGuarded } from \"./context.js\";\nimport { keyOf, offsetPages, useContentScope, useList, useResource, type UseList } from \"./use-resource.js\";\n\nexport interface ManageFilter extends Omit<ManageQuery, \"limit\" | \"offset\"> {\n pageSize?: number;\n}\n\n/** The content items the caller manages, newest first, a page at a time. */\nexport function useManagedContents(f: ManageFilter = {}, o: { client?: ContentKitClient } = {}): UseList<Content> {\n const { client, store, scope } = useContentScope(o.client);\n const { pageSize, ...q } = f;\n const size = pageSize ?? 20;\n return useList(\n store,\n keyOf(\"contents\", scope, q.kind, q.state, q.owner_group, q.q, q.language, size),\n { type: \"contents\", scope: q.state === \"deleted\" ? \"deleted\" : undefined },\n offsetPages(size, (page, signal) => client.contents.manage({ ...q, ...page }, signal)),\n );\n}\n\nexport interface UseContent {\n /** null before create (or while loading). */\n content: Content | null;\n loading: boolean;\n error?: ContentKitError;\n /** Writes in flight. */\n saving: boolean;\n /** Reads the item again. */\n reload: () => void;\n /** Creates the item as a draft; the hook then edits it. */\n create: (input: ContentInput) => Promise<Content>;\n update: (patch: ContentPatch) => Promise<Content>;\n /** Sets the text in the hook's language; a body from the editor is stored with image references (storedBody). */\n putText: (text: CatalogText) => Promise<Content>;\n /** Publishes now, or schedules for at. */\n publish: (at?: string) => Promise<Content>;\n unpublish: () => Promise<Content>;\n remove: () => Promise<void>;\n restore: () => Promise<Content>;\n /**\n * The version whose cover and body images the hook edits: the one asked\n * for, else the first. Every version has its own cover and its own copy of\n * the body's images.\n */\n version: Version | null;\n /** Uploads the version's cover (null returns to its first upload); resolves with a URL that shows it now. */\n setCover: (file: Blob | null) => Promise<string | null>;\n /** Uploads an image for the body into the version, copied into the others; resolves with a URL that shows it now, to place in the editor. */\n uploadImage: (file: Blob) => Promise<string>;\n /**\n * A URL that shows one of the item's images now, by name (\"i-{uuid}\") or\n * reference: a fresh upload from its file, else its public file\n * (`content.images`), else, while it has none (an unpublished item's), its\n * signed editor view from an editor read. Anything else is returned as is.\n */\n imageSrc: (image: string | null | undefined) => string | undefined;\n /** The version's cover through imageSrc. */\n coverSrc: string | undefined;\n /** The language's stored text, its body's images through imageSrc: what an editor shows. */\n text: CatalogText | undefined;\n /** HTML from the editor with every image URL this hook showed turned back into the image's reference. */\n storedBody: (html: string) => string;\n}\n\n/** The names of the images a body references, once each. */\nconst refNames = (body: string | undefined) => [...new Set([...(body ?? \"\").matchAll(imageRefs())].map((m) => m[1]!))];\nconst uploadName = (path: string) => {\n const base = path.slice(path.lastIndexOf(\"/\") + 1);\n const dot = base.lastIndexOf(\".\");\n return dot > 0 ? base.slice(0, dot) : base;\n};\n\n/**\n * One content item of kind for its editors: read, create, text in language,\n * publish, delete, restore, a version's cover and the body's images. null\n * creates a new item.\n */\nexport function useContent(\n id: string | null | undefined,\n kind: string,\n language: string,\n o: { initial?: Content; client?: ContentKitClient; version?: string } = {},\n): UseContent {\n const { client, store, scope } = useContentScope(o.client);\n const [created, setCreated] = useState<string | null>(null);\n const cid = id ?? created;\n const key = cid ? keyOf(\"content\", scope, cid) : null;\n const r = useResource<Content | null>(store, key, { type: \"content\", id: cid ?? undefined }, (s) => client.contents.get(cid!, language, s), { initial: o.initial });\n const content = r.data ?? null;\n const [inflight, setInflight] = useState(0);\n const guarded = useGuarded();\n const run = useCallback(async <T>(fn: () => Promise<T>): Promise<T> => {\n setInflight((n) => n + 1);\n try {\n return await guarded(fn);\n } finally {\n setInflight((n) => n - 1);\n }\n }, [guarded]);\n const need = useCallback(() => {\n if (!cid) throw new Error(\"contentkit-ui: create the item first\");\n return cid;\n }, [cid]);\n const stored = content?.text?.[language];\n const body = stored?.body;\n const version = useMemo(() => {\n const vs = [...(content?.versions ?? [])].sort((a, b) => a.position - b.position);\n return vs.find((v) => v.id === o.version) ?? vs[0] ?? null;\n }, [content?.versions, o.version]);\n const vid = version?.id;\n const cover = version?.cover;\n const needVersion = useCallback(() => {\n if (!vid) throw new Error(\"contentkit-ui: the item has no version yet\");\n return vid;\n }, [vid]);\n\n // Images: fresh uploads show from their file, published ones from\n // content.images, the rest (an unpublished item's) from an editor read.\n const [previews, setPreviews] = useState<ReadonlyMap<string, string>>(new Map());\n const blobs = useRef<string[]>([]);\n useEffect(() => {\n const urls = blobs.current;\n return () => {\n for (const u of urls) URL.revokeObjectURL(u);\n };\n }, []);\n const published = useMemo(() => {\n const out = new Map(Object.entries(content?.images ?? {}));\n if (cover?.image && cover.url) out.set(cover.image, cover.url);\n return out;\n }, [content?.images, cover?.image, cover?.url]);\n // The cover and the body's images are the version's.\n const coverPending = !!cover?.image && !cover.url && !previews.has(cover.image) && !published.has(cover.image);\n const bodyPending = useMemo(() => refNames(body).filter((n) => !previews.has(n) && !published.has(n)), [body, previews, published]);\n const pending = useMemo(() => (coverPending ? [...bodyPending, cover!.image!] : bodyPending), [coverPending, bodyPending, cover]);\n const folder = useMemo(() => ({ kind, id: cid ?? \"none\", version: vid }), [kind, cid, vid]);\n const folderRead = useMediaRead(folder, { editor: true, read: pending.length && vid ? undefined : null, client });\n const files = useMemo(() => folderRead.read?.files ?? [], [folderRead.read]);\n const views = useMemo(() => {\n const out = new Map<string, string>();\n for (const f of files) if (f.upload && f.editor_url) out.set(uploadName(f.path), f.editor_url);\n return out;\n }, [files]);\n // Editor views render on the first editor read that misses them: read again, backing off.\n const failed = (n: string) => files.some((f) => f.failed && uploadName(f.path) === n);\n const missing = !!folderRead.read && pending.some((n) => !views.has(n) && !failed(n));\n const tries = useRef(0);\n const reload = folderRead.reload;\n useEffect(() => {\n if (!missing) {\n tries.current = 0;\n return;\n }\n if (tries.current >= 6) return;\n const t = setTimeout(() => {\n tries.current++;\n reload();\n }, 1000 * 2 ** tries.current);\n return () => clearTimeout(t);\n }, [missing, files, reload]);\n\n // Every URL shown for an image, of this and earlier reads, back to its name.\n const shown = useRef(new Map<string, string>());\n useEffect(() => {\n for (const m of [previews, published, views]) for (const [n, u] of m) shown.current.set(u, n);\n }, [previews, published, views]);\n\n const imageSrc = useCallback(\n (image: string | null | undefined) => {\n if (!image) return undefined;\n const n = image.startsWith(IMAGE_SCHEME) ? image.slice(IMAGE_SCHEME.length) : image;\n return previews.get(n) ?? published.get(n) ?? views.get(n) ?? image;\n },\n [previews, published, views],\n );\n const text = useMemo(\n () => (stored ? { ...stored, body: (stored.body ?? \"\").replace(imageRefs(), (ref, n: string) => previews.get(n) ?? published.get(n) ?? views.get(n) ?? ref) } : undefined),\n [stored, previews, published, views],\n );\n const storedBody = useCallback(\n (html: string) => {\n const back = new Map(shown.current);\n for (const m of [previews, published, views]) for (const [n, u] of m) back.set(u, n);\n let out = html;\n for (const [u, n] of back) out = out.split(u).join(imageRef(n)).split(u.replaceAll(\"&\", \"&\")).join(imageRef(n));\n return out;\n },\n [previews, published, views],\n );\n const preview = useCallback((name: string, file: Blob): string | undefined => {\n if (typeof URL.createObjectURL !== \"function\") return undefined;\n const url = URL.createObjectURL(file);\n blobs.current.push(url);\n setPreviews((m) => new Map(m).set(name, url));\n return url;\n }, []);\n\n const create = useCallback(\n (input: ContentInput) =>\n run(async () => {\n const c = await client.contents.create(input);\n setCreated(c.id);\n return c;\n }),\n [client, run],\n );\n const update = useCallback((patch: ContentPatch) => run(() => client.contents.update(need(), patch)), [client, run, need]);\n const putText = useCallback(\n (t: CatalogText) => run(() => client.contents.putText(need(), language, t.body === undefined ? t : { ...t, body: storedBody(t.body) })),\n [client, run, need, language, storedBody],\n );\n const publish = useCallback((at?: string) => run(() => client.contents.publishWhenReady(need(), at)), [client, run, need]);\n const unpublish = useCallback(() => run(() => client.contents.unpublish(need())), [client, run, need]);\n const remove = useCallback(() => run(() => client.contents.remove(need())), [client, run, need]);\n const restore = useCallback(() => run(() => client.contents.restore(need())), [client, run, need]);\n const setCover = useCallback(\n (file: Blob | null) =>\n run(async () => {\n if (!file) {\n await client.contents.setCover(need(), needVersion(), null);\n return null;\n }\n const ref = { kind, id: need(), version: needVersion() };\n const up = await client.media.uploadNamed(ref, file, { path: await client.media.presetPath(kind, \"cover\", file) });\n const saved = await client.contents.setCover(ref.id, ref.version, up.name);\n const url = preview(up.name, file) ?? saved.cover?.url ?? null;\n if (url) shown.current.set(url, up.name);\n return url;\n }),\n [client, run, need, needVersion, kind, preview],\n );\n const uploadImage = useCallback(\n (file: Blob) =>\n run(async () => {\n const up = await client.media.uploadInline({ kind, id: need(), version: needVersion() }, file);\n const url = preview(up.name, file) ?? up.url ?? up.ref;\n shown.current.set(url, up.name);\n return url;\n }),\n [client, run, need, needVersion, kind, preview],\n );\n return {\n content,\n reload: r.reload,\n loading: !!key && (r.loading || (!r.loaded && o.initial === undefined)),\n error: r.error,\n saving: inflight > 0,\n create,\n update,\n putText,\n publish,\n unpublish,\n remove,\n restore,\n version,\n setCover,\n uploadImage,\n imageSrc,\n coverSrc: cover?.image ? imageSrc(cover.image) : (cover?.url ?? undefined),\n text,\n storedBody,\n };\n}\n"],"mappings":"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"}
|
|
@@ -12,6 +12,22 @@ export interface UseContents extends UseList<Card, ContentPage["summary"]> {
|
|
|
12
12
|
export declare function useContents(q: ContentQuery | null, o?: {
|
|
13
13
|
client?: ContentKitClient;
|
|
14
14
|
}): UseContents;
|
|
15
|
+
/** One numbered page of a list or search: its cards and the selection's summary (total included). */
|
|
16
|
+
export interface UseContentsPage {
|
|
17
|
+
items: Card[];
|
|
18
|
+
summary?: ContentPage["summary"];
|
|
19
|
+
loading: boolean;
|
|
20
|
+
error?: ContentKitError;
|
|
21
|
+
reload: () => void;
|
|
22
|
+
}
|
|
23
|
+
/** Page `page` (from 1) of a list, with its summary; null reads nothing. */
|
|
24
|
+
export declare function useContentsPage(q: ContentQuery | null, page: number, o?: {
|
|
25
|
+
client?: ContentKitClient;
|
|
26
|
+
}): UseContentsPage;
|
|
27
|
+
/** Page `page` (from 1) of a search, with its summary; nothing until the query has text. */
|
|
28
|
+
export declare function useSearchPage(q: SearchQuery | null, page: number, o?: {
|
|
29
|
+
client?: ContentKitClient;
|
|
30
|
+
}): UseContentsPage;
|
|
15
31
|
/** Locked contents in the same full selection, including its activity window. */
|
|
16
32
|
export declare function useLockedCount(q: ContentQuery | null, o?: {
|
|
17
33
|
client?: ContentKitClient;
|
package/dist/react/discovery.js
CHANGED
|
@@ -38,7 +38,39 @@ function T(e, t = {}) {
|
|
|
38
38
|
summary: l.metadata
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
|
-
|
|
41
|
+
var E = [];
|
|
42
|
+
function D(e, t, n) {
|
|
43
|
+
let { store: r } = a(n.client), i = s(r, e, { type: "cards" }, t);
|
|
44
|
+
return {
|
|
45
|
+
items: i.data?.contents ?? E,
|
|
46
|
+
summary: i.data?.summary,
|
|
47
|
+
loading: i.loading || !!e && !i.loaded,
|
|
48
|
+
error: i.error,
|
|
49
|
+
reload: i.reload
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function O(e, t, n = {}) {
|
|
53
|
+
let { client: r, scope: o } = a(n.client), s = w(e), c = Math.max(1, Math.floor(t));
|
|
54
|
+
return D(s ? i("cards", o, "list-page", s, c) : null, (e) => r.discovery.list({
|
|
55
|
+
...s,
|
|
56
|
+
cursor: void 0,
|
|
57
|
+
page: c,
|
|
58
|
+
summary: s.summary ?? !0
|
|
59
|
+
}, e), n);
|
|
60
|
+
}
|
|
61
|
+
function k(e, t, n = {}) {
|
|
62
|
+
let { client: r, scope: o, viewer: s } = a(n.client), c = w(e?.q.trim() ? e : null), l = Math.max(1, Math.floor(t)), u = C(r, o);
|
|
63
|
+
return D(c ? i("cards", o, "search-page", c, l) : null, async (e) => {
|
|
64
|
+
let t = await r.discovery.search({
|
|
65
|
+
...c,
|
|
66
|
+
cursor: void 0,
|
|
67
|
+
page: l,
|
|
68
|
+
summary: c.summary ?? !0
|
|
69
|
+
}, e);
|
|
70
|
+
return l === 1 && s === null && !e.aborted && u() && r.discovery.browserSearches.record(c.q, t.contents.length), t;
|
|
71
|
+
}, n);
|
|
72
|
+
}
|
|
73
|
+
function A(e, t = {}) {
|
|
42
74
|
let { client: n, store: r, scope: o } = a(t.client), c = w(g(() => {
|
|
43
75
|
if (!e) return null;
|
|
44
76
|
let { cursor: t, ...n } = e;
|
|
@@ -54,7 +86,7 @@ function E(e, t = {}) {
|
|
|
54
86
|
loading: l.loading
|
|
55
87
|
};
|
|
56
88
|
}
|
|
57
|
-
function
|
|
89
|
+
function j(e, t = {}) {
|
|
58
90
|
let { client: n, store: r, scope: s, viewer: c } = a(t.client), l = w(e?.q.trim() ? e : null), u = C(n, s), d = o(r, l ? i("cards", s, "search", l) : null, { type: "cards" }, async (e, t) => {
|
|
59
91
|
let r = await n.discovery.search({
|
|
60
92
|
...l,
|
|
@@ -68,7 +100,7 @@ function D(e, t = {}) {
|
|
|
68
100
|
summary: d.metadata
|
|
69
101
|
};
|
|
70
102
|
}
|
|
71
|
-
function
|
|
103
|
+
function M(e, t, n) {
|
|
72
104
|
let { store: r } = a(n.client), i = s(r, e, { type: "cards" }, t), o = i.error?.code === "not_configured";
|
|
73
105
|
return {
|
|
74
106
|
items: i.data?.contents ?? [],
|
|
@@ -79,15 +111,15 @@ function O(e, t, n) {
|
|
|
79
111
|
reload: i.reload
|
|
80
112
|
};
|
|
81
113
|
}
|
|
82
|
-
function
|
|
114
|
+
function N(e, t = {}, n = {}) {
|
|
83
115
|
let { client: r, scope: o } = a(n.client), s = w(t);
|
|
84
|
-
return
|
|
116
|
+
return M(e ? i("cards", o, "similar", e, s) : null, (t) => r.discovery.similar(e, s, t), n);
|
|
85
117
|
}
|
|
86
|
-
function
|
|
118
|
+
function P(e = {}, t = {}) {
|
|
87
119
|
let { client: n, scope: r, viewer: o } = a(t.client), s = w(e);
|
|
88
|
-
return
|
|
120
|
+
return M(o === null || !s ? null : i("cards", r, "recommended", s), (e) => n.discovery.recommendations(s, e), t);
|
|
89
121
|
}
|
|
90
|
-
function
|
|
122
|
+
function F(e = {}, t = {}) {
|
|
91
123
|
let { client: n, store: r, scope: s } = a(t.client), c = w(e);
|
|
92
124
|
return o(r, i("release-dates", s, c), { type: "release-dates" }, async (e, t) => {
|
|
93
125
|
let r = await n.discovery.releaseDates({
|
|
@@ -103,7 +135,7 @@ function j(e = {}, t = {}) {
|
|
|
103
135
|
};
|
|
104
136
|
});
|
|
105
137
|
}
|
|
106
|
-
function
|
|
138
|
+
function I(e = {}, t = {}) {
|
|
107
139
|
let { client: n, store: r, scope: o } = a(t.client), c = w(e), l = s(r, c ? i("daily-releases", o, c) : null, { type: "daily-releases" }, (e) => n.discovery.releases(c, e));
|
|
108
140
|
return {
|
|
109
141
|
data: l.data,
|
|
@@ -112,7 +144,7 @@ function M(e = {}, t = {}) {
|
|
|
112
144
|
reload: l.reload
|
|
113
145
|
};
|
|
114
146
|
}
|
|
115
|
-
function
|
|
147
|
+
function L(e = {}, t = {}) {
|
|
116
148
|
let { client: n, store: s, scope: l, viewer: u } = a(t.client), d = w(e), p = r(), m = u === null, h = C(n, l), _ = n.guestHistory, v = d !== null, x = f((e) => m && v ? _.subscribe(e) : () => {}, [
|
|
117
149
|
_,
|
|
118
150
|
m,
|
|
@@ -177,7 +209,7 @@ function N(e = {}, t = {}) {
|
|
|
177
209
|
forget: A
|
|
178
210
|
};
|
|
179
211
|
}
|
|
180
|
-
function
|
|
212
|
+
function R(e = {}) {
|
|
181
213
|
let { client: t, store: n, scope: o, viewer: c } = a(e.client), u = r(), d = C(t, o), p = c === null, h = e.enabled !== !1, _ = t.discovery.browserSearches, v = f((e) => p && h ? _.subscribe(e) : () => {}, [
|
|
182
214
|
_,
|
|
183
215
|
p,
|
|
@@ -226,7 +258,7 @@ function P(e = {}) {
|
|
|
226
258
|
clear: D
|
|
227
259
|
};
|
|
228
260
|
}
|
|
229
|
-
var
|
|
261
|
+
var z = (e) => ({
|
|
230
262
|
items: e.items.map((e) => ({
|
|
231
263
|
...e,
|
|
232
264
|
id: e.content?.id ?? e.entity?.id ?? ""
|
|
@@ -234,8 +266,8 @@ var F = (e) => ({
|
|
|
234
266
|
next: e.next_cursor ?? null,
|
|
235
267
|
metadata: e.summary
|
|
236
268
|
});
|
|
237
|
-
function
|
|
238
|
-
let { client: n, store: r, scope: s, viewer: c } = a(t.client), l = w(e), u = o(r, c === null ? null : i("favorites", s, l), { type: "favorites" }, async (e, t) =>
|
|
269
|
+
function B(e = {}, t = {}) {
|
|
270
|
+
let { client: n, store: r, scope: s, viewer: c } = a(t.client), l = w(e), u = o(r, c === null ? null : i("favorites", s, l), { type: "favorites" }, async (e, t) => z(await n.favorites.mine({
|
|
239
271
|
...l,
|
|
240
272
|
cursor: e,
|
|
241
273
|
summary: e ? void 0 : l.summary
|
|
@@ -245,8 +277,8 @@ function I(e = {}, t = {}) {
|
|
|
245
277
|
summary: u.metadata
|
|
246
278
|
};
|
|
247
279
|
}
|
|
248
|
-
function
|
|
249
|
-
let { client: n, store: r, scope: s, viewer: c } = a(t.client), l = w(e), u = o(r, c === null ? null : i("reactions", s, l), { type: "reactions" }, async (e, t) =>
|
|
280
|
+
function V(e = {}, t = {}) {
|
|
281
|
+
let { client: n, store: r, scope: s, viewer: c } = a(t.client), l = w(e), u = o(r, c === null ? null : i("reactions", s, l), { type: "reactions" }, async (e, t) => z(await n.reactions.mine({
|
|
250
282
|
...l,
|
|
251
283
|
cursor: e,
|
|
252
284
|
summary: e ? void 0 : l.summary
|
|
@@ -256,7 +288,7 @@ function L(e = {}, t = {}) {
|
|
|
256
288
|
summary: u.metadata
|
|
257
289
|
};
|
|
258
290
|
}
|
|
259
|
-
function
|
|
291
|
+
function H(t = {}) {
|
|
260
292
|
let { client: n, store: o, scope: c, viewer: l, language: u } = a(t.client), d = t.language ?? u, p = l === null, h = n.preferences.browser, b = y(h.subscribe, h.snapshot, h.snapshot), x = i("content-filters", c, d), S = _(null), w = p && S.current?.guest && S.current.client === n && S.current.language === d ? S.current.data : void 0, T = s(o, x, { type: "content-filters" }, (e) => n.discovery.contentFilters(d, e), { initial: w });
|
|
261
293
|
S.current = {
|
|
262
294
|
client: n,
|
|
@@ -353,11 +385,11 @@ function R(t = {}) {
|
|
|
353
385
|
setIncludeDeleted: F
|
|
354
386
|
};
|
|
355
387
|
}
|
|
356
|
-
var
|
|
388
|
+
var U = {
|
|
357
389
|
contents: [],
|
|
358
390
|
entities: []
|
|
359
391
|
};
|
|
360
|
-
function
|
|
392
|
+
function W(e, n = {}) {
|
|
361
393
|
let { client: r, language: i, scope: o } = a(n.client), { debounce: s = 150, minLength: c = 1, client: l, management: u = !1, request: d, ...f } = n, p = g(() => ({
|
|
362
394
|
viewerScope: o,
|
|
363
395
|
management: u,
|
|
@@ -375,7 +407,7 @@ function B(e, n = {}) {
|
|
|
375
407
|
h,
|
|
376
408
|
JSON.stringify(f)
|
|
377
409
|
]), [y, b] = v({
|
|
378
|
-
...
|
|
410
|
+
...U,
|
|
379
411
|
query: "",
|
|
380
412
|
loading: !1,
|
|
381
413
|
scope: p
|
|
@@ -383,7 +415,7 @@ function B(e, n = {}) {
|
|
|
383
415
|
return m(() => {
|
|
384
416
|
if (h.length < c) {
|
|
385
417
|
b({
|
|
386
|
-
...
|
|
418
|
+
...U,
|
|
387
419
|
query: "",
|
|
388
420
|
loading: !1,
|
|
389
421
|
scope: p
|
|
@@ -392,7 +424,7 @@ function B(e, n = {}) {
|
|
|
392
424
|
}
|
|
393
425
|
b((e) => ({
|
|
394
426
|
...e.scope === p ? e : {
|
|
395
|
-
...
|
|
427
|
+
...U,
|
|
396
428
|
query: ""
|
|
397
429
|
},
|
|
398
430
|
loading: !0,
|
|
@@ -418,7 +450,7 @@ function B(e, n = {}) {
|
|
|
418
450
|
}, (n) => {
|
|
419
451
|
let r = t(n);
|
|
420
452
|
!e.signal.aborted && r.code !== "aborted" && b({
|
|
421
|
-
...
|
|
453
|
+
...U,
|
|
422
454
|
query: h,
|
|
423
455
|
loading: !1,
|
|
424
456
|
error: r,
|
|
@@ -439,22 +471,22 @@ function B(e, n = {}) {
|
|
|
439
471
|
d,
|
|
440
472
|
p
|
|
441
473
|
]), y.scope === p ? y : {
|
|
442
|
-
...
|
|
474
|
+
...U,
|
|
443
475
|
query: "",
|
|
444
476
|
loading: h.length >= c
|
|
445
477
|
};
|
|
446
478
|
}
|
|
447
|
-
var
|
|
448
|
-
function
|
|
449
|
-
let n =
|
|
450
|
-
return n ||
|
|
479
|
+
var G = /* @__PURE__ */ new WeakMap();
|
|
480
|
+
function K(e, t) {
|
|
481
|
+
let n = G.get(e);
|
|
482
|
+
return n || G.set(e, n = new u(e, t)), n;
|
|
451
483
|
}
|
|
452
|
-
function
|
|
484
|
+
function q(e = {}) {
|
|
453
485
|
let { client: t } = a(e.client);
|
|
454
|
-
return
|
|
486
|
+
return K(t);
|
|
455
487
|
}
|
|
456
|
-
function
|
|
457
|
-
let { client: n, scope: r, language: i } = a(t.client), o =
|
|
488
|
+
function J(e, t) {
|
|
489
|
+
let { client: n, scope: r, language: i } = a(t.client), o = K(n), s = C(n, r), c = g(() => d(), [t.render, r]), l = g(() => ({
|
|
458
490
|
surface: t.surface,
|
|
459
491
|
ranker: t.ranker,
|
|
460
492
|
query_id: t.query_id,
|
|
@@ -482,7 +514,7 @@ function W(e, t) {
|
|
|
482
514
|
if (!s()) return;
|
|
483
515
|
let t = /* @__PURE__ */ new Set();
|
|
484
516
|
for (let [n, r] of e.entries()) {
|
|
485
|
-
let e = r.position, i = e !== void 0 && Number.isSafeInteger(e) && e > 0 ? e : n + 1, a = Math.floor((i - 1) /
|
|
517
|
+
let e = r.position, i = e !== void 0 && Number.isSafeInteger(e) && e > 0 ? e : n + 1, a = Math.floor((i - 1) / Y), o = h(a);
|
|
486
518
|
o.rendered.has(r.id) || (o.rendered.set(r.id, {
|
|
487
519
|
content_id: r.id,
|
|
488
520
|
version_id: r.version_id ?? r.version?.id,
|
|
@@ -513,7 +545,7 @@ function W(e, t) {
|
|
|
513
545
|
if (s()) {
|
|
514
546
|
for (let t of e) {
|
|
515
547
|
if (!t.isIntersecting) continue;
|
|
516
|
-
let e = t.target, n = e.dataset.exposureContent, r = Number(e.dataset.exposurePosition), i = Math.floor((r - 1) /
|
|
548
|
+
let e = t.target, n = e.dataset.exposureContent, r = Number(e.dataset.exposurePosition), i = Math.floor((r - 1) / Y), a = h(i);
|
|
517
549
|
a.visible.has(n) || (a.visible.set(n, a.rendered.get(n) ?? {
|
|
518
550
|
content_id: n,
|
|
519
551
|
position: r
|
|
@@ -562,7 +594,7 @@ function W(e, t) {
|
|
|
562
594
|
}, [_]),
|
|
563
595
|
click: f((n, r) => {
|
|
564
596
|
if (!s()) return;
|
|
565
|
-
let i = Math.floor((r - 1) /
|
|
597
|
+
let i = Math.floor((r - 1) / Y), a = e.find((e) => e.id === n), c = a?.version_id ?? a?.version?.id;
|
|
566
598
|
o.click(n, {
|
|
567
599
|
render_id: p(i),
|
|
568
600
|
surface: t.surface,
|
|
@@ -580,8 +612,8 @@ function W(e, t) {
|
|
|
580
612
|
])
|
|
581
613
|
};
|
|
582
614
|
}
|
|
583
|
-
var
|
|
615
|
+
var Y = 32;
|
|
584
616
|
//#endregion
|
|
585
|
-
export {
|
|
617
|
+
export { K as beaconsFor, q as useBeacons, H as useContentFilters, T as useContents, O as useContentsPage, I as useDailyReleases, J as useExposure, L as useHistory, A as useLockedCount, B as useMyFavorites, V as useMyReactions, R as useRecentSearches, P as useRecommendations, F as useReleaseDates, j as useSearch, k as useSearchPage, N as useSimilar, W as useTypeahead };
|
|
586
618
|
|
|
587
619
|
//# sourceMappingURL=discovery.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"discovery.js","names":[],"sources":["../../src/react/discovery.ts"],"sourcesContent":["import { useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from \"react\";\nimport { Beacons, eventId, type BeaconOptions } from \"../client/beacons.js\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { MineQuery } from \"../client/content/favorites.js\";\nimport type { ContentQuery, DailyReleasesQuery, HistoryQuery, RailQuery, ReleaseDatesQuery, SearchQuery, TypeaheadQuery } from \"../client/discovery.js\";\nimport { ContentKitError, toContentKitError } from \"../client/errors.js\";\nimport type { Card, ContentFilters, ContentFiltersUpdate, ContentPage, DailyReleases, DateCount, GroupCard, Interaction, InteractionPage, RecentSearch, Typeahead } from \"../client/generated/wire.js\";\nimport { ContentKitContext, useGuarded } from \"./context.js\";\nimport { keyOf, useContentScope, useList, useResource, type UseList } from \"./use-resource.js\";\nimport { guestStanding, type GuestReadingItem } from \"../client/guest-reading-history.js\";\nimport { recentSearchLimit } from \"../client/browser-search-history.js\";\n\nconst page = (p: ContentPage) => ({ items: p.contents, next: p.next_cursor ?? null, metadata: p.summary });\nexport interface UseContents extends UseList<Card, ContentPage[\"summary\"]> { summary?: ContentPage[\"summary\"] }\nconst NO_SEARCHES: RecentSearch[] = [];\nconst NO_READING: readonly GuestReadingItem[] = Object.freeze([]);\n\n// A new identity even after A → B → A, so late requests cannot write into the new visit.\nfunction useCurrentDiscoveryScope(client: ContentKitClient, scope: string): () => boolean {\n const owner = useMemo(() => ({ client, scope }), [client, scope]);\n const current = useRef<typeof owner | null>(owner);\n useLayoutEffect(() => {\n current.current = owner;\n return () => { current.current = null; };\n }, [owner]);\n return useCallback(() => current.current === owner, [owner]);\n}\n\n/** Titles, names and paths in the provider's language unless the query says otherwise. */\nfunction useDisplay<T extends { display_language?: string }>(q: T | null): T | null {\n const language = useContext(ContentKitContext)?.language;\n return useMemo(() => (q && !q.display_language && language ? { ...q, display_language: language } : q), [q, language]);\n}\n\n/** Contents as cards, a cursor page at a time; null reads nothing. */\nexport function useContents(q: ContentQuery | null, o: { client?: ContentKitClient } = {}): UseContents {\n const { client, store, scope } = useContentScope(o.client);\n const query = useDisplay(q);\n const list = useList(store, query ? keyOf(\"cards\", scope, \"list\", query) : null, { type: \"cards\" }, async (cursor, signal) =>\n page(await client.discovery.list({ ...query, cursor: cursor as string | undefined, summary: cursor ? undefined : query?.summary }, signal)),\n );\n return { ...list, summary: list.metadata };\n}\n\n/** Locked contents in the same full selection, including its activity window. */\nexport function useLockedCount(q: ContentQuery | null, o: { client?: ContentKitClient } = {}): { count?: number; loading: boolean } {\n const { client, store, scope } = useContentScope(o.client);\n const filter = useMemo(() => {\n if (!q) return null;\n const { cursor: _cursor, ...rest } = q;\n return { ...rest, mode: \"lock\" as const, limit: 1, summary: true };\n }, [q]);\n const query = useDisplay(filter);\n const r = useResource<number>(store, query ? keyOf(\"cards\", scope, \"locked-summary\", query) : null, { type: \"cards\" }, async (signal) => {\n const out = await client.discovery.list(query!, signal);\n return out.summary?.locked_count ?? 0;\n });\n return { count: r.data, loading: r.loading };\n}\n\n/** Keyword search results as cards; nothing while q.q is empty. */\nexport function useSearch(q: SearchQuery | null, o: { client?: ContentKitClient } = {}): UseContents {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q?.q.trim() ? q : null);\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const list = useList(store, query ? keyOf(\"cards\", scope, \"search\", query) : null, { type: \"cards\" }, async (cursor, signal) => {\n const out = await client.discovery.search({ ...query!, cursor: cursor as string | undefined, summary: cursor ? undefined : query?.summary }, signal);\n if (!cursor && viewer === null && !signal.aborted && isCurrent()) client.discovery.browserSearches.record(query!.q, out.contents.length);\n return page(out);\n });\n return { ...list, summary: list.metadata };\n}\n\nexport interface UseRail {\n items: Card[];\n summary?: ContentPage[\"summary\"];\n loading: boolean;\n error?: ContentKitError;\n /** The site runs without the signal plane (not_configured): leave the rail out. */\n unavailable: boolean;\n reload: () => void;\n}\n\nfunction useRail(key: string | null, fetch: (signal: AbortSignal) => Promise<ContentPage>, o: { client?: ContentKitClient }): UseRail {\n const { store } = useContentScope(o.client);\n const r = useResource<ContentPage>(store, key, { type: \"cards\" }, fetch);\n const unavailable = r.error?.code === \"not_configured\";\n return { items: r.data?.contents ?? [], summary: r.data?.summary, loading: !!key && (r.loading || !r.loaded), error: unavailable ? undefined : r.error, unavailable, reload: r.reload };\n}\n\n/** Contents like one: co-engagement, or the site's configured source. */\nexport function useSimilar(id: string | null | undefined, q: RailQuery = {}, o: { client?: ContentKitClient } = {}): UseRail {\n const { client, scope } = useContentScope(o.client);\n const query = useDisplay(q)!;\n return useRail(id ? keyOf(\"cards\", scope, \"similar\", id, query) : null, (s) => client.discovery.similar(id!, query, s), o);\n}\n\n/** Contents for the signed-in reader; nothing signed out, or when q is null. */\nexport function useRecommendations(q: RailQuery | null = {}, o: { client?: ContentKitClient } = {}): UseRail {\n const { client, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q);\n return useRail(viewer === null || !query ? null : keyOf(\"cards\", scope, \"recommended\", query), (s) => client.discovery.recommendations(query!, s), o);\n}\n\n/** A release date bucket, keyed by its date. */\nexport type ReleaseDate = DateCount & { id: string };\n\n/** The release date index: per month or day, newest first. */\nexport function useReleaseDates(q: ReleaseDatesQuery = {}, o: { client?: ContentKitClient } = {}): UseList<ReleaseDate> {\n const { client, store, scope } = useContentScope(o.client);\n const query = useDisplay(q)!;\n return useList(store, keyOf(\"release-dates\", scope, query), { type: \"release-dates\" }, async (cursor, signal) => {\n const r = await client.discovery.releaseDates({ ...query, cursor: cursor as string | undefined }, signal);\n return { items: r.dates.map((d) => ({ ...d, id: d.date })), next: r.next_cursor ?? null };\n });\n}\n\nexport interface UseDailyReleases {\n data?: DailyReleases;\n loading: boolean;\n error?: ContentKitError;\n reload: () => void;\n}\n\n/** One complete calendar window, shared by all readers of the same query. */\nexport function useDailyReleases(q: DailyReleasesQuery | null = {}, o: { client?: ContentKitClient } = {}): UseDailyReleases {\n const { client, store, scope } = useContentScope(o.client);\n const query = useDisplay(q);\n const r = useResource<DailyReleases>(store, query ? keyOf(\"daily-releases\", scope, query) : null, { type: \"daily-releases\" }, (signal) => client.discovery.releases(query!, signal));\n return { data: r.data, loading: !!query && (r.loading || !r.loaded), error: r.error, reload: r.reload };\n}\n\nexport interface UseHistory extends UseContents {\n /** A status-filtered guest selection has hidden candidates whose current version facts cannot be inspected. */\n filterSummaryUnknown?: boolean;\n /** Erases the reader's history: of one content item, one kind, or (no argument) everything. */\n forget: (o?: { kind?: string; content_id?: string }) => Promise<void>;\n}\n\n/** Account history is authoritative; signed-out reading stays in this browser across tabs. */\nexport function useHistory(q: HistoryQuery | null = {}, o: { client?: ContentKitClient } = {}): UseHistory {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q);\n const guarded = useGuarded();\n const guest = viewer === null;\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const browser = client.guestHistory;\n const enabled = query !== null;\n const subscribe = useCallback((listener: () => void) => guest && enabled ? browser.subscribe(listener) : () => {}, [browser, guest, enabled]);\n const snapshot = useCallback(() => guest && enabled ? browser.snapshot() : NO_READING, [browser, guest, enabled]);\n const local = useSyncExternalStore(subscribe, snapshot, () => NO_READING);\n const selected = useMemo(() => local.filter(row => !query?.kind || row.kind === query.kind).slice(0, 100), [local, query?.kind]);\n const localRevision = guest ? selected.map(row => [row.id, row.at, row.checkpoints.map(checkpoint => [checkpoint.visit_id, checkpoint.segment_id, checkpoint.revision])]) : undefined;\n const list = useList(store, !query || viewer === undefined ? null : keyOf(\"history\", scope, query, localRevision), { type: \"history\" }, async (cursor, signal) => {\n if (!guest) return page(await client.discovery.history({ ...query, cursor: cursor as string | undefined, summary: cursor ? undefined : query?.summary }, signal));\n const offset = typeof cursor === \"number\" ? cursor : 0;\n const limit = Math.max(1, Math.min(100, query?.limit ?? 50));\n const batch = selected.slice(offset, offset + limit);\n if (!batch.length) return { items: [], next: null };\n // Public hydration enforces current hard-domain rules, access and optional preferences.\n const out = await client.discovery.list({ ids: (query?.summary && !cursor ? selected : batch).map(row => row.id), summary: !cursor ? query?.summary : undefined, kind: query?.kind, language: query?.language,\n display_language: query?.display_language, mode: query?.mode, card_entities: query?.card_entities, limit: 100 }, signal);\n const cards = new Map(out.contents.map(card => [card.id, card]));\n const items = batch.flatMap(row => {\n const card = cards.get(row.id); if (!card) return [];\n const viewer = guestStanding(card, row);\n if (query?.status === \"seen\" && !viewer.seen || query?.status === \"in_progress\" && (!viewer.seen || viewer.completed) || query?.status === \"completed\" && !viewer.completed) return [];\n return [{ ...card, viewer }];\n });\n return { items, next: offset + batch.length < selected.length ? offset + batch.length : null, metadata: out.summary };\n });\n const forget = useCallback((filter: { kind?: string; content_id?: string } = {}) => {\n if (!isCurrent()) return Promise.resolve();\n if (guest) { browser.clear(filter); return Promise.resolve(); }\n return guarded(() => client.discovery.forgetHistory(filter));\n }, [browser, client, guest, guarded, isCurrent]);\n const uncertain = guest && !!query?.status;\n return { ...list, summary: uncertain ? undefined : list.metadata, filterSummaryUnknown: uncertain && (list.metadata?.filtered_count ?? 0) > 0, forget };\n}\n\nexport interface UseRecentSearches {\n searches: RecentSearch[];\n loading: boolean;\n error?: ContentKitError;\n /** Clears one query, or every recent search. */\n clear: (query?: string) => Promise<void>;\n}\n\n/** Guest history stays in this browser; account history comes only from the server. enabled false reads nothing yet. */\nexport function useRecentSearches(o: { limit?: number; enabled?: boolean; client?: ContentKitClient } = {}): UseRecentSearches {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const guarded = useGuarded();\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const guest = viewer === null;\n const enabled = o.enabled !== false;\n const browser = client.discovery.browserSearches;\n const subscribe = useCallback((listener: () => void) => guest && enabled ? browser.subscribe(listener) : () => {}, [browser, guest, enabled]);\n const snapshot = useCallback(() => guest && enabled ? browser.snapshot() : NO_SEARCHES, [browser, guest, enabled]);\n const local = useSyncExternalStore(subscribe, snapshot, () => NO_SEARCHES);\n const searches = useMemo(() => local.slice(0, recentSearchLimit(o.limit)), [local, o.limit]);\n const key = !enabled || guest ? null : keyOf(\"searches\", scope, o.limit ?? 10);\n const r = useResource<RecentSearch[]>(store, key, { type: \"searches\" }, async (s) => (await client.discovery.recentSearches({ limit: o.limit }, s)).searches);\n useEffect(() => {\n if (!key) return;\n const reload = () => { if (!store.snapshot(key).loading) store.load(key, true); };\n // Reopening a panel must not leave an already-cached account list stale.\n if (store.snapshot(key).loaded) reload();\n const visible = () => { if (document.visibilityState === \"visible\") reload(); };\n if (typeof window !== \"undefined\") window.addEventListener(\"focus\", reload);\n if (typeof document !== \"undefined\") document.addEventListener(\"visibilitychange\", visible);\n return () => {\n if (typeof window !== \"undefined\") window.removeEventListener(\"focus\", reload);\n if (typeof document !== \"undefined\") document.removeEventListener(\"visibilitychange\", visible);\n };\n }, [key, store]);\n const clear = useCallback(async (query?: string) => {\n if (!isCurrent()) return;\n if (guest) { browser.clear(query); return; }\n await guarded(() => isCurrent() ? client.discovery.clearSearches(query ? { query } : {}) : Promise.resolve());\n }, [browser, client, guest, guarded, isCurrent]);\n return guest\n ? { searches: enabled ? searches : NO_SEARCHES, loading: false, clear }\n : { searches: r.data ?? NO_SEARCHES, loading: !!key && (r.loading || !r.loaded), error: r.error, clear };\n}\n\n/** A favorite or reaction with its content's or group's id. */\nexport type MyInteraction = Interaction & { id: string };\n\nconst interactions = (p: InteractionPage) => ({ items: p.items.map((x) => ({ ...x, id: x.content?.id ?? x.entity?.id ?? \"\" })), next: p.next_cursor ?? null, metadata: p.summary });\n\nexport interface UseInteractions extends UseList<MyInteraction, InteractionPage[\"summary\"]> { summary?: InteractionPage[\"summary\"] }\n\n/** The signed-in reader's favorites, most recent first: content cards or groups. */\nexport function useMyFavorites(q: MineQuery = {}, o: { client?: ContentKitClient } = {}): UseInteractions {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q)!;\n const list = useList(store, viewer === null ? null : keyOf(\"favorites\", scope, query), { type: \"favorites\" }, async (cursor, signal) =>\n interactions(await client.favorites.mine({ ...query, cursor: cursor as string | undefined, summary: cursor ? undefined : query.summary }, signal)),\n );\n return { ...list, summary: list.metadata };\n}\n\n/** What the signed-in reader liked (or, with value, disliked), most recent first. */\nexport function useMyReactions(q: MineQuery & { value?: \"like\" | \"dislike\" } = {}, o: { client?: ContentKitClient } = {}): UseInteractions {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q)!;\n const list = useList(store, viewer === null ? null : keyOf(\"reactions\", scope, query), { type: \"reactions\" }, async (cursor, signal) =>\n interactions(await client.reactions.mine({ ...query, cursor: cursor as string | undefined, summary: cursor ? undefined : query.summary }, signal)),\n );\n return { ...list, summary: list.metadata };\n}\n\nexport interface UseContentFilters {\n filters: ContentFilters | null;\n loading: boolean;\n error?: ContentKitError;\n saving: boolean;\n /** Atomically changes submitted entity choices; other choices are preserved. */\n save: (update: ContentFiltersUpdate) => Promise<ContentFilters>;\n setVisible: (entityId: string, visible: boolean) => Promise<ContentFilters>;\n setIncludeDeleted: (include: boolean) => Promise<ContentFilters>;\n}\n\n/** One current-domain control per entity, shared by all applies_to kinds. */\nexport function useContentFilters(o: { language?: string; client?: ContentKitClient } = {}): UseContentFilters {\n const { client, store, scope, viewer, language: provided } = useContentScope(o.client);\n const language = o.language ?? provided;\n const guest = viewer === null;\n const browser = client.preferences.browser;\n const local = useSyncExternalStore(browser.subscribe, browser.snapshot, browser.snapshot);\n const key = keyOf(\"content-filters\", scope, language);\n const previous = useRef<{\n client: ContentKitClient;\n language?: string;\n guest: boolean;\n data?: ContentFilters;\n } | null>(null);\n const initial =\n guest && previous.current?.guest && previous.current.client === client && previous.current.language === language\n ? previous.current.data\n : undefined;\n const r = useResource<ContentFilters>(\n store,\n key,\n { type: \"content-filters\" },\n (signal) => client.discovery.contentFilters(language, signal),\n { initial },\n );\n previous.current = { client, language, guest, data: r.data };\n const applyGuest = useCallback(\n (source: ContentFilters, choices = local): ContentFilters => {\n const values = new Map(choices.filters.map((row) => [row.entity_id, row]));\n return {\n ...source,\n include_deleted: false,\n filters: source.filters.map((row) => {\n const choice = values.get(row.entity.id);\n return { ...row, visible: choice?.visible ?? row.default_visible, overridden: choice?.visible !== undefined };\n }),\n };\n },\n [local],\n );\n const displayed = useMemo(() => (r.data && guest ? applyGuest(r.data) : r.data), [r.data, guest, applyGuest]);\n const guarded = useGuarded();\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const [inflight, setInflight] = useState(0);\n const current = useRef(displayed);\n current.current = displayed;\n useEffect(() => {\n setInflight(0);\n }, [client, scope]);\n const save = useCallback(\n async (update: ContentFiltersUpdate) => {\n if (!isCurrent()) throw new ContentKitError(\"aborted\", \"The account changed.\");\n if (guest) {\n const source = current.current;\n if (!source) throw new ContentKitError(\"invalid_request\", \"Content filters have not loaded.\");\n const allowed = new Set(source.filters.map((row) => row.entity.id));\n const updates: import(\"../client/browser-reader-preferences.js\").ReaderFilterChoice[] = [];\n const seen = new Set<string>();\n for (const row of update.filters ?? []) {\n if (!allowed.has(row.entity_id) || seen.has(row.entity_id))\n throw new ContentKitError(\"invalid_request\", \"This content filter is not configured or is set twice.\");\n seen.add(row.entity_id);\n if (row.default === true && row.visible === undefined)\n updates.push({ entity_id: row.entity_id, default: true });\n else if (row.default === undefined && typeof row.visible === \"boolean\")\n updates.push({ entity_id: row.entity_id, visible: row.visible });\n else throw new ContentKitError(\"invalid_request\", \"A content filter needs visible or default:true.\");\n }\n client.preferences.setGuestFilters(updates);\n return applyGuest(source, browser.snapshot());\n }\n const submitted = new Set((update.filters ?? []).map((row) => row.entity_id));\n const changesDeleted = typeof update.include_deleted === \"boolean\";\n setInflight((n) => n + 1);\n try {\n const out = await guarded(() => {\n if (!isCurrent()) throw new ContentKitError(\"aborted\", \"The account changed.\");\n return client.discovery.setContentFilters(update, language);\n });\n if (isCurrent()) {\n const rows = new Map(out.filters.map((row) => [row.entity.id, row]));\n // Another control may already have applied a newer response. Merge\n // only this request's choices, never its stale unrelated snapshot.\n store.set<ContentFilters>(key, (previous) => previous ? {\n ...previous,\n filters: previous.filters.flatMap((row) => {\n if (!submitted.has(row.entity.id)) return [row];\n const next = rows.get(row.entity.id);\n return next ? [next] : [];\n }),\n include_deleted: changesDeleted ? out.include_deleted : previous.include_deleted,\n } : out);\n }\n return out;\n } finally {\n setInflight((n) => Math.max(0, n - 1));\n }\n },\n [client, guarded, language, key, store, isCurrent, guest, browser, applyGuest],\n );\n const setVisible = useCallback(\n (entityId: string, visible: boolean) => save({ filters: [{ entity_id: entityId, visible }] }),\n [save],\n );\n const setIncludeDeleted = useCallback((include: boolean) => save({ include_deleted: include }), [save]);\n return {\n filters: displayed ?? null,\n loading: r.loading || !r.loaded,\n error: r.error,\n saving: inflight > 0,\n save,\n setVisible,\n setIncludeDeleted,\n };\n}\n\nexport interface UseTypeahead {\n contents: Card[];\n entities: GroupCard[];\n /** The query the suggestions answer (trimmed). */\n query: string;\n loading: boolean;\n error?: ContentKitError;\n}\n\nconst NONE: Pick<UseTypeahead, \"contents\" | \"entities\"> = { contents: [], entities: [] };\n\n/** Suggestions while the reader types: debounced, the stale ones abandoned. */\nexport function useTypeahead(\n text: string,\n o: Omit<TypeaheadQuery, \"q\"> & { debounce?: number; minLength?: number; client?: ContentKitClient; management?: boolean; request?: (query: TypeaheadQuery, signal: AbortSignal) => Promise<Typeahead> } = {},\n): UseTypeahead {\n const { client, language, scope: viewerScope } = useContentScope(o.client);\n const { debounce = 150, minLength = 1, client: _own, management = false, request, ...rest } = o;\n const scope = useMemo(() => ({ viewerScope, management, request }), [viewerScope, management, request]);\n const q = text.trim();\n const query = useMemo(() => ({ display_language: language, ...rest, q }), [language, q, JSON.stringify(rest)]); // eslint-disable-line react-hooks/exhaustive-deps\n const [state, setState] = useState<UseTypeahead & { scope: typeof scope }>({ ...NONE, query: \"\", loading: false, scope });\n useEffect(() => {\n if (q.length < minLength) {\n setState({ ...NONE, query: \"\", loading: false, scope });\n return;\n }\n setState((s) => ({ ...(s.scope === scope ? s : { ...NONE, query: \"\" }), loading: true, scope }));\n const ctl = new AbortController();\n const timer = setTimeout(() => {\n const pending = request ? request(query, ctl.signal) : management\n ? client.entities.manage({ q, kind: query.entity_kinds?.[0], language: query.display_language, limit: query.limit ?? 10 }, ctl.signal)\n .then((page) => ({ contents: [], entities: page.entities }))\n : client.discovery.typeahead(query, ctl.signal);\n pending.then(\n (r) => { if (!ctl.signal.aborted) setState({ contents: r.contents, entities: r.entities, query: q, loading: false, scope }); },\n (e) => {\n const error = toContentKitError(e);\n if (!ctl.signal.aborted && error.code !== \"aborted\") setState({ ...NONE, query: q, loading: false, error, scope });\n },\n );\n }, debounce);\n return () => {\n clearTimeout(timer);\n ctl.abort();\n };\n }, [client, query, q, debounce, minLength, management, request, scope]);\n return state.scope === scope ? state : { ...NONE, query: \"\", loading: q.length >= minLength };\n}\n\nconst beacons = new WeakMap<ContentKitClient, Beacons>();\n\n/** The client's signal and exposure batcher: one per client. */\nexport function beaconsFor(client: ContentKitClient, o?: BeaconOptions): Beacons {\n let b = beacons.get(client);\n if (!b) beacons.set(client, (b = new Beacons(client, o)));\n return b;\n}\n\nexport function useBeacons(o: { client?: ContentKitClient } = {}): Beacons {\n const { client } = useContentScope(o.client);\n return beaconsFor(client);\n}\n\nexport interface ExposureOptions {\n /** Where the list is: \"home\", \"search\", \"similar\". */\n surface: string;\n /** Changes with what the list shows: a new render id. */\n render: string;\n ranker?: string;\n query_id?: string;\n language?: string;\n client?: ContentKitClient;\n}\n\nexport interface UseExposure {\n /** The first bounded segment; click() selects the matching segment for later positions. */\n render_id: string;\n /** A card's ref: reports it shown once at least half of it is in view. */\n track: (content: string, position: number) => (el: Element | null) => void;\n /** Reports a click on the card at position. */\n click: (content: string, position: number) => void;\n}\n\n/** A rendered result list: each page rendered, each card shown, clicks attributed to the render. */\nexport function useExposure(items: readonly { id: string; position?: number; version_id?: string; version?: { id: string } | null }[], o: ExposureOptions): UseExposure {\n const { client, scope, language } = useContentScope(o.client);\n const b = beaconsFor(client);\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const renderId = useMemo(() => eventId(), [o.render, scope]); // eslint-disable-line react-hooks/exhaustive-deps\n const base = useMemo(() => ({ surface: o.surface, ranker: o.ranker, query_id: o.query_id, language: o.language ?? language }), [o.surface, o.ranker, o.query_id, o.language, language]);\n const state = useMemo(() => ({ segments: new Map<number, ExposureSegment>(), pending: new Set<number>(), timer: undefined as ReturnType<typeof setTimeout> | undefined }), [renderId]); // eslint-disable-line react-hooks/exhaustive-deps\n const segmentID = useCallback((index: number) => index === 0 ? renderId : `${renderId}-${index}`, [renderId]);\n const segmentFor = useCallback((index: number) => {\n let segment = state.segments.get(index);\n if (!segment) {\n segment = { rendered: new Map(), visible: new Map(), renderedRevision: 0, visibleRevision: 0 };\n state.segments.set(index, segment);\n }\n return segment;\n }, [state]);\n useEffect(() => {\n if (!isCurrent()) return;\n const changed = new Set<number>();\n for (const [i, item] of items.entries()) {\n const supplied = item.position;\n const position = supplied !== undefined && Number.isSafeInteger(supplied) && supplied > 0 ? supplied : i + 1;\n const index = Math.floor((position - 1) / EXPOSURE_SEGMENT_SIZE), segment = segmentFor(index);\n if (segment.rendered.has(item.id)) continue;\n segment.rendered.set(item.id, { content_id: item.id, version_id: item.version_id ?? item.version?.id, position });\n changed.add(index);\n }\n for (const index of changed) {\n const segment = segmentFor(index);\n b.exposure({ ...base, render_id: segmentID(index), stage: \"rendered\", revision: ++segment.renderedRevision,\n occurred_at: segment.renderedAt ??= new Date().toISOString(), shown: [...segment.rendered.values()] });\n }\n }, [b, base, items, state, segmentFor, segmentID, isCurrent]);\n const observer = useMemo(() => {\n if (typeof IntersectionObserver !== \"function\") return null;\n return new IntersectionObserver((entries) => {\n if (!isCurrent()) return;\n for (const e of entries) {\n if (!e.isIntersecting) continue;\n const el = e.target as HTMLElement, content = el.dataset.exposureContent!;\n const position = Number(el.dataset.exposurePosition), index = Math.floor((position - 1) / EXPOSURE_SEGMENT_SIZE);\n const segment = segmentFor(index);\n if (segment.visible.has(content)) continue;\n segment.visible.set(content, segment.rendered.get(content) ?? { content_id: content, position });\n state.pending.add(index);\n }\n if (!state.pending.size) return;\n state.timer ??= setTimeout(() => {\n state.timer = undefined;\n if (!isCurrent()) return;\n for (const index of state.pending) {\n const segment = segmentFor(index);\n b.exposure({ ...base, render_id: segmentID(index), stage: \"visible\", revision: ++segment.visibleRevision,\n occurred_at: segment.visibleAt ??= new Date().toISOString(), shown: [...segment.visible.values()] });\n }\n state.pending.clear();\n }, 300);\n }, { threshold: 0.5 });\n }, [b, base, state, segmentFor, segmentID, isCurrent]);\n useEffect(() => () => { observer?.disconnect(); clearTimeout(state.timer); }, [observer, state]);\n useEffect(() => {\n for (const index of state.segments.keys()) b.beginExposure(segmentID(index));\n return () => { for (const index of state.segments.keys()) b.endExposure(segmentID(index)); };\n }, [b, state, segmentID]);\n const track = useCallback((content: string, position: number) => (el: Element | null) => {\n if (!el || !observer) return;\n (el as HTMLElement).dataset.exposureContent = content;\n (el as HTMLElement).dataset.exposurePosition = String(position);\n observer.observe(el);\n }, [observer]);\n const click = useCallback((content: string, position: number) => {\n if (!isCurrent()) return;\n const index = Math.floor((position - 1) / EXPOSURE_SEGMENT_SIZE);\n const item = items.find((item) => item.id === content);\n const version = item?.version_id ?? item?.version?.id;\n b.click(content, { render_id: segmentID(index), surface: o.surface, position, version_id: version, language: base.language });\n }, [b, items, segmentID, o.surface, base.language, isCurrent]);\n return { render_id: renderId, track, click };\n}\n\ntype ObservedPlacement = { content_id: string; version_id?: string; position: number };\ntype ExposureSegment = {\n rendered: Map<string, ObservedPlacement>;\n visible: Map<string, ObservedPlacement>;\n renderedRevision: number;\n visibleRevision: number;\n renderedAt?: string;\n visibleAt?: string;\n};\nconst EXPOSURE_SEGMENT_SIZE = 32;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"discovery.js","names":[],"sources":["../../src/react/discovery.ts"],"sourcesContent":["import { useCallback, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from \"react\";\nimport { Beacons, eventId, type BeaconOptions } from \"../client/beacons.js\";\nimport type { ContentKitClient } from \"../client/client.js\";\nimport type { MineQuery } from \"../client/content/favorites.js\";\nimport type { ContentQuery, DailyReleasesQuery, HistoryQuery, RailQuery, ReleaseDatesQuery, SearchQuery, TypeaheadQuery } from \"../client/discovery.js\";\nimport { ContentKitError, toContentKitError } from \"../client/errors.js\";\nimport type { Card, ContentFilters, ContentFiltersUpdate, ContentPage, DailyReleases, DateCount, GroupCard, Interaction, InteractionPage, RecentSearch, Typeahead } from \"../client/generated/wire.js\";\nimport { ContentKitContext, useGuarded } from \"./context.js\";\nimport { keyOf, useContentScope, useList, useResource, type UseList } from \"./use-resource.js\";\nimport { guestStanding, type GuestReadingItem } from \"../client/guest-reading-history.js\";\nimport { recentSearchLimit } from \"../client/browser-search-history.js\";\n\nconst page = (p: ContentPage) => ({ items: p.contents, next: p.next_cursor ?? null, metadata: p.summary });\nexport interface UseContents extends UseList<Card, ContentPage[\"summary\"]> { summary?: ContentPage[\"summary\"] }\nconst NO_SEARCHES: RecentSearch[] = [];\nconst NO_READING: readonly GuestReadingItem[] = Object.freeze([]);\n\n// A new identity even after A → B → A, so late requests cannot write into the new visit.\nfunction useCurrentDiscoveryScope(client: ContentKitClient, scope: string): () => boolean {\n const owner = useMemo(() => ({ client, scope }), [client, scope]);\n const current = useRef<typeof owner | null>(owner);\n useLayoutEffect(() => {\n current.current = owner;\n return () => { current.current = null; };\n }, [owner]);\n return useCallback(() => current.current === owner, [owner]);\n}\n\n/** Titles, names and paths in the provider's language unless the query says otherwise. */\nfunction useDisplay<T extends { display_language?: string }>(q: T | null): T | null {\n const language = useContext(ContentKitContext)?.language;\n return useMemo(() => (q && !q.display_language && language ? { ...q, display_language: language } : q), [q, language]);\n}\n\n/** Contents as cards, a cursor page at a time; null reads nothing. */\nexport function useContents(q: ContentQuery | null, o: { client?: ContentKitClient } = {}): UseContents {\n const { client, store, scope } = useContentScope(o.client);\n const query = useDisplay(q);\n const list = useList(store, query ? keyOf(\"cards\", scope, \"list\", query) : null, { type: \"cards\" }, async (cursor, signal) =>\n page(await client.discovery.list({ ...query, cursor: cursor as string | undefined, summary: cursor ? undefined : query?.summary }, signal)),\n );\n return { ...list, summary: list.metadata };\n}\n\n/** One numbered page of a list or search: its cards and the selection's summary (total included). */\nexport interface UseContentsPage {\n items: Card[];\n summary?: ContentPage[\"summary\"];\n loading: boolean;\n error?: ContentKitError;\n reload: () => void;\n}\n\nconst NO_CARDS: Card[] = [];\n\nfunction useNumbered(key: string | null, fetch: (signal: AbortSignal) => Promise<ContentPage>, o: { client?: ContentKitClient }): UseContentsPage {\n const { store } = useContentScope(o.client);\n const r = useResource<ContentPage>(store, key, { type: \"cards\" }, fetch);\n return { items: r.data?.contents ?? NO_CARDS, summary: r.data?.summary, loading: r.loading || (!!key && !r.loaded), error: r.error, reload: r.reload };\n}\n\n/** Page `page` (from 1) of a list, with its summary; null reads nothing. */\nexport function useContentsPage(q: ContentQuery | null, page: number, o: { client?: ContentKitClient } = {}): UseContentsPage {\n const { client, scope } = useContentScope(o.client);\n const query = useDisplay(q);\n const n = Math.max(1, Math.floor(page));\n return useNumbered(query ? keyOf(\"cards\", scope, \"list-page\", query, n) : null, (signal) => client.discovery.list({ ...query!, cursor: undefined, page: n, summary: query!.summary ?? true }, signal), o);\n}\n\n/** Page `page` (from 1) of a search, with its summary; nothing until the query has text. */\nexport function useSearchPage(q: SearchQuery | null, page: number, o: { client?: ContentKitClient } = {}): UseContentsPage {\n const { client, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q?.q.trim() ? q : null);\n const n = Math.max(1, Math.floor(page));\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n return useNumbered(\n query ? keyOf(\"cards\", scope, \"search-page\", query, n) : null,\n async (signal) => {\n const out = await client.discovery.search({ ...query!, cursor: undefined, page: n, summary: query!.summary ?? true }, signal);\n if (n === 1 && viewer === null && !signal.aborted && isCurrent()) client.discovery.browserSearches.record(query!.q, out.contents.length);\n return out;\n },\n o,\n );\n}\n\n/** Locked contents in the same full selection, including its activity window. */\nexport function useLockedCount(q: ContentQuery | null, o: { client?: ContentKitClient } = {}): { count?: number; loading: boolean } {\n const { client, store, scope } = useContentScope(o.client);\n const filter = useMemo(() => {\n if (!q) return null;\n const { cursor: _cursor, ...rest } = q;\n return { ...rest, mode: \"lock\" as const, limit: 1, summary: true };\n }, [q]);\n const query = useDisplay(filter);\n const r = useResource<number>(store, query ? keyOf(\"cards\", scope, \"locked-summary\", query) : null, { type: \"cards\" }, async (signal) => {\n const out = await client.discovery.list(query!, signal);\n return out.summary?.locked_count ?? 0;\n });\n return { count: r.data, loading: r.loading };\n}\n\n/** Keyword search results as cards; nothing while q.q is empty. */\nexport function useSearch(q: SearchQuery | null, o: { client?: ContentKitClient } = {}): UseContents {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q?.q.trim() ? q : null);\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const list = useList(store, query ? keyOf(\"cards\", scope, \"search\", query) : null, { type: \"cards\" }, async (cursor, signal) => {\n const out = await client.discovery.search({ ...query!, cursor: cursor as string | undefined, summary: cursor ? undefined : query?.summary }, signal);\n if (!cursor && viewer === null && !signal.aborted && isCurrent()) client.discovery.browserSearches.record(query!.q, out.contents.length);\n return page(out);\n });\n return { ...list, summary: list.metadata };\n}\n\nexport interface UseRail {\n items: Card[];\n summary?: ContentPage[\"summary\"];\n loading: boolean;\n error?: ContentKitError;\n /** The site runs without the signal plane (not_configured): leave the rail out. */\n unavailable: boolean;\n reload: () => void;\n}\n\nfunction useRail(key: string | null, fetch: (signal: AbortSignal) => Promise<ContentPage>, o: { client?: ContentKitClient }): UseRail {\n const { store } = useContentScope(o.client);\n const r = useResource<ContentPage>(store, key, { type: \"cards\" }, fetch);\n const unavailable = r.error?.code === \"not_configured\";\n return { items: r.data?.contents ?? [], summary: r.data?.summary, loading: !!key && (r.loading || !r.loaded), error: unavailable ? undefined : r.error, unavailable, reload: r.reload };\n}\n\n/** Contents like one: co-engagement, or the site's configured source. */\nexport function useSimilar(id: string | null | undefined, q: RailQuery = {}, o: { client?: ContentKitClient } = {}): UseRail {\n const { client, scope } = useContentScope(o.client);\n const query = useDisplay(q)!;\n return useRail(id ? keyOf(\"cards\", scope, \"similar\", id, query) : null, (s) => client.discovery.similar(id!, query, s), o);\n}\n\n/** Contents for the signed-in reader; nothing signed out, or when q is null. */\nexport function useRecommendations(q: RailQuery | null = {}, o: { client?: ContentKitClient } = {}): UseRail {\n const { client, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q);\n return useRail(viewer === null || !query ? null : keyOf(\"cards\", scope, \"recommended\", query), (s) => client.discovery.recommendations(query!, s), o);\n}\n\n/** A release date bucket, keyed by its date. */\nexport type ReleaseDate = DateCount & { id: string };\n\n/** The release date index: per month or day, newest first. */\nexport function useReleaseDates(q: ReleaseDatesQuery = {}, o: { client?: ContentKitClient } = {}): UseList<ReleaseDate> {\n const { client, store, scope } = useContentScope(o.client);\n const query = useDisplay(q)!;\n return useList(store, keyOf(\"release-dates\", scope, query), { type: \"release-dates\" }, async (cursor, signal) => {\n const r = await client.discovery.releaseDates({ ...query, cursor: cursor as string | undefined }, signal);\n return { items: r.dates.map((d) => ({ ...d, id: d.date })), next: r.next_cursor ?? null };\n });\n}\n\nexport interface UseDailyReleases {\n data?: DailyReleases;\n loading: boolean;\n error?: ContentKitError;\n reload: () => void;\n}\n\n/** One complete calendar window, shared by all readers of the same query. */\nexport function useDailyReleases(q: DailyReleasesQuery | null = {}, o: { client?: ContentKitClient } = {}): UseDailyReleases {\n const { client, store, scope } = useContentScope(o.client);\n const query = useDisplay(q);\n const r = useResource<DailyReleases>(store, query ? keyOf(\"daily-releases\", scope, query) : null, { type: \"daily-releases\" }, (signal) => client.discovery.releases(query!, signal));\n return { data: r.data, loading: !!query && (r.loading || !r.loaded), error: r.error, reload: r.reload };\n}\n\nexport interface UseHistory extends UseContents {\n /** A status-filtered guest selection has hidden candidates whose current version facts cannot be inspected. */\n filterSummaryUnknown?: boolean;\n /** Erases the reader's history: of one content item, one kind, or (no argument) everything. */\n forget: (o?: { kind?: string; content_id?: string }) => Promise<void>;\n}\n\n/** Account history is authoritative; signed-out reading stays in this browser across tabs. */\nexport function useHistory(q: HistoryQuery | null = {}, o: { client?: ContentKitClient } = {}): UseHistory {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q);\n const guarded = useGuarded();\n const guest = viewer === null;\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const browser = client.guestHistory;\n const enabled = query !== null;\n const subscribe = useCallback((listener: () => void) => guest && enabled ? browser.subscribe(listener) : () => {}, [browser, guest, enabled]);\n const snapshot = useCallback(() => guest && enabled ? browser.snapshot() : NO_READING, [browser, guest, enabled]);\n const local = useSyncExternalStore(subscribe, snapshot, () => NO_READING);\n const selected = useMemo(() => local.filter(row => !query?.kind || row.kind === query.kind).slice(0, 100), [local, query?.kind]);\n const localRevision = guest ? selected.map(row => [row.id, row.at, row.checkpoints.map(checkpoint => [checkpoint.visit_id, checkpoint.segment_id, checkpoint.revision])]) : undefined;\n const list = useList(store, !query || viewer === undefined ? null : keyOf(\"history\", scope, query, localRevision), { type: \"history\" }, async (cursor, signal) => {\n if (!guest) return page(await client.discovery.history({ ...query, cursor: cursor as string | undefined, summary: cursor ? undefined : query?.summary }, signal));\n const offset = typeof cursor === \"number\" ? cursor : 0;\n const limit = Math.max(1, Math.min(100, query?.limit ?? 50));\n const batch = selected.slice(offset, offset + limit);\n if (!batch.length) return { items: [], next: null };\n // Public hydration enforces current hard-domain rules, access and optional preferences.\n const out = await client.discovery.list({ ids: (query?.summary && !cursor ? selected : batch).map(row => row.id), summary: !cursor ? query?.summary : undefined, kind: query?.kind, language: query?.language,\n display_language: query?.display_language, mode: query?.mode, card_entities: query?.card_entities, limit: 100 }, signal);\n const cards = new Map(out.contents.map(card => [card.id, card]));\n const items = batch.flatMap(row => {\n const card = cards.get(row.id); if (!card) return [];\n const viewer = guestStanding(card, row);\n if (query?.status === \"seen\" && !viewer.seen || query?.status === \"in_progress\" && (!viewer.seen || viewer.completed) || query?.status === \"completed\" && !viewer.completed) return [];\n return [{ ...card, viewer }];\n });\n return { items, next: offset + batch.length < selected.length ? offset + batch.length : null, metadata: out.summary };\n });\n const forget = useCallback((filter: { kind?: string; content_id?: string } = {}) => {\n if (!isCurrent()) return Promise.resolve();\n if (guest) { browser.clear(filter); return Promise.resolve(); }\n return guarded(() => client.discovery.forgetHistory(filter));\n }, [browser, client, guest, guarded, isCurrent]);\n const uncertain = guest && !!query?.status;\n return { ...list, summary: uncertain ? undefined : list.metadata, filterSummaryUnknown: uncertain && (list.metadata?.filtered_count ?? 0) > 0, forget };\n}\n\nexport interface UseRecentSearches {\n searches: RecentSearch[];\n loading: boolean;\n error?: ContentKitError;\n /** Clears one query, or every recent search. */\n clear: (query?: string) => Promise<void>;\n}\n\n/** Guest history stays in this browser; account history comes only from the server. enabled false reads nothing yet. */\nexport function useRecentSearches(o: { limit?: number; enabled?: boolean; client?: ContentKitClient } = {}): UseRecentSearches {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const guarded = useGuarded();\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const guest = viewer === null;\n const enabled = o.enabled !== false;\n const browser = client.discovery.browserSearches;\n const subscribe = useCallback((listener: () => void) => guest && enabled ? browser.subscribe(listener) : () => {}, [browser, guest, enabled]);\n const snapshot = useCallback(() => guest && enabled ? browser.snapshot() : NO_SEARCHES, [browser, guest, enabled]);\n const local = useSyncExternalStore(subscribe, snapshot, () => NO_SEARCHES);\n const searches = useMemo(() => local.slice(0, recentSearchLimit(o.limit)), [local, o.limit]);\n const key = !enabled || guest ? null : keyOf(\"searches\", scope, o.limit ?? 10);\n const r = useResource<RecentSearch[]>(store, key, { type: \"searches\" }, async (s) => (await client.discovery.recentSearches({ limit: o.limit }, s)).searches);\n useEffect(() => {\n if (!key) return;\n const reload = () => { if (!store.snapshot(key).loading) store.load(key, true); };\n // Reopening a panel must not leave an already-cached account list stale.\n if (store.snapshot(key).loaded) reload();\n const visible = () => { if (document.visibilityState === \"visible\") reload(); };\n if (typeof window !== \"undefined\") window.addEventListener(\"focus\", reload);\n if (typeof document !== \"undefined\") document.addEventListener(\"visibilitychange\", visible);\n return () => {\n if (typeof window !== \"undefined\") window.removeEventListener(\"focus\", reload);\n if (typeof document !== \"undefined\") document.removeEventListener(\"visibilitychange\", visible);\n };\n }, [key, store]);\n const clear = useCallback(async (query?: string) => {\n if (!isCurrent()) return;\n if (guest) { browser.clear(query); return; }\n await guarded(() => isCurrent() ? client.discovery.clearSearches(query ? { query } : {}) : Promise.resolve());\n }, [browser, client, guest, guarded, isCurrent]);\n return guest\n ? { searches: enabled ? searches : NO_SEARCHES, loading: false, clear }\n : { searches: r.data ?? NO_SEARCHES, loading: !!key && (r.loading || !r.loaded), error: r.error, clear };\n}\n\n/** A favorite or reaction with its content's or group's id. */\nexport type MyInteraction = Interaction & { id: string };\n\nconst interactions = (p: InteractionPage) => ({ items: p.items.map((x) => ({ ...x, id: x.content?.id ?? x.entity?.id ?? \"\" })), next: p.next_cursor ?? null, metadata: p.summary });\n\nexport interface UseInteractions extends UseList<MyInteraction, InteractionPage[\"summary\"]> { summary?: InteractionPage[\"summary\"] }\n\n/** The signed-in reader's favorites, most recent first: content cards or groups. */\nexport function useMyFavorites(q: MineQuery = {}, o: { client?: ContentKitClient } = {}): UseInteractions {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q)!;\n const list = useList(store, viewer === null ? null : keyOf(\"favorites\", scope, query), { type: \"favorites\" }, async (cursor, signal) =>\n interactions(await client.favorites.mine({ ...query, cursor: cursor as string | undefined, summary: cursor ? undefined : query.summary }, signal)),\n );\n return { ...list, summary: list.metadata };\n}\n\n/** What the signed-in reader liked (or, with value, disliked), most recent first. */\nexport function useMyReactions(q: MineQuery & { value?: \"like\" | \"dislike\" } = {}, o: { client?: ContentKitClient } = {}): UseInteractions {\n const { client, store, scope, viewer } = useContentScope(o.client);\n const query = useDisplay(q)!;\n const list = useList(store, viewer === null ? null : keyOf(\"reactions\", scope, query), { type: \"reactions\" }, async (cursor, signal) =>\n interactions(await client.reactions.mine({ ...query, cursor: cursor as string | undefined, summary: cursor ? undefined : query.summary }, signal)),\n );\n return { ...list, summary: list.metadata };\n}\n\nexport interface UseContentFilters {\n filters: ContentFilters | null;\n loading: boolean;\n error?: ContentKitError;\n saving: boolean;\n /** Atomically changes submitted entity choices; other choices are preserved. */\n save: (update: ContentFiltersUpdate) => Promise<ContentFilters>;\n setVisible: (entityId: string, visible: boolean) => Promise<ContentFilters>;\n setIncludeDeleted: (include: boolean) => Promise<ContentFilters>;\n}\n\n/** One current-domain control per entity, shared by all applies_to kinds. */\nexport function useContentFilters(o: { language?: string; client?: ContentKitClient } = {}): UseContentFilters {\n const { client, store, scope, viewer, language: provided } = useContentScope(o.client);\n const language = o.language ?? provided;\n const guest = viewer === null;\n const browser = client.preferences.browser;\n const local = useSyncExternalStore(browser.subscribe, browser.snapshot, browser.snapshot);\n const key = keyOf(\"content-filters\", scope, language);\n const previous = useRef<{\n client: ContentKitClient;\n language?: string;\n guest: boolean;\n data?: ContentFilters;\n } | null>(null);\n const initial =\n guest && previous.current?.guest && previous.current.client === client && previous.current.language === language\n ? previous.current.data\n : undefined;\n const r = useResource<ContentFilters>(\n store,\n key,\n { type: \"content-filters\" },\n (signal) => client.discovery.contentFilters(language, signal),\n { initial },\n );\n previous.current = { client, language, guest, data: r.data };\n const applyGuest = useCallback(\n (source: ContentFilters, choices = local): ContentFilters => {\n const values = new Map(choices.filters.map((row) => [row.entity_id, row]));\n return {\n ...source,\n include_deleted: false,\n filters: source.filters.map((row) => {\n const choice = values.get(row.entity.id);\n return { ...row, visible: choice?.visible ?? row.default_visible, overridden: choice?.visible !== undefined };\n }),\n };\n },\n [local],\n );\n const displayed = useMemo(() => (r.data && guest ? applyGuest(r.data) : r.data), [r.data, guest, applyGuest]);\n const guarded = useGuarded();\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const [inflight, setInflight] = useState(0);\n const current = useRef(displayed);\n current.current = displayed;\n useEffect(() => {\n setInflight(0);\n }, [client, scope]);\n const save = useCallback(\n async (update: ContentFiltersUpdate) => {\n if (!isCurrent()) throw new ContentKitError(\"aborted\", \"The account changed.\");\n if (guest) {\n const source = current.current;\n if (!source) throw new ContentKitError(\"invalid_request\", \"Content filters have not loaded.\");\n const allowed = new Set(source.filters.map((row) => row.entity.id));\n const updates: import(\"../client/browser-reader-preferences.js\").ReaderFilterChoice[] = [];\n const seen = new Set<string>();\n for (const row of update.filters ?? []) {\n if (!allowed.has(row.entity_id) || seen.has(row.entity_id))\n throw new ContentKitError(\"invalid_request\", \"This content filter is not configured or is set twice.\");\n seen.add(row.entity_id);\n if (row.default === true && row.visible === undefined)\n updates.push({ entity_id: row.entity_id, default: true });\n else if (row.default === undefined && typeof row.visible === \"boolean\")\n updates.push({ entity_id: row.entity_id, visible: row.visible });\n else throw new ContentKitError(\"invalid_request\", \"A content filter needs visible or default:true.\");\n }\n client.preferences.setGuestFilters(updates);\n return applyGuest(source, browser.snapshot());\n }\n const submitted = new Set((update.filters ?? []).map((row) => row.entity_id));\n const changesDeleted = typeof update.include_deleted === \"boolean\";\n setInflight((n) => n + 1);\n try {\n const out = await guarded(() => {\n if (!isCurrent()) throw new ContentKitError(\"aborted\", \"The account changed.\");\n return client.discovery.setContentFilters(update, language);\n });\n if (isCurrent()) {\n const rows = new Map(out.filters.map((row) => [row.entity.id, row]));\n // Another control may already have applied a newer response. Merge\n // only this request's choices, never its stale unrelated snapshot.\n store.set<ContentFilters>(key, (previous) => previous ? {\n ...previous,\n filters: previous.filters.flatMap((row) => {\n if (!submitted.has(row.entity.id)) return [row];\n const next = rows.get(row.entity.id);\n return next ? [next] : [];\n }),\n include_deleted: changesDeleted ? out.include_deleted : previous.include_deleted,\n } : out);\n }\n return out;\n } finally {\n setInflight((n) => Math.max(0, n - 1));\n }\n },\n [client, guarded, language, key, store, isCurrent, guest, browser, applyGuest],\n );\n const setVisible = useCallback(\n (entityId: string, visible: boolean) => save({ filters: [{ entity_id: entityId, visible }] }),\n [save],\n );\n const setIncludeDeleted = useCallback((include: boolean) => save({ include_deleted: include }), [save]);\n return {\n filters: displayed ?? null,\n loading: r.loading || !r.loaded,\n error: r.error,\n saving: inflight > 0,\n save,\n setVisible,\n setIncludeDeleted,\n };\n}\n\nexport interface UseTypeahead {\n contents: Card[];\n entities: GroupCard[];\n /** The query the suggestions answer (trimmed). */\n query: string;\n loading: boolean;\n error?: ContentKitError;\n}\n\nconst NONE: Pick<UseTypeahead, \"contents\" | \"entities\"> = { contents: [], entities: [] };\n\n/** Suggestions while the reader types: debounced, the stale ones abandoned. */\nexport function useTypeahead(\n text: string,\n o: Omit<TypeaheadQuery, \"q\"> & { debounce?: number; minLength?: number; client?: ContentKitClient; management?: boolean; request?: (query: TypeaheadQuery, signal: AbortSignal) => Promise<Typeahead> } = {},\n): UseTypeahead {\n const { client, language, scope: viewerScope } = useContentScope(o.client);\n const { debounce = 150, minLength = 1, client: _own, management = false, request, ...rest } = o;\n const scope = useMemo(() => ({ viewerScope, management, request }), [viewerScope, management, request]);\n const q = text.trim();\n const query = useMemo(() => ({ display_language: language, ...rest, q }), [language, q, JSON.stringify(rest)]); // eslint-disable-line react-hooks/exhaustive-deps\n const [state, setState] = useState<UseTypeahead & { scope: typeof scope }>({ ...NONE, query: \"\", loading: false, scope });\n useEffect(() => {\n if (q.length < minLength) {\n setState({ ...NONE, query: \"\", loading: false, scope });\n return;\n }\n setState((s) => ({ ...(s.scope === scope ? s : { ...NONE, query: \"\" }), loading: true, scope }));\n const ctl = new AbortController();\n const timer = setTimeout(() => {\n const pending = request ? request(query, ctl.signal) : management\n ? client.entities.manage({ q, kind: query.entity_kinds?.[0], language: query.display_language, limit: query.limit ?? 10 }, ctl.signal)\n .then((page) => ({ contents: [], entities: page.entities }))\n : client.discovery.typeahead(query, ctl.signal);\n pending.then(\n (r) => { if (!ctl.signal.aborted) setState({ contents: r.contents, entities: r.entities, query: q, loading: false, scope }); },\n (e) => {\n const error = toContentKitError(e);\n if (!ctl.signal.aborted && error.code !== \"aborted\") setState({ ...NONE, query: q, loading: false, error, scope });\n },\n );\n }, debounce);\n return () => {\n clearTimeout(timer);\n ctl.abort();\n };\n }, [client, query, q, debounce, minLength, management, request, scope]);\n return state.scope === scope ? state : { ...NONE, query: \"\", loading: q.length >= minLength };\n}\n\nconst beacons = new WeakMap<ContentKitClient, Beacons>();\n\n/** The client's signal and exposure batcher: one per client. */\nexport function beaconsFor(client: ContentKitClient, o?: BeaconOptions): Beacons {\n let b = beacons.get(client);\n if (!b) beacons.set(client, (b = new Beacons(client, o)));\n return b;\n}\n\nexport function useBeacons(o: { client?: ContentKitClient } = {}): Beacons {\n const { client } = useContentScope(o.client);\n return beaconsFor(client);\n}\n\nexport interface ExposureOptions {\n /** Where the list is: \"home\", \"search\", \"similar\". */\n surface: string;\n /** Changes with what the list shows: a new render id. */\n render: string;\n ranker?: string;\n query_id?: string;\n language?: string;\n client?: ContentKitClient;\n}\n\nexport interface UseExposure {\n /** The first bounded segment; click() selects the matching segment for later positions. */\n render_id: string;\n /** A card's ref: reports it shown once at least half of it is in view. */\n track: (content: string, position: number) => (el: Element | null) => void;\n /** Reports a click on the card at position. */\n click: (content: string, position: number) => void;\n}\n\n/** A rendered result list: each page rendered, each card shown, clicks attributed to the render. */\nexport function useExposure(items: readonly { id: string; position?: number; version_id?: string; version?: { id: string } | null }[], o: ExposureOptions): UseExposure {\n const { client, scope, language } = useContentScope(o.client);\n const b = beaconsFor(client);\n const isCurrent = useCurrentDiscoveryScope(client, scope);\n const renderId = useMemo(() => eventId(), [o.render, scope]); // eslint-disable-line react-hooks/exhaustive-deps\n const base = useMemo(() => ({ surface: o.surface, ranker: o.ranker, query_id: o.query_id, language: o.language ?? language }), [o.surface, o.ranker, o.query_id, o.language, language]);\n const state = useMemo(() => ({ segments: new Map<number, ExposureSegment>(), pending: new Set<number>(), timer: undefined as ReturnType<typeof setTimeout> | undefined }), [renderId]); // eslint-disable-line react-hooks/exhaustive-deps\n const segmentID = useCallback((index: number) => index === 0 ? renderId : `${renderId}-${index}`, [renderId]);\n const segmentFor = useCallback((index: number) => {\n let segment = state.segments.get(index);\n if (!segment) {\n segment = { rendered: new Map(), visible: new Map(), renderedRevision: 0, visibleRevision: 0 };\n state.segments.set(index, segment);\n }\n return segment;\n }, [state]);\n useEffect(() => {\n if (!isCurrent()) return;\n const changed = new Set<number>();\n for (const [i, item] of items.entries()) {\n const supplied = item.position;\n const position = supplied !== undefined && Number.isSafeInteger(supplied) && supplied > 0 ? supplied : i + 1;\n const index = Math.floor((position - 1) / EXPOSURE_SEGMENT_SIZE), segment = segmentFor(index);\n if (segment.rendered.has(item.id)) continue;\n segment.rendered.set(item.id, { content_id: item.id, version_id: item.version_id ?? item.version?.id, position });\n changed.add(index);\n }\n for (const index of changed) {\n const segment = segmentFor(index);\n b.exposure({ ...base, render_id: segmentID(index), stage: \"rendered\", revision: ++segment.renderedRevision,\n occurred_at: segment.renderedAt ??= new Date().toISOString(), shown: [...segment.rendered.values()] });\n }\n }, [b, base, items, state, segmentFor, segmentID, isCurrent]);\n const observer = useMemo(() => {\n if (typeof IntersectionObserver !== \"function\") return null;\n return new IntersectionObserver((entries) => {\n if (!isCurrent()) return;\n for (const e of entries) {\n if (!e.isIntersecting) continue;\n const el = e.target as HTMLElement, content = el.dataset.exposureContent!;\n const position = Number(el.dataset.exposurePosition), index = Math.floor((position - 1) / EXPOSURE_SEGMENT_SIZE);\n const segment = segmentFor(index);\n if (segment.visible.has(content)) continue;\n segment.visible.set(content, segment.rendered.get(content) ?? { content_id: content, position });\n state.pending.add(index);\n }\n if (!state.pending.size) return;\n state.timer ??= setTimeout(() => {\n state.timer = undefined;\n if (!isCurrent()) return;\n for (const index of state.pending) {\n const segment = segmentFor(index);\n b.exposure({ ...base, render_id: segmentID(index), stage: \"visible\", revision: ++segment.visibleRevision,\n occurred_at: segment.visibleAt ??= new Date().toISOString(), shown: [...segment.visible.values()] });\n }\n state.pending.clear();\n }, 300);\n }, { threshold: 0.5 });\n }, [b, base, state, segmentFor, segmentID, isCurrent]);\n useEffect(() => () => { observer?.disconnect(); clearTimeout(state.timer); }, [observer, state]);\n useEffect(() => {\n for (const index of state.segments.keys()) b.beginExposure(segmentID(index));\n return () => { for (const index of state.segments.keys()) b.endExposure(segmentID(index)); };\n }, [b, state, segmentID]);\n const track = useCallback((content: string, position: number) => (el: Element | null) => {\n if (!el || !observer) return;\n (el as HTMLElement).dataset.exposureContent = content;\n (el as HTMLElement).dataset.exposurePosition = String(position);\n observer.observe(el);\n }, [observer]);\n const click = useCallback((content: string, position: number) => {\n if (!isCurrent()) return;\n const index = Math.floor((position - 1) / EXPOSURE_SEGMENT_SIZE);\n const item = items.find((item) => item.id === content);\n const version = item?.version_id ?? item?.version?.id;\n b.click(content, { render_id: segmentID(index), surface: o.surface, position, version_id: version, language: base.language });\n }, [b, items, segmentID, o.surface, base.language, isCurrent]);\n return { render_id: renderId, track, click };\n}\n\ntype ObservedPlacement = { content_id: string; version_id?: string; position: number };\ntype ExposureSegment = {\n rendered: Map<string, ObservedPlacement>;\n visible: Map<string, ObservedPlacement>;\n renderedRevision: number;\n visibleRevision: number;\n renderedAt?: string;\n visibleAt?: string;\n};\nconst EXPOSURE_SEGMENT_SIZE = 32;\n"],"mappings":"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"}
|