@openrails/contentkit-ui 0.79.0 → 0.81.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +82 -54
- package/dist/client/beacons.d.ts +53 -0
- package/dist/client/beacons.js +72 -0
- package/dist/client/beacons.js.map +1 -0
- package/dist/client/catalog.d.ts +2 -2
- package/dist/client/catalog.js +1 -1
- package/dist/client/catalog.js.map +1 -1
- package/dist/client/client.d.ts +24 -11
- package/dist/client/client.js +37 -29
- package/dist/client/client.js.map +1 -1
- package/dist/client/content/comments.d.ts +12 -8
- package/dist/client/content/comments.js +33 -20
- package/dist/client/content/comments.js.map +1 -1
- package/dist/client/content/favorites.d.ts +24 -9
- package/dist/client/content/favorites.js +21 -22
- package/dist/client/content/favorites.js.map +1 -1
- package/dist/client/content/moderation.d.ts +1 -1
- package/dist/client/content/moderation.js.map +1 -1
- package/dist/client/content/reactions.d.ts +11 -6
- package/dist/client/content/reactions.js +23 -18
- package/dist/client/content/reactions.js.map +1 -1
- package/dist/client/content/types.d.ts +40 -21
- package/dist/client/content/types.js +5 -2
- package/dist/client/content/types.js.map +1 -1
- package/dist/client/contents.d.ts +55 -0
- package/dist/client/contents.js +144 -0
- package/dist/client/contents.js.map +1 -0
- package/dist/client/discovery.d.ts +126 -0
- package/dist/client/discovery.js +125 -0
- package/dist/client/discovery.js.map +1 -0
- package/dist/client/generated/error-codes.d.ts +1 -1
- package/dist/client/generated/error-codes.js +12 -0
- package/dist/client/generated/error-codes.js.map +1 -1
- package/dist/client/generated/routes.d.ts +1244 -370
- package/dist/client/generated/routes.js +1870 -554
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +960 -134
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/group-fields.d.ts +25 -0
- package/dist/client/group-fields.js +63 -0
- package/dist/client/group-fields.js.map +1 -0
- package/dist/client/groups.d.ts +58 -0
- package/dist/client/groups.js +119 -0
- package/dist/client/groups.js.map +1 -0
- package/dist/client/http.d.ts +24 -12
- package/dist/client/http.js +20 -24
- package/dist/client/http.js.map +1 -1
- package/dist/client/index.d.ts +11 -6
- package/dist/client/media/api.d.ts +1 -1
- package/dist/client/media/api.js +4 -2
- package/dist/client/media/api.js.map +1 -1
- package/dist/client/media/client.d.ts +8 -9
- package/dist/client/media/client.js +58 -71
- package/dist/client/media/client.js.map +1 -1
- package/dist/client/media/ref.d.ts +30 -0
- package/dist/client/media/ref.js +10 -3
- package/dist/client/media/ref.js.map +1 -1
- package/dist/client/offers.d.ts +41 -0
- package/dist/client/offers.js +66 -0
- package/dist/client/offers.js.map +1 -0
- package/dist/client/route.d.ts +2 -0
- package/dist/client/route.js +2 -1
- package/dist/client/route.js.map +1 -1
- package/dist/client/versions.d.ts +20 -0
- package/dist/client/versions.js +53 -0
- package/dist/client/versions.js.map +1 -0
- package/dist/client.js +35 -30
- package/dist/components/admin/content-manager.d.ts +80 -0
- package/dist/components/admin/content-manager.js +591 -0
- package/dist/components/admin/content-manager.js.map +1 -0
- package/dist/components/admin/group-manager.d.ts +24 -0
- package/dist/components/admin/group-manager.js +244 -0
- package/dist/components/admin/group-manager.js.map +1 -0
- package/dist/components/admin/media-item-panel.js +1 -1
- package/dist/components/admin/media-item-panel.js.map +1 -1
- package/dist/components/content/card.d.ts +44 -0
- package/dist/components/content/card.js +285 -0
- package/dist/components/content/card.js.map +1 -0
- package/dist/components/content/editors.d.ts +40 -0
- package/dist/components/content/editors.js +764 -0
- package/dist/components/content/editors.js.map +1 -0
- package/dist/components/content/filters.d.ts +28 -0
- package/dist/components/content/filters.js +134 -0
- package/dist/components/content/filters.js.map +1 -0
- package/dist/components/content/grid.d.ts +62 -0
- package/dist/components/content/grid.js +233 -0
- package/dist/components/content/grid.js.map +1 -0
- package/dist/components/content/index.d.ts +8 -0
- package/dist/components/content/listing.d.ts +20 -0
- package/dist/components/content/listing.js +150 -0
- package/dist/components/content/listing.js.map +1 -0
- package/dist/components/content/offer-fields.d.ts +8 -0
- package/dist/components/content/offer-fields.js +127 -0
- package/dist/components/content/offer-fields.js.map +1 -0
- package/dist/components/content/paywall.d.ts +53 -0
- package/dist/components/content/paywall.js +221 -0
- package/dist/components/content/paywall.js.map +1 -0
- package/dist/components/content/search.d.ts +27 -0
- package/dist/components/content/search.js +164 -0
- package/dist/components/content/search.js.map +1 -0
- package/dist/components/groups/banner.d.ts +51 -0
- package/dist/components/groups/banner.js +194 -0
- package/dist/components/groups/banner.js.map +1 -0
- package/dist/components/groups/directory.d.ts +37 -0
- package/dist/components/groups/directory.js +117 -0
- package/dist/components/groups/directory.js.map +1 -0
- package/dist/components/groups/editor.d.ts +44 -0
- package/dist/components/groups/editor.js +860 -0
- package/dist/components/groups/editor.js.map +1 -0
- package/dist/components/groups/fields.d.ts +13 -0
- package/dist/components/groups/fields.js +68 -0
- package/dist/components/groups/fields.js.map +1 -0
- package/dist/components/groups/header.d.ts +25 -0
- package/dist/components/groups/header.js +131 -0
- package/dist/components/groups/header.js.map +1 -0
- package/dist/components/groups/index.d.ts +6 -0
- package/dist/components/groups/memberships.d.ts +55 -0
- package/dist/components/groups/memberships.js +527 -0
- package/dist/components/groups/memberships.js.map +1 -0
- package/dist/components/groups/parts.d.ts +49 -0
- package/dist/components/groups/parts.js +172 -0
- package/dist/components/groups/parts.js.map +1 -0
- package/dist/components/media-folder-editor.js +153 -152
- package/dist/components/media-folder-editor.js.map +1 -1
- package/dist/components/social/comments.d.ts +7 -5
- package/dist/components/social/comments.js +6 -2
- package/dist/components/social/comments.js.map +1 -1
- package/dist/components/social/engagement.d.ts +4 -3
- package/dist/components/social/engagement.js.map +1 -1
- package/dist/components/social/moderation.d.ts +1 -1
- package/dist/components/social/moderation.js +3 -3
- package/dist/components/social/moderation.js.map +1 -1
- package/dist/editor/rich-text-editor.d.ts +4 -4
- package/dist/editor/rich-text-editor.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.js +23 -9
- package/dist/locales/admin/de.js +5 -66
- package/dist/locales/admin/de.js.map +1 -1
- package/dist/locales/admin/en.d.ts +5 -66
- package/dist/locales/admin/en.js +19 -80
- package/dist/locales/admin/en.js.map +1 -1
- package/dist/locales/admin/es.js +5 -66
- package/dist/locales/admin/es.js.map +1 -1
- package/dist/locales/admin/ja.js +5 -66
- package/dist/locales/admin/ja.js.map +1 -1
- package/dist/locales/admin/ko.js +5 -66
- package/dist/locales/admin/ko.js.map +1 -1
- package/dist/locales/admin/zh.js +5 -66
- package/dist/locales/admin/zh.js.map +1 -1
- package/dist/locales/content/de.d.ts +2 -0
- package/dist/locales/content/de.js +98 -0
- package/dist/locales/content/de.js.map +1 -0
- package/dist/locales/content/en.d.ts +93 -0
- package/dist/locales/content/en.js +98 -0
- package/dist/locales/content/en.js.map +1 -0
- package/dist/locales/content/es.d.ts +2 -0
- package/dist/locales/content/es.js +98 -0
- package/dist/locales/content/es.js.map +1 -0
- package/dist/locales/content/ja.d.ts +2 -0
- package/dist/locales/content/ja.js +98 -0
- package/dist/locales/content/ja.js.map +1 -0
- package/dist/locales/content/ko.d.ts +2 -0
- package/dist/locales/content/ko.js +98 -0
- package/dist/locales/content/ko.js.map +1 -0
- package/dist/locales/content/zh.d.ts +2 -0
- package/dist/locales/content/zh.js +98 -0
- package/dist/locales/content/zh.js.map +1 -0
- package/dist/locales/de.js +11 -2
- package/dist/locales/de.js.map +1 -1
- package/dist/locales/discovery/de.d.ts +2 -0
- package/dist/locales/discovery/de.js +68 -0
- package/dist/locales/discovery/de.js.map +1 -0
- package/dist/locales/discovery/en.d.ts +63 -0
- package/dist/locales/discovery/en.js +68 -0
- package/dist/locales/discovery/en.js.map +1 -0
- package/dist/locales/discovery/es.d.ts +2 -0
- package/dist/locales/discovery/es.js +68 -0
- package/dist/locales/discovery/es.js.map +1 -0
- package/dist/locales/discovery/ja.d.ts +2 -0
- package/dist/locales/discovery/ja.js +68 -0
- package/dist/locales/discovery/ja.js.map +1 -0
- package/dist/locales/discovery/ko.d.ts +2 -0
- package/dist/locales/discovery/ko.js +68 -0
- package/dist/locales/discovery/ko.js.map +1 -0
- package/dist/locales/discovery/zh.d.ts +2 -0
- package/dist/locales/discovery/zh.js +68 -0
- package/dist/locales/discovery/zh.js.map +1 -0
- package/dist/locales/en.d.ts +288 -67
- package/dist/locales/en.js +11 -2
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +11 -2
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/groups/de.d.ts +2 -0
- package/dist/locales/groups/de.js +133 -0
- package/dist/locales/groups/de.js.map +1 -0
- package/dist/locales/groups/en.d.ts +128 -0
- package/dist/locales/groups/en.js +133 -0
- package/dist/locales/groups/en.js.map +1 -0
- package/dist/locales/groups/es.d.ts +2 -0
- package/dist/locales/groups/es.js +133 -0
- package/dist/locales/groups/es.js.map +1 -0
- package/dist/locales/groups/ja.d.ts +2 -0
- package/dist/locales/groups/ja.js +133 -0
- package/dist/locales/groups/ja.js.map +1 -0
- package/dist/locales/groups/ko.d.ts +2 -0
- package/dist/locales/groups/ko.js +133 -0
- package/dist/locales/groups/ko.js.map +1 -0
- package/dist/locales/groups/zh.d.ts +2 -0
- package/dist/locales/groups/zh.js +133 -0
- package/dist/locales/groups/zh.js.map +1 -0
- package/dist/locales/ja.js +11 -2
- package/dist/locales/ja.js.map +1 -1
- package/dist/locales/ko.js +11 -2
- package/dist/locales/ko.js.map +1 -1
- package/dist/locales/social/de.js +2 -1
- package/dist/locales/social/de.js.map +1 -1
- package/dist/locales/social/en.d.ts +2 -1
- package/dist/locales/social/en.js +2 -1
- package/dist/locales/social/en.js.map +1 -1
- package/dist/locales/social/es.js +2 -1
- package/dist/locales/social/es.js.map +1 -1
- package/dist/locales/social/ja.js +2 -1
- package/dist/locales/social/ja.js.map +1 -1
- package/dist/locales/social/ko.js +2 -1
- package/dist/locales/social/ko.js.map +1 -1
- package/dist/locales/social/zh.js +2 -1
- package/dist/locales/social/zh.js.map +1 -1
- package/dist/locales/zh.js +11 -2
- package/dist/locales/zh.js.map +1 -1
- package/dist/react/admin.d.ts +1 -1
- package/dist/react/admin.js +8 -6
- package/dist/react/admin.js.map +1 -1
- package/dist/react/comments.d.ts +9 -7
- package/dist/react/comments.js +42 -27
- package/dist/react/comments.js.map +1 -1
- package/dist/react/contents.d.ts +57 -0
- package/dist/react/contents.js +214 -0
- package/dist/react/contents.js.map +1 -0
- package/dist/react/context.d.ts +1 -1
- package/dist/react/context.js.map +1 -1
- package/dist/react/crop.js +45 -44
- package/dist/react/crop.js.map +1 -1
- package/dist/react/detail.d.ts +30 -0
- package/dist/react/detail.js +42 -0
- package/dist/react/detail.js.map +1 -0
- package/dist/react/discovery.d.ts +138 -0
- package/dist/react/discovery.js +299 -0
- package/dist/react/discovery.js.map +1 -0
- package/dist/react/engagement.d.ts +5 -5
- package/dist/react/engagement.js +55 -41
- package/dist/react/engagement.js.map +1 -1
- package/dist/react/folder.js +54 -53
- package/dist/react/folder.js.map +1 -1
- package/dist/react/groups.d.ts +115 -0
- package/dist/react/groups.js +229 -0
- package/dist/react/groups.js.map +1 -0
- package/dist/react/index.d.ts +5 -1
- package/dist/react/public.d.ts +6 -5
- package/dist/react/public.js +19 -22
- package/dist/react/public.js.map +1 -1
- package/dist/react/read.js +105 -106
- package/dist/react/read.js.map +1 -1
- package/dist/react/resources.d.ts +2 -2
- package/dist/react/resources.js +69 -40
- package/dist/react/resources.js.map +1 -1
- package/dist/react/store.js +41 -39
- package/dist/react/store.js.map +1 -1
- package/dist/react/upload.js +54 -53
- package/dist/react/upload.js.map +1 -1
- package/dist/react/use-resource.d.ts +2 -1
- package/dist/react/use-resource.js +1 -0
- package/dist/react/use-resource.js.map +1 -1
- package/dist/react/versions.d.ts +57 -0
- package/dist/react/versions.js +94 -0
- package/dist/react/versions.js.map +1 -0
- package/dist/react/video.js +87 -86
- package/dist/react/video.js.map +1 -1
- package/dist/react.js +9 -5
- package/dist/styles.css +1 -1
- package/package.json +1 -1
- package/dist/client/content/posts.d.ts +0 -52
- package/dist/client/content/posts.js +0 -84
- package/dist/client/content/posts.js.map +0 -1
- package/dist/client/taxonomy.d.ts +0 -34
- package/dist/client/taxonomy.js +0 -84
- package/dist/client/taxonomy.js.map +0 -1
- package/dist/components/admin/post-manager.d.ts +0 -45
- package/dist/components/admin/post-manager.js +0 -602
- package/dist/components/admin/post-manager.js.map +0 -1
- package/dist/components/admin/taxonomy-manager.d.ts +0 -54
- package/dist/components/admin/taxonomy-manager.js +0 -976
- package/dist/components/admin/taxonomy-manager.js.map +0 -1
- package/dist/react/posts.d.ts +0 -61
- package/dist/react/posts.js +0 -183
- package/dist/react/posts.js.map +0 -1
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ pnpm add @openrails/contentkit-ui@X.Y.Z
|
|
|
15
15
|
| `@openrails/contentkit-ui/react` | `ContentKitProvider` and every hook | `react` |
|
|
16
16
|
| `@openrails/contentkit-ui/client` | `createContentKitClient`, `ContentKitError`, generated wire types, crop/aspect/rendition/ABR/gallery math | nothing |
|
|
17
17
|
| `@openrails/contentkit-ui/urls` | content codes, `[/{lang}]/{route}/{CODE}[/{slug}]` paths, `canonical` | nothing |
|
|
18
|
-
| `@openrails/contentkit-ui/editor` | `RichTextEditor`, `richTextEditor` (
|
|
18
|
+
| `@openrails/contentkit-ui/editor` | `RichTextEditor`, `richTextEditor` (ContentManager's body editor) | the optional peers `@tiptap/core`, `@tiptap/pm`, `@tiptap/react`, `@tiptap/starter-kit`, `@tiptap/extension-image`, `@tiptap/extensions` (3.31+) |
|
|
19
19
|
| `@openrails/contentkit-ui/locales/{de,es,ja,ko,zh}` | message bundles (English is built in) | |
|
|
20
20
|
| `@openrails/contentkit-ui/styles.css` | the stylesheet, scoped under `.ckui` (the root entry also installs it) | |
|
|
21
21
|
|
|
@@ -31,7 +31,7 @@ import { ContentKitUiProvider } from "@openrails/contentkit-ui";
|
|
|
31
31
|
import { createContentURLs } from "@openrails/contentkit-ui/urls";
|
|
32
32
|
|
|
33
33
|
const contentkit = createContentKitClient({
|
|
34
|
-
baseUrl: "/api/
|
|
34
|
+
baseUrl: "/api/contentkit", // the host's contentkit.Routes.Prefix
|
|
35
35
|
mounts: { upload: "/api/v1/user-uploads" }, // optional: modules mounted elsewhere (a string, or (ref) => string)
|
|
36
36
|
fetch: auth.authFetch, // an authenticating transport
|
|
37
37
|
token: () => auth.getAccessToken(), // HLS playlists on the API origin (hls.js uses XHR)
|
|
@@ -72,8 +72,9 @@ The framework-free client exposes `setReadScope(key)` and passes that key as
|
|
|
72
72
|
the second `subscribe` / `onChange` argument, or `null` when the scope changed during the
|
|
73
73
|
operation. This does not change the operation's result or its authentication.
|
|
74
74
|
|
|
75
|
-
- **Mounts.** Without `mounts`, modules live under `baseUrl`: content
|
|
76
|
-
root, `/media` (reads, HLS),
|
|
75
|
+
- **Mounts.** Without `mounts`, modules live under `{baseUrl}/v1`: content,
|
|
76
|
+
groups and the content model at its root, `/media` (reads, HLS),
|
|
77
|
+
`/media/upload`, `/codes`. A mount is a module's full base URL.
|
|
77
78
|
- **`client.media`**: `upload`, `put` (upload, commit, wait), `commit`, `read`,
|
|
78
79
|
`waitFor`, `editorView`, `getFrame`, `hlsBase(ref, dir)`, `discard`, and
|
|
79
80
|
`xhrSetup` for players (`<MediaGallery xhrSetup={contentkit.media.xhrSetup} />`).
|
|
@@ -81,23 +82,25 @@ operation. This does not change the operation's result or its authentication.
|
|
|
81
82
|
resumable multipart above (`onState`/`resume`). The bucket must allow CORS
|
|
82
83
|
`PUT` from the app's origin with `Content-Type` and `x-amz-checksum-sha256`.
|
|
83
84
|
- **Content modules**, one per resource, each method one route of the
|
|
84
|
-
generated route table with its generated types: `
|
|
85
|
+
generated route table with its generated types: `contents`, `catalog`, `comments`,
|
|
85
86
|
`reactions`, `favorites`, `polls`, `bans` (`"owner"` or `"global"`; `get("global", user)`),
|
|
86
|
-
`moderation`, `
|
|
87
|
-
queue a `cursor`);
|
|
88
|
-
`
|
|
89
|
-
`
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
`
|
|
93
|
-
|
|
94
|
-
(
|
|
95
|
-
|
|
87
|
+
`moderation`, `groups`, `codes`. Lists take `limit`/`offset` (the review
|
|
88
|
+
queue and group listings a `cursor`); `contents.manage` lists what the caller
|
|
89
|
+
manages (`kind`, `state` incl. `deleted` for `contents.restore`, `q`); `catalog.totals({kinds, languages})`
|
|
90
|
+
counts what is open; staff lists are `polls.adminList` (`state`, `q`),
|
|
91
|
+
`comments.adminList` (`contentKind`, `author`); `groups.members(id)` pages
|
|
92
|
+
a group's memberships, `groups.ofContent(id)` / `setOfContent` a content's,
|
|
93
|
+
`groups.uploadCover(group, file)` its cover; `client.kinds()` the content model.
|
|
94
|
+
- **Images of content and polls** go to the item's server-named upload path:
|
|
95
|
+
`media.uploadNamed(ref, file)` resolves the name content routes take
|
|
96
|
+
(`contents.setCover`); `media.uploadInline({kind, id}, file)` resolves a
|
|
97
|
+
body image's reference (`ref`, `contentkit:i-{uuid}`, what the body stores:
|
|
98
|
+
`imageRef(name)`) and a URL that shows it now; `polls.uploadImage` and
|
|
96
99
|
`polls.uploadOptionImage` do both steps. Reads resolve references: a
|
|
97
|
-
|
|
98
|
-
each name to its URL. `folders` renames the
|
|
99
|
-
|
|
100
|
-
|
|
100
|
+
content's `body` shows the images' current public files and `images` maps
|
|
101
|
+
each name to its URL. `folders` renames the poll media kind. Public image
|
|
102
|
+
files exist only while the item is live; `useContent` shows an unpublished
|
|
103
|
+
item's images to its editors (below).
|
|
101
104
|
- **`client.config()`** says what the content module allows: which
|
|
102
105
|
interactions signed-out visitors may make (`content.Options.Anonymous`,
|
|
103
106
|
none by default) and the longest comment (`CommentMaxLength`, 2,200 by
|
|
@@ -145,23 +148,23 @@ const { poll, vote } = usePoll(null, { language }); // the newest live poll
|
|
|
145
148
|
const editor = usePollEditor(pollId); // staff
|
|
146
149
|
```
|
|
147
150
|
|
|
148
|
-
A
|
|
151
|
+
A content editor puts `text.body` in its rich-text field and inserts what
|
|
149
152
|
`uploadImage(file)` resolves: URLs that show the images now (the file for a
|
|
150
|
-
fresh upload, public files, signed editor views of an unpublished
|
|
151
|
-
images, read and refreshed as needed). `
|
|
152
|
-
those URLs as the image's reference (`storedBody(html)` does the same for
|
|
153
|
-
host's own save); `coverSrc` shows the cover, `imageSrc(name)` any image.
|
|
153
|
+
fresh upload, public files, signed editor views of an unpublished item's
|
|
154
|
+
images, read and refreshed as needed). `putText({ title, body })` stores each
|
|
155
|
+
of those URLs as the image's reference (`storedBody(html)` does the same for
|
|
156
|
+
a host's own save); `coverSrc` shows the cover, `imageSrc(name)` any image.
|
|
154
157
|
|
|
155
158
|
```tsx
|
|
156
|
-
const editor =
|
|
157
|
-
<RichText value={editor.
|
|
159
|
+
const editor = useContent(id, "blog", "en");
|
|
160
|
+
<RichText value={editor.text?.body} onImage={editor.uploadImage} onSave={(html) => editor.putText({ title, body: html })} />
|
|
158
161
|
<img src={editor.coverSrc} alt="" />
|
|
159
162
|
```
|
|
160
163
|
|
|
161
164
|
Also `useContentConfig` (`client.config()`, read once), `useCommentReplies`,
|
|
162
165
|
`useCanComment` (may the caller comment, may signed-out visitors, the ban
|
|
163
166
|
that stops it, and what it may do to others' comments), `useLatestComments`,
|
|
164
|
-
`usePolls`, `
|
|
167
|
+
`usePolls`, `useManagedContents` (`kind`, `state`, `q`), `useContent` (with `publish`, `restore`), and for staff `useAdminComments`
|
|
165
168
|
(`contentKind`, `author`), `useModerationQueue`, `useCommentBans`, `useGlobalCommentBan` (one user's), and
|
|
166
169
|
`useStaffAccess`, `useAdminLocation`, `useFlowClient` and `usePaged`, which the admin flows are built from.
|
|
167
170
|
|
|
@@ -226,7 +229,7 @@ op. Nothing is uploaded.
|
|
|
226
229
|
### usePublicImage
|
|
227
230
|
|
|
228
231
|
```tsx
|
|
229
|
-
const { image, rule, isDefault } = usePublicImage("user", userId, "avatar");
|
|
232
|
+
const { image, rule, isDefault } = usePublicImage({ kind: "user", id: userId }, "avatar");
|
|
230
233
|
<SlotImage image={image} fallback={<Initials name={name} />} />
|
|
231
234
|
```
|
|
232
235
|
|
|
@@ -415,6 +418,37 @@ Staff building blocks: `CommentBans` (paged) with `CommentBanDialog`, and
|
|
|
415
418
|
<Poll language={lang} />
|
|
416
419
|
```
|
|
417
420
|
|
|
421
|
+
## Groups
|
|
422
|
+
|
|
423
|
+
Tags, artists, series, characters, channels and rails: the kinds the site's
|
|
424
|
+
content model declares. `useKinds()` reads it (`GET /v1/kinds`); until that
|
|
425
|
+
route is served, pass the host's model as `initial` (and `kinds` to the
|
|
426
|
+
components below).
|
|
427
|
+
|
|
428
|
+
```tsx
|
|
429
|
+
const { items, hasMore, loadMore } = useGroups({ kind: "artist", letter: "a", sort: "count" }); // parent, scope, contentKind, language
|
|
430
|
+
const g = useGroup(id); // g.group: names, text, attributes, parent, scope, children, edges, counts
|
|
431
|
+
await g.update({ attributes: { artist_type: "circle" } }); // staff: create, names, edges, merge, remove, restore
|
|
432
|
+
await g.uploadCover(file); // into the group kind's folder (cover/{name}), then selected
|
|
433
|
+
const members = useGroupMembers(id); // add, remove, reorder
|
|
434
|
+
const content = useContentGroups(contentId); // content.set(memberships, kinds)
|
|
435
|
+
```
|
|
436
|
+
|
|
437
|
+
- **`GroupDirectory`**: one kind's groups with A–Z buckets (`letter` and
|
|
438
|
+
`onLetterChange` to keep it in the URL), content counts, `layout` list or
|
|
439
|
+
grid, paged. **`GroupHeader`**: a group page's cover, names, description,
|
|
440
|
+
typed attributes, parent, scope and sub-groups. Links go to each group's
|
|
441
|
+
canonical path (`href` overrides) through the provider's `navigate`.
|
|
442
|
+
- **`GroupEditor`** (staff): create, or edit slug, parent, scope, declared
|
|
443
|
+
attributes, names and aliases per language, description and sort key per
|
|
444
|
+
language, cover, related groups; `GroupMergeDialog`; delete and restore.
|
|
445
|
+
- **`MembershipEditor`** (staff): a content's groups per group kind, with the
|
|
446
|
+
version (`versions`), role, position and window each kind allows; one save.
|
|
447
|
+
**`GroupMembers`**: a group's members, reordered, windowed, used as cover.
|
|
448
|
+
- `labels` names kinds, attributes, roles and values by identifier; others
|
|
449
|
+
show humanized. Covers render `cover.renditions`; `renderCover` stands in
|
|
450
|
+
until group reads carry them.
|
|
451
|
+
|
|
418
452
|
## Admin flows
|
|
419
453
|
|
|
420
454
|
Drop-in staff screens for a host's own admin area: each makes its own reads
|
|
@@ -448,7 +482,7 @@ const nav = useMemo(() => ({ pathname: location.pathname, search: location.searc
|
|
|
448
482
|
`userHref`, `sections`, `pageSize`. `useCommentModerationAccess()`.
|
|
449
483
|
|
|
450
484
|
```tsx
|
|
451
|
-
<CommentModeration client={contentkit} basePath="/admin/comments" navigation={nav} contentKinds={["video", "
|
|
485
|
+
<CommentModeration client={contentkit} basePath="/admin/comments" navigation={nav} contentKinds={["video", "blog"]} />
|
|
452
486
|
```
|
|
453
487
|
|
|
454
488
|
- **`PollManager`**: every poll by language, month or day, state (live,
|
|
@@ -461,39 +495,23 @@ const nav = useMemo(() => ({ pathname: location.pathname, search: location.searc
|
|
|
461
495
|
<PollManager client={contentkit} basePath="/admin/polls" navigation={nav} languages={["en", "ja"]} />
|
|
462
496
|
```
|
|
463
497
|
|
|
464
|
-
- **`
|
|
465
|
-
ones to restore; title, slug,
|
|
466
|
-
with inline images
|
|
467
|
-
|
|
468
|
-
host's; a plain
|
|
469
|
-
`
|
|
498
|
+
- **`ContentManager`**: the items of one `kind` the caller manages, by
|
|
499
|
+
state and text, deleted ones to restore; title, slug, description,
|
|
500
|
+
schedule, cover and body with inline images per language; publish or
|
|
501
|
+
unpublish; the moderation state. Props: `kind`, `languages`,
|
|
502
|
+
`renderEditor` (`richTextEditor` from `/editor`, or the host's; a plain
|
|
503
|
+
HTML field without it), `contentHref`, `pageSize`.
|
|
504
|
+
`useContentManagerAccess()`.
|
|
470
505
|
|
|
471
506
|
```tsx
|
|
472
507
|
import { richTextEditor } from "@openrails/contentkit-ui/editor";
|
|
473
|
-
<
|
|
508
|
+
<ContentManager kind="blog" client={contentkit} basePath="/admin/blog" navigation={nav} renderEditor={richTextEditor} />
|
|
474
509
|
```
|
|
475
510
|
|
|
476
511
|
`RichTextEditor` (`value`, `onChange`, `uploadImage`) is Tiptap: headings,
|
|
477
512
|
emphasis, lists, quotes, links and images picked, pasted or dropped. Its
|
|
478
513
|
HTML keeps to that schema, so bodies stay a small, predictable subset.
|
|
479
514
|
|
|
480
|
-
- **`TaxonomyManager`**: the taxonomy per kind (`kinds`: `kind`, `label`,
|
|
481
|
-
`relations` such as a character `member_of` a series, `cover` in a media
|
|
482
|
-
kind). Each kind's nodes by name, state, language, minimum count and order
|
|
483
|
-
at `basePath/{kind}`; a node at `basePath/{kind}/{id}`: slug, names and
|
|
484
|
-
aliases per language, host fields (`renderFields`), relations with a
|
|
485
|
-
typeahead (both directions), cover, counts and assigned contents
|
|
486
|
-
(`renderContent`); create, delete, restore, and merge with a typed
|
|
487
|
-
confirmation. Props: `kinds`, `languages`, `contentKind`, `renderFields`,
|
|
488
|
-
`renderContent`, `pageSize`. `useTaxonomyManagerAccess()`. Host-owned
|
|
489
|
-
fields stay in host tables.
|
|
490
|
-
|
|
491
|
-
```tsx
|
|
492
|
-
<TaxonomyManager client={contentkit} basePath="/admin/taxonomy" navigation={nav} languages={["en", "ja"]}
|
|
493
|
-
kinds={[{ kind: "tag", label: "Tags" }, { kind: "series", label: "Series", cover: { kind: "series" } },
|
|
494
|
-
{ kind: "character", label: "Characters", relations: [{ relation: "member_of", to: "series", label: "Series" }] }]} />
|
|
495
|
-
```
|
|
496
|
-
|
|
497
515
|
- **`MediaItemPanel`**: one video item for its editors: encode state and
|
|
498
516
|
progress, failures with their reason, replace the source, subtitle
|
|
499
517
|
sidecars (language, label, forced), the poster from a frame or an image,
|
|
@@ -518,6 +536,16 @@ const nav = useMemo(() => ({ pathname: location.pathname, search: location.searc
|
|
|
518
536
|
The per-item queue engine behind `useUploadQueue` is `ItemUploadQueue` in
|
|
519
537
|
`/client`.
|
|
520
538
|
|
|
539
|
+
- **`GroupManager`**: groups per kind (tabs at `basePath/{kind}`): by
|
|
540
|
+
letter, order and language; a new group at `basePath/{kind}/new`; a group
|
|
541
|
+
at `basePath/{kind}/{id}` with `GroupEditor` and `GroupMembers`. Props:
|
|
542
|
+
`groupKinds` (default the model's site-owned ones), `kinds`, `labels`,
|
|
543
|
+
`contentKind`, `renderContent`, `pageSize`. `useGroupManagerAccess()`.
|
|
544
|
+
|
|
545
|
+
```tsx
|
|
546
|
+
<GroupManager client={contentkit} basePath="/admin/groups" navigation={nav} labels={{ artist: "Artists" }} />
|
|
547
|
+
```
|
|
548
|
+
|
|
521
549
|
- **`UserCommentStanding`**: for a user page, the person's site-wide comment
|
|
522
550
|
ban (ban, replace, lift) and their recent comments (delete, restore). Props:
|
|
523
551
|
`user` (their id), `name`, `itemHref`, `pageSize`.
|
|
@@ -569,7 +597,7 @@ pnpm demo # the stack with seeded demo pages, until Ctrl-C
|
|
|
569
597
|
```
|
|
570
598
|
|
|
571
599
|
The suites need Docker, Go and ffmpeg. `e2e/server` composes the real
|
|
572
|
-
|
|
600
|
+
ContentKit's engine (content, groups, codes, media upload and read) with
|
|
573
601
|
AuthKit for identity over PGroonga PostgreSQL 18, MinIO, and media-worker and
|
|
574
602
|
media-gateway built from this checkout (`e2e/compose.yaml`). Each run brings
|
|
575
603
|
the stack up under its own project name and takes it down; the server exits
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { DiscoveryClient } from './discovery.js';
|
|
2
|
+
import { ExposureInput } from './generated/wire.js';
|
|
3
|
+
export interface BeaconOptions {
|
|
4
|
+
/** A signed-out visitor's session; default one per browser tab. */
|
|
5
|
+
session?: () => string | undefined;
|
|
6
|
+
/** How long events gather before they are sent, ms. Default 2000. */
|
|
7
|
+
delay?: number;
|
|
8
|
+
}
|
|
9
|
+
/** Where a click or a view came from: the list render it was shown in. */
|
|
10
|
+
export interface Attribution {
|
|
11
|
+
render_id?: string;
|
|
12
|
+
surface?: string;
|
|
13
|
+
/** 1-based position in that render. */
|
|
14
|
+
position?: number;
|
|
15
|
+
}
|
|
16
|
+
export interface ViewSession {
|
|
17
|
+
/** Reports the view so far: pages read, seconds watched or percent scrolled; resume is where to pick up. */
|
|
18
|
+
update(o: {
|
|
19
|
+
progress?: number;
|
|
20
|
+
duration_s?: number;
|
|
21
|
+
resume?: string;
|
|
22
|
+
}): void;
|
|
23
|
+
}
|
|
24
|
+
export declare const eventId: () => string;
|
|
25
|
+
/** A signed-out reader's session: one per browser tab, kept across reloads. */
|
|
26
|
+
export declare function readerSession(): string;
|
|
27
|
+
/**
|
|
28
|
+
* Batched, best-effort signals and exposures: gathered for `delay`, sent in
|
|
29
|
+
* one request each, flushed with keepalive when the page hides. A site
|
|
30
|
+
* without the signal plane (not_configured) turns them off.
|
|
31
|
+
*/
|
|
32
|
+
export declare class Beacons {
|
|
33
|
+
private readonly discovery;
|
|
34
|
+
private signals;
|
|
35
|
+
private exposures;
|
|
36
|
+
private timer;
|
|
37
|
+
private off;
|
|
38
|
+
private readonly session;
|
|
39
|
+
private readonly delay;
|
|
40
|
+
constructor(discovery: DiscoveryClient, o?: BeaconOptions);
|
|
41
|
+
/** A click on a listed card. */
|
|
42
|
+
click(content: string, a?: Attribution & {
|
|
43
|
+
version_id?: string;
|
|
44
|
+
}): void;
|
|
45
|
+
/** A consumption session of a content (or one version): each update a revision of one event. */
|
|
46
|
+
view(content: string, version?: string, a?: Attribution): ViewSession;
|
|
47
|
+
/** A result list served, rendered or shown. */
|
|
48
|
+
exposure(e: ExposureInput): void;
|
|
49
|
+
/** Sends what has gathered now. */
|
|
50
|
+
flush(keepalive?: boolean): Promise<void>;
|
|
51
|
+
private signal;
|
|
52
|
+
private schedule;
|
|
53
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { toContentKitError as e } from "./errors.js";
|
|
2
|
+
//#region src/client/beacons.ts
|
|
3
|
+
var t = 100, n = "contentkit.session", r = () => typeof crypto < "u" && "randomUUID" in crypto ? crypto.randomUUID() : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`, i;
|
|
4
|
+
function a() {
|
|
5
|
+
try {
|
|
6
|
+
let e = sessionStorage.getItem(n);
|
|
7
|
+
if (e) return e;
|
|
8
|
+
let t = r();
|
|
9
|
+
return sessionStorage.setItem(n, t), t;
|
|
10
|
+
} catch {
|
|
11
|
+
return i ??= r();
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
var o = class {
|
|
15
|
+
discovery;
|
|
16
|
+
signals = [];
|
|
17
|
+
exposures = [];
|
|
18
|
+
timer;
|
|
19
|
+
off = !1;
|
|
20
|
+
session;
|
|
21
|
+
delay;
|
|
22
|
+
constructor(e, t = {}) {
|
|
23
|
+
this.discovery = e, this.session = t.session ?? a, this.delay = t.delay ?? 2e3, typeof addEventListener == "function" && (addEventListener("pagehide", () => void this.flush(!0)), addEventListener("visibilitychange", () => {
|
|
24
|
+
typeof document < "u" && document.visibilityState === "hidden" && this.flush(!0);
|
|
25
|
+
}));
|
|
26
|
+
}
|
|
27
|
+
click(e, t = {}) {
|
|
28
|
+
this.signal({
|
|
29
|
+
content_id: e,
|
|
30
|
+
type: "click",
|
|
31
|
+
event_id: r(),
|
|
32
|
+
occurred_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
33
|
+
...t
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
view(e, t, n = {}) {
|
|
37
|
+
let i = r(), a = 0;
|
|
38
|
+
return { update: (r) => this.signal({
|
|
39
|
+
content_id: e,
|
|
40
|
+
version_id: t,
|
|
41
|
+
type: "view",
|
|
42
|
+
event_id: i,
|
|
43
|
+
revision: ++a,
|
|
44
|
+
occurred_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
45
|
+
...n,
|
|
46
|
+
...r
|
|
47
|
+
}) };
|
|
48
|
+
}
|
|
49
|
+
exposure(e) {
|
|
50
|
+
!this.off && e.shown.length && (this.exposures.push(e), this.schedule());
|
|
51
|
+
}
|
|
52
|
+
async flush(n = !1) {
|
|
53
|
+
clearTimeout(this.timer), this.timer = void 0;
|
|
54
|
+
let r = this.signals.splice(0), i = this.exposures.splice(0);
|
|
55
|
+
if (this.off) return;
|
|
56
|
+
let a = this.session(), o = [];
|
|
57
|
+
for (let e = 0; e < r.length; e += t) o.push(this.discovery.signals(r.slice(e, e + t), a, { keepalive: n }));
|
|
58
|
+
for (let e = 0; e < i.length; e += t) o.push(this.discovery.exposures(i.slice(e, e + t), a, { keepalive: n }));
|
|
59
|
+
(await Promise.allSettled(o)).some((t) => t.status === "rejected" && e(t.reason).code === "not_configured") && (this.off = !0);
|
|
60
|
+
}
|
|
61
|
+
signal(e) {
|
|
62
|
+
this.off || (e.type === "view" && (this.signals = this.signals.filter((t) => t.event_id !== e.event_id)), this.signals.push(e), this.schedule());
|
|
63
|
+
}
|
|
64
|
+
schedule() {
|
|
65
|
+
if (this.signals.length + this.exposures.length >= t) return void this.flush();
|
|
66
|
+
this.timer ??= setTimeout(() => void this.flush(), this.delay);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
//#endregion
|
|
70
|
+
export { o as Beacons, r as eventId, a as readerSession };
|
|
71
|
+
|
|
72
|
+
//# sourceMappingURL=beacons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beacons.js","names":[],"sources":["../../src/client/beacons.ts"],"sourcesContent":["import type { DiscoveryClient } from \"./discovery.js\";\nimport { toContentKitError } from \"./errors.js\";\nimport type { ExposureInput, SignalInput } from \"./generated/wire.js\";\n\nexport interface BeaconOptions {\n /** A signed-out visitor's session; default one per browser tab. */\n session?: () => string | undefined;\n /** How long events gather before they are sent, ms. Default 2000. */\n delay?: number;\n}\n\n/** Where a click or a view came from: the list render it was shown in. */\nexport interface Attribution {\n render_id?: string;\n surface?: string;\n /** 1-based position in that render. */\n position?: number;\n}\n\nexport interface ViewSession {\n /** Reports the view so far: pages read, seconds watched or percent scrolled; resume is where to pick up. */\n update(o: { progress?: number; duration_s?: number; resume?: string }): void;\n}\n\nconst MAX = 100;\nconst SESSION_KEY = \"contentkit.session\";\nexport const eventId = () => (typeof crypto !== \"undefined\" && \"randomUUID\" in crypto ? crypto.randomUUID() : `${Date.now().toString(36)}-${Math.random().toString(36).slice(2)}`);\n\nlet unstored: string | undefined;\n\n/** A signed-out reader's session: one per browser tab, kept across reloads. */\nexport function readerSession(): string {\n try {\n const kept = sessionStorage.getItem(SESSION_KEY);\n if (kept) return kept;\n const made = eventId();\n sessionStorage.setItem(SESSION_KEY, made);\n return made;\n } catch {\n return (unstored ??= eventId());\n }\n}\n\n/**\n * Batched, best-effort signals and exposures: gathered for `delay`, sent in\n * one request each, flushed with keepalive when the page hides. A site\n * without the signal plane (not_configured) turns them off.\n */\nexport class Beacons {\n private signals: SignalInput[] = [];\n private exposures: ExposureInput[] = [];\n private timer: ReturnType<typeof setTimeout> | undefined;\n private off = false;\n private readonly session: () => string | undefined;\n private readonly delay: number;\n\n constructor(\n private readonly discovery: DiscoveryClient,\n o: BeaconOptions = {},\n ) {\n this.session = o.session ?? readerSession;\n this.delay = o.delay ?? 2000;\n if (typeof addEventListener === \"function\") {\n addEventListener(\"pagehide\", () => void this.flush(true));\n addEventListener(\"visibilitychange\", () => {\n if (typeof document !== \"undefined\" && document.visibilityState === \"hidden\") void this.flush(true);\n });\n }\n }\n\n /** A click on a listed card. */\n click(content: string, a: Attribution & { version_id?: string } = {}): void {\n this.signal({ content_id: content, type: \"click\", event_id: eventId(), occurred_at: new Date().toISOString(), ...a });\n }\n\n /** A consumption session of a content (or one version): each update a revision of one event. */\n view(content: string, version?: string, a: Attribution = {}): ViewSession {\n const event = eventId();\n let revision = 0;\n return {\n update: (o) => this.signal({ content_id: content, version_id: version, type: \"view\", event_id: event, revision: ++revision, occurred_at: new Date().toISOString(), ...a, ...o }),\n };\n }\n\n /** A result list served, rendered or shown. */\n exposure(e: ExposureInput): void {\n if (this.off || !e.shown.length) return;\n this.exposures.push(e);\n this.schedule();\n }\n\n /** Sends what has gathered now. */\n async flush(keepalive = false): Promise<void> {\n clearTimeout(this.timer);\n this.timer = undefined;\n const signals = this.signals.splice(0);\n const exposures = this.exposures.splice(0);\n if (this.off) return;\n const session = this.session();\n const sends: Promise<void>[] = [];\n for (let i = 0; i < signals.length; i += MAX) sends.push(this.discovery.signals(signals.slice(i, i + MAX), session, { keepalive }));\n for (let i = 0; i < exposures.length; i += MAX) sends.push(this.discovery.exposures(exposures.slice(i, i + MAX), session, { keepalive }));\n const done = await Promise.allSettled(sends);\n if (done.some((r) => r.status === \"rejected\" && toContentKitError(r.reason).code === \"not_configured\")) this.off = true;\n }\n\n private signal(s: SignalInput): void {\n if (this.off) return;\n // A view's later revision replaces its earlier one still waiting.\n if (s.type === \"view\") this.signals = this.signals.filter((x) => x.event_id !== s.event_id);\n this.signals.push(s);\n this.schedule();\n }\n\n private schedule(): void {\n if (this.signals.length + this.exposures.length >= MAX) return void this.flush();\n this.timer ??= setTimeout(() => void this.flush(), this.delay);\n }\n}\n"],"mappings":";;AAwBA,IAAM,IAAM,KACN,IAAc,sBACP,UAAiB,OAAO,SAAW,OAAe,gBAAgB,SAAS,OAAO,WAAW,IAAI,GAAG,KAAK,IAAI,CAAC,CAAC,SAAS,EAAE,EAAE,GAAG,KAAK,OAAO,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,KAE1K;AAGJ,SAAgB,IAAwB;CACtC,IAAI;EACF,IAAM,IAAO,eAAe,QAAQ,CAAW;EAC/C,IAAI,GAAM,OAAO;EACjB,IAAM,IAAO,EAAQ;EAErB,OADA,eAAe,QAAQ,GAAa,CAAI,GACjC;CACT,QAAQ;EACN,OAAQ,MAAa,EAAQ;CAC/B;AACF;AAOA,IAAa,IAAb,MAAqB;CASA;CARnB,UAAiC,CAAC;CAClC,YAAqC,CAAC;CACtC;CACA,MAAc;CACd;CACA;CAEA,YACE,GACA,IAAmB,CAAC,GACpB;EAGA,AALiB,KAAA,YAAA,GAGjB,KAAK,UAAU,EAAE,WAAW,GAC5B,KAAK,QAAQ,EAAE,SAAS,KACpB,OAAO,oBAAqB,eAC9B,iBAAiB,kBAAkB,KAAK,KAAK,MAAM,EAAI,CAAC,GACxD,iBAAiB,0BAA0B;GACzC,AAAI,OAAO,WAAa,OAAe,SAAS,oBAAoB,YAAU,KAAU,MAAM,EAAI;EACpG,CAAC;CAEL;CAGA,MAAM,GAAiB,IAA2C,CAAC,GAAS;EAC1E,KAAK,OAAO;GAAE,YAAY;GAAS,MAAM;GAAS,UAAU,EAAQ;GAAG,8BAAa,IAAI,KAAK,EAAA,CAAE,YAAY;GAAG,GAAG;EAAE,CAAC;CACtH;CAGA,KAAK,GAAiB,GAAkB,IAAiB,CAAC,GAAgB;EACxE,IAAM,IAAQ,EAAQ,GAClB,IAAW;EACf,OAAO,EACL,SAAS,MAAM,KAAK,OAAO;GAAE,YAAY;GAAS,YAAY;GAAS,MAAM;GAAQ,UAAU;GAAO,UAAU,EAAE;GAAU,8BAAa,IAAI,KAAK,EAAA,CAAE,YAAY;GAAG,GAAG;GAAG,GAAG;EAAE,CAAC,EACjL;CACF;CAGA,SAAS,GAAwB;EAC3B,MAAK,OAAQ,EAAE,MAAM,WACzB,KAAK,UAAU,KAAK,CAAC,GACrB,KAAK,SAAS;CAChB;CAGA,MAAM,MAAM,IAAY,IAAsB;EAE5C,AADA,aAAa,KAAK,KAAK,GACvB,KAAK,QAAQ,KAAA;EACb,IAAM,IAAU,KAAK,QAAQ,OAAO,CAAC,GAC/B,IAAY,KAAK,UAAU,OAAO,CAAC;EACzC,IAAI,KAAK,KAAK;EACd,IAAM,IAAU,KAAK,QAAQ,GACvB,IAAyB,CAAC;EAChC,KAAK,IAAI,IAAI,GAAG,IAAI,EAAQ,QAAQ,KAAK,GAAK,EAAM,KAAK,KAAK,UAAU,QAAQ,EAAQ,MAAM,GAAG,IAAI,CAAG,GAAG,GAAS,EAAE,aAAU,CAAC,CAAC;EAClI,KAAK,IAAI,IAAI,GAAG,IAAI,EAAU,QAAQ,KAAK,GAAK,EAAM,KAAK,KAAK,UAAU,UAAU,EAAU,MAAM,GAAG,IAAI,CAAG,GAAG,GAAS,EAAE,aAAU,CAAC,CAAC;EAExI,CAAI,MADe,QAAQ,WAAW,CAAK,EAAA,CAClC,MAAM,MAAM,EAAE,WAAW,cAAc,EAAkB,EAAE,MAAM,CAAC,CAAC,SAAS,gBAAgB,MAAG,KAAK,MAAM;CACrH;CAEA,OAAe,GAAsB;EAC/B,KAAK,QAEL,EAAE,SAAS,WAAQ,KAAK,UAAU,KAAK,QAAQ,QAAQ,MAAM,EAAE,aAAa,EAAE,QAAQ,IAC1F,KAAK,QAAQ,KAAK,CAAC,GACnB,KAAK,SAAS;CAChB;CAEA,WAAyB;EACvB,IAAI,KAAK,QAAQ,SAAS,KAAK,UAAU,UAAU,GAAK,OAAO,KAAK,KAAK,MAAM;EAC/E,KAAK,UAAU,iBAAiB,KAAK,KAAK,MAAM,GAAG,KAAK,KAAK;CAC/D;AACF"}
|
package/dist/client/catalog.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Totals } from './generated/wire.js';
|
|
2
2
|
import { Http } from './http.js';
|
|
3
|
-
/** GET /catalog/totals filters: kinds to total (every
|
|
3
|
+
/** GET /catalog/totals filters: kinds to total (every kind when empty), languages to break them down by (every counted one when empty). */
|
|
4
4
|
export interface CatalogTotalsQuery {
|
|
5
5
|
kinds?: readonly string[];
|
|
6
6
|
languages?: readonly string[];
|
|
@@ -9,6 +9,6 @@ export interface CatalogTotalsQuery {
|
|
|
9
9
|
export declare class CatalogClient {
|
|
10
10
|
private readonly http;
|
|
11
11
|
constructor(http: Http);
|
|
12
|
-
/**
|
|
12
|
+
/** Content items per kind, in all and per language: how many anyone's listing shows and opens, and how many each tier's holders open. */
|
|
13
13
|
totals(q?: CatalogTotalsQuery, signal?: AbortSignal): Promise<Totals>;
|
|
14
14
|
}
|
package/dist/client/catalog.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"catalog.js","names":[],"sources":["../../src/client/catalog.ts"],"sourcesContent":["import type { Totals } from \"./generated/wire.js\";\nimport type { Http } from \"./http.js\";\nimport { call } from \"./route.js\";\n\n/** GET /catalog/totals filters: kinds to total (every
|
|
1
|
+
{"version":3,"file":"catalog.js","names":[],"sources":["../../src/client/catalog.ts"],"sourcesContent":["import type { Totals } from \"./generated/wire.js\";\nimport type { Http } from \"./http.js\";\nimport { call } from \"./route.js\";\n\n/** GET /catalog/totals filters: kinds to total (every kind when empty), languages to break them down by (every counted one when empty). */\nexport interface CatalogTotalsQuery {\n kinds?: readonly string[];\n languages?: readonly string[];\n}\n\n/** The public catalog. */\nexport class CatalogClient {\n constructor(private readonly http: Http) {}\n\n /** Content items per kind, in all and per language: how many anyone's listing shows and opens, and how many each tier's holders open. */\n totals(q: CatalogTotalsQuery = {}, signal?: AbortSignal): Promise<Totals> {\n return call(this.http, \"GET\", \"/catalog/totals\", { query: { kinds: q.kinds?.join(\",\"), languages: q.languages?.join(\",\") }, signal });\n }\n}\n"],"mappings":";;AAWA,IAAa,IAAb,MAA2B;CACI;CAA7B,YAAY,GAA6B;EAAZ,KAAA,OAAA;CAAa;CAG1C,OAAO,IAAwB,CAAC,GAAG,GAAuC;EACxE,OAAO,EAAK,KAAK,MAAM,OAAO,mBAAmB;GAAE,OAAO;IAAE,OAAO,EAAE,OAAO,KAAK,GAAG;IAAG,WAAW,EAAE,WAAW,KAAK,GAAG;GAAE;GAAG;EAAO,CAAC;CACtI;AACF"}
|
package/dist/client/client.d.ts
CHANGED
|
@@ -1,21 +1,24 @@
|
|
|
1
1
|
import { CatalogClient } from './catalog.js';
|
|
2
2
|
import { CodesClient } from './codes.js';
|
|
3
|
+
import { ContentsClient } from './contents.js';
|
|
3
4
|
import { BansClient } from './content/bans.js';
|
|
4
5
|
import { CommentsClient } from './content/comments.js';
|
|
5
6
|
import { FavoritesClient } from './content/favorites.js';
|
|
6
7
|
import { ModerationClient } from './content/moderation.js';
|
|
7
8
|
import { PollsClient } from './content/polls.js';
|
|
8
|
-
import { PostsClient } from './content/posts.js';
|
|
9
9
|
import { ReactionsClient } from './content/reactions.js';
|
|
10
|
-
import { Config, RefBody } from './generated/wire.js';
|
|
10
|
+
import { Batch, Config, ContentModel, RefBody, Result } from './generated/wire.js';
|
|
11
|
+
import { DiscoveryClient } from './discovery.js';
|
|
12
|
+
import { GroupsClient } from './groups.js';
|
|
13
|
+
import { OffersClient } from './offers.js';
|
|
14
|
+
import { VersionsClient } from './versions.js';
|
|
11
15
|
import { ContentKitChange, ContentKitModule, HttpOptions } from './http.js';
|
|
12
16
|
import { MediaClient, ContentFolders, MediaOptions } from './media/client.js';
|
|
13
17
|
import { NotificationsClient } from './notifications.js';
|
|
14
|
-
import { TaxonomyClient } from './taxonomy.js';
|
|
15
18
|
export interface ContentKitClientOptions extends HttpOptions {
|
|
16
19
|
/** Upload tuning (transport, part concurrency, retries). */
|
|
17
20
|
media?: MediaOptions;
|
|
18
|
-
/** The media
|
|
21
|
+
/** The media kind of poll folders, when the host renamed it (content.Media). */
|
|
19
22
|
folders?: ContentFolders;
|
|
20
23
|
}
|
|
21
24
|
/**
|
|
@@ -25,8 +28,10 @@ export interface ContentKitClientOptions extends HttpOptions {
|
|
|
25
28
|
export interface ContentKitClient {
|
|
26
29
|
/** Uploads, multipart, commits, reads, frames, HLS bases, hls.js `xhrSetup` and inline images. */
|
|
27
30
|
readonly media: MediaClient;
|
|
28
|
-
/**
|
|
29
|
-
readonly
|
|
31
|
+
/** Content items: reads, and writes for their creators, owner-group editors and staff. */
|
|
32
|
+
readonly contents: ContentsClient;
|
|
33
|
+
/** The catalog's totals by kind, language and audience. */
|
|
34
|
+
readonly catalog: CatalogClient;
|
|
30
35
|
/** Threads, replies, edits, tombstones, reactions, standing, the latest feed, moderation. */
|
|
31
36
|
readonly comments: CommentsClient;
|
|
32
37
|
/** Likes and dislikes of an item. */
|
|
@@ -37,18 +42,26 @@ export interface ContentKitClient {
|
|
|
37
42
|
readonly polls: PollsClient;
|
|
38
43
|
/** Comment bans, owner and global. */
|
|
39
44
|
readonly bans: BansClient;
|
|
40
|
-
/** The review queue of held comments and
|
|
45
|
+
/** The review queue of held comments and content. */
|
|
41
46
|
readonly moderation: ModerationClient;
|
|
42
|
-
/**
|
|
43
|
-
readonly
|
|
47
|
+
/** Groups: listings, pages, staff writes and memberships. */
|
|
48
|
+
readonly groups: GroupsClient;
|
|
49
|
+
/** Lists, search, typeahead, rails, release dates, content filters, history, signals and exposures. */
|
|
50
|
+
readonly discovery: DiscoveryClient;
|
|
51
|
+
/** Content versions: reader plans, reader metadata, forks and downloads. */
|
|
52
|
+
readonly versions: VersionsClient;
|
|
53
|
+
/** Offers on contents, versions and groups; group joins; the reader's library. */
|
|
54
|
+
readonly offers: OffersClient;
|
|
44
55
|
/** Content-code lookup. */
|
|
45
56
|
readonly codes: CodesClient;
|
|
46
|
-
/** The public catalog: listing totals by kind and audience. */
|
|
47
|
-
readonly catalog: CatalogClient;
|
|
48
57
|
/** The signed-in person's native and imported notifications. */
|
|
49
58
|
readonly notifications: NotificationsClient;
|
|
50
59
|
/** What the content module allows: which interactions signed-out visitors may make. */
|
|
51
60
|
config(signal?: AbortSignal): Promise<Config>;
|
|
61
|
+
/** The site's content model: languages, tiers, kinds, group kinds and content filters. */
|
|
62
|
+
kinds(signal?: AbortSignal): Promise<ContentModel>;
|
|
63
|
+
/** Staff bulk import (root:import:write): groups, contents, memberships, offers and aliases, idempotent per source. */
|
|
64
|
+
import(batch: Batch): Promise<Result>;
|
|
52
65
|
/** A module's base URL as configured (no trailing slash). */
|
|
53
66
|
url(module: ContentKitModule, ref?: RefBody): string;
|
|
54
67
|
/** Cache context only, not authentication. The React provider keeps this in sync. */
|
package/dist/client/client.js
CHANGED
|
@@ -2,39 +2,47 @@ import { call as e } from "./route.js";
|
|
|
2
2
|
import { MediaClient as t } from "./media/client.js";
|
|
3
3
|
import { CatalogClient as n } from "./catalog.js";
|
|
4
4
|
import { CodesClient as r } from "./codes.js";
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
5
|
+
import { ContentsClient as i } from "./contents.js";
|
|
6
|
+
import { BansClient as a } from "./content/bans.js";
|
|
7
|
+
import { CommentsClient as o } from "./content/comments.js";
|
|
8
|
+
import { DiscoveryClient as s } from "./discovery.js";
|
|
9
|
+
import { FavoritesClient as c } from "./content/favorites.js";
|
|
10
|
+
import { ModerationClient as l } from "./content/moderation.js";
|
|
11
|
+
import { PollsClient as u } from "./content/polls.js";
|
|
12
|
+
import { ReactionsClient as d } from "./content/reactions.js";
|
|
13
|
+
import { GroupsClient as f } from "./groups.js";
|
|
14
|
+
import { OffersClient as p } from "./offers.js";
|
|
15
|
+
import { VersionsClient as m } from "./versions.js";
|
|
16
|
+
import { Http as h } from "./http.js";
|
|
17
|
+
import { NotificationsClient as g } from "./notifications.js";
|
|
15
18
|
//#region src/client/client.ts
|
|
16
|
-
function
|
|
17
|
-
let { media:
|
|
19
|
+
function _(_) {
|
|
20
|
+
let { media: v, folders: y, ...b } = _, x = new h(b), S = new t(x, v, y);
|
|
18
21
|
return {
|
|
19
|
-
media:
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
22
|
+
media: S,
|
|
23
|
+
contents: new i(x),
|
|
24
|
+
catalog: new n(x),
|
|
25
|
+
comments: new o(x),
|
|
26
|
+
reactions: new d(x),
|
|
27
|
+
favorites: new c(x),
|
|
28
|
+
polls: new u(x, S),
|
|
29
|
+
bans: new a(x),
|
|
30
|
+
moderation: new l(x),
|
|
31
|
+
groups: new f(x, S),
|
|
32
|
+
discovery: new s(x),
|
|
33
|
+
versions: new m(x),
|
|
34
|
+
offers: new p(x),
|
|
35
|
+
codes: new r(x),
|
|
36
|
+
notifications: new g(x),
|
|
37
|
+
config: (t) => e(x, "GET", "/config", { signal: t }),
|
|
38
|
+
kinds: (t) => e(x, "GET", "/kinds", { signal: t }),
|
|
39
|
+
import: (t) => e(x, "POST", "/import", { body: t }),
|
|
40
|
+
url: (e, t) => x.mount(e, t),
|
|
41
|
+
setReadScope: (e) => x.setReadScope(e),
|
|
42
|
+
subscribe: (e) => x.subscribe(e)
|
|
35
43
|
};
|
|
36
44
|
}
|
|
37
45
|
//#endregion
|
|
38
|
-
export {
|
|
46
|
+
export { _ as createContentKitClient };
|
|
39
47
|
|
|
40
48
|
//# sourceMappingURL=client.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":[],"sources":["../../src/client/client.ts"],"sourcesContent":["import { CatalogClient } from \"./catalog.js\";\nimport { CodesClient } from \"./codes.js\";\nimport { BansClient } from \"./content/bans.js\";\nimport { CommentsClient } from \"./content/comments.js\";\nimport { FavoritesClient } from \"./content/favorites.js\";\nimport { ModerationClient } from \"./content/moderation.js\";\nimport { PollsClient } from \"./content/polls.js\";\nimport {
|
|
1
|
+
{"version":3,"file":"client.js","names":[],"sources":["../../src/client/client.ts"],"sourcesContent":["import { CatalogClient } from \"./catalog.js\";\nimport { CodesClient } from \"./codes.js\";\nimport { ContentsClient } from \"./contents.js\";\nimport { BansClient } from \"./content/bans.js\";\nimport { CommentsClient } from \"./content/comments.js\";\nimport { FavoritesClient } from \"./content/favorites.js\";\nimport { ModerationClient } from \"./content/moderation.js\";\nimport { PollsClient } from \"./content/polls.js\";\nimport { ReactionsClient } from \"./content/reactions.js\";\nimport type { Batch, Config, ContentModel, RefBody, Result } from \"./generated/wire.js\";\nimport { DiscoveryClient } from \"./discovery.js\";\nimport { GroupsClient } from \"./groups.js\";\nimport { OffersClient } from \"./offers.js\";\nimport { VersionsClient } from \"./versions.js\";\nimport { Http, type ContentKitChange, type ContentKitModule, type HttpOptions } from \"./http.js\";\nimport { MediaClient, type ContentFolders, type MediaOptions } from \"./media/client.js\";\nimport { call } from \"./route.js\";\nimport { NotificationsClient } from \"./notifications.js\";\n\nexport interface ContentKitClientOptions extends HttpOptions {\n /** Upload tuning (transport, part concurrency, retries). */\n media?: MediaOptions;\n /** The media kind of poll folders, when the host renamed it (content.Media). */\n folders?: ContentFolders;\n}\n\n/**\n * One ContentKit deployment as the browser sees it. Each module is a property\n * over one shared transport (mounts, auth, language, errors, change events).\n */\nexport interface ContentKitClient {\n /** Uploads, multipart, commits, reads, frames, HLS bases, hls.js `xhrSetup` and inline images. */\n readonly media: MediaClient;\n /** Content items: reads, and writes for their creators, owner-group editors and staff. */\n readonly contents: ContentsClient;\n /** The catalog's totals by kind, language and audience. */\n readonly catalog: CatalogClient;\n /** Threads, replies, edits, tombstones, reactions, standing, the latest feed, moderation. */\n readonly comments: CommentsClient;\n /** Likes and dislikes of an item. */\n readonly reactions: ReactionsClient;\n /** The signed-in caller's favorites. */\n readonly favorites: FavoritesClient;\n /** Polls: votes, free-text answers and the staff editor. */\n readonly polls: PollsClient;\n /** Comment bans, owner and global. */\n readonly bans: BansClient;\n /** The review queue of held comments and content. */\n readonly moderation: ModerationClient;\n /** Groups: listings, pages, staff writes and memberships. */\n readonly groups: GroupsClient;\n /** Lists, search, typeahead, rails, release dates, content filters, history, signals and exposures. */\n readonly discovery: DiscoveryClient;\n /** Content versions: reader plans, reader metadata, forks and downloads. */\n readonly versions: VersionsClient;\n /** Offers on contents, versions and groups; group joins; the reader's library. */\n readonly offers: OffersClient;\n /** Content-code lookup. */\n readonly codes: CodesClient;\n /** The signed-in person's native and imported notifications. */\n readonly notifications: NotificationsClient;\n\n /** What the content module allows: which interactions signed-out visitors may make. */\n config(signal?: AbortSignal): Promise<Config>;\n /** The site's content model: languages, tiers, kinds, group kinds and content filters. */\n kinds(signal?: AbortSignal): Promise<ContentModel>;\n /** Staff bulk import (root:import:write): groups, contents, memberships, offers and aliases, idempotent per source. */\n import(batch: Batch): Promise<Result>;\n /** A module's base URL as configured (no trailing slash). */\n url(module: ContentKitModule, ref?: RefBody): string;\n /** Cache context only, not authentication. The React provider keeps this in sync. */\n setReadScope(scope: string): void;\n /** Every successful mutation; a null scope means its data predates a context change. */\n subscribe(listener: (change: ContentKitChange, scope: string | null) => void): () => void;\n}\n\nexport function createContentKitClient(options: ContentKitClientOptions): ContentKitClient {\n const { media: mediaOptions, folders, ...http } = options;\n const h = new Http(http);\n const media = new MediaClient(h, mediaOptions, folders);\n return {\n media,\n contents: new ContentsClient(h),\n catalog: new CatalogClient(h),\n comments: new CommentsClient(h),\n reactions: new ReactionsClient(h),\n favorites: new FavoritesClient(h),\n polls: new PollsClient(h, media),\n bans: new BansClient(h),\n moderation: new ModerationClient(h),\n groups: new GroupsClient(h, media),\n discovery: new DiscoveryClient(h),\n versions: new VersionsClient(h),\n offers: new OffersClient(h),\n codes: new CodesClient(h),\n notifications: new NotificationsClient(h),\n config: (signal) => call(h, \"GET\", \"/config\", { signal }),\n kinds: (signal) => call(h, \"GET\", \"/kinds\", { signal }),\n import: (batch) => call(h, \"POST\", \"/import\", { body: batch }),\n url: (module, ref) => h.mount(module, ref),\n setReadScope: (scope) => h.setReadScope(scope),\n subscribe: (listener) => h.subscribe(listener),\n };\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;AA4EA,SAAgB,EAAuB,GAAoD;CACzF,IAAM,EAAE,OAAO,GAAc,YAAS,GAAG,MAAS,GAC5C,IAAI,IAAI,EAAK,CAAI,GACjB,IAAQ,IAAI,EAAY,GAAG,GAAc,CAAO;CACtD,OAAO;EACL;EACA,UAAU,IAAI,EAAe,CAAC;EAC9B,SAAS,IAAI,EAAc,CAAC;EAC5B,UAAU,IAAI,EAAe,CAAC;EAC9B,WAAW,IAAI,EAAgB,CAAC;EAChC,WAAW,IAAI,EAAgB,CAAC;EAChC,OAAO,IAAI,EAAY,GAAG,CAAK;EAC/B,MAAM,IAAI,EAAW,CAAC;EACtB,YAAY,IAAI,EAAiB,CAAC;EAClC,QAAQ,IAAI,EAAa,GAAG,CAAK;EACjC,WAAW,IAAI,EAAgB,CAAC;EAChC,UAAU,IAAI,EAAe,CAAC;EAC9B,QAAQ,IAAI,EAAa,CAAC;EAC1B,OAAO,IAAI,EAAY,CAAC;EACxB,eAAe,IAAI,EAAoB,CAAC;EACxC,SAAS,MAAW,EAAK,GAAG,OAAO,WAAW,EAAE,UAAO,CAAC;EACxD,QAAQ,MAAW,EAAK,GAAG,OAAO,UAAU,EAAE,UAAO,CAAC;EACtD,SAAS,MAAU,EAAK,GAAG,QAAQ,WAAW,EAAE,MAAM,EAAM,CAAC;EAC7D,MAAM,GAAQ,MAAQ,EAAE,MAAM,GAAQ,CAAG;EACzC,eAAe,MAAU,EAAE,aAAa,CAAK;EAC7C,YAAY,MAAa,EAAE,UAAU,CAAQ;CAC/C;AACF"}
|