@openrails/contentkit-ui 0.71.0 → 0.72.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 +98 -10
- package/dist/client/content/bans.d.ts +2 -0
- package/dist/client/content/bans.js +24 -12
- package/dist/client/content/bans.js.map +1 -1
- package/dist/client/content/comments.d.ts +2 -0
- package/dist/client/content/comments.js.map +1 -1
- package/dist/client/content/polls.d.ts +9 -2
- package/dist/client/content/polls.js.map +1 -1
- package/dist/client/generated/routes.d.ts +28 -2
- package/dist/client/generated/routes.js +40 -0
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +4 -0
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/index.d.ts +2 -2
- package/dist/client/taxonomy.d.ts +5 -1
- package/dist/client/taxonomy.js +7 -0
- package/dist/client/taxonomy.js.map +1 -1
- package/dist/components/admin/poll-manager.d.ts +28 -0
- package/dist/components/admin/poll-manager.js +297 -0
- package/dist/components/admin/poll-manager.js.map +1 -0
- package/dist/components/admin/post-manager.d.ts +45 -0
- package/dist/components/admin/post-manager.js +602 -0
- package/dist/components/admin/post-manager.js.map +1 -0
- package/dist/components/admin/shell.d.ts +73 -0
- package/dist/components/admin/shell.js +148 -0
- package/dist/components/admin/shell.js.map +1 -0
- package/dist/components/admin/taxonomy-manager.d.ts +54 -0
- package/dist/components/admin/taxonomy-manager.js +976 -0
- package/dist/components/admin/taxonomy-manager.js.map +1 -0
- package/dist/components/admin/user-comment-standing.d.ts +25 -0
- package/dist/components/admin/user-comment-standing.js +229 -0
- package/dist/components/admin/user-comment-standing.js.map +1 -0
- package/dist/components/social/bans.d.ts +5 -2
- package/dist/components/social/bans.js +132 -134
- package/dist/components/social/bans.js.map +1 -1
- package/dist/components/social/index.d.ts +1 -1
- package/dist/components/social/moderation.d.ts +11 -13
- package/dist/components/social/moderation.js +299 -218
- package/dist/components/social/moderation.js.map +1 -1
- package/dist/components/social/parts.d.ts +3 -2
- package/dist/components/social/parts.js +74 -48
- package/dist/components/social/parts.js.map +1 -1
- package/dist/components/social/poll-editor.js +1 -0
- package/dist/components/social/poll-editor.js.map +1 -1
- package/dist/editor/index.d.ts +1 -0
- package/dist/editor/rich-text-editor.d.ts +13 -0
- package/dist/editor/rich-text-editor.js +228 -0
- package/dist/editor/rich-text-editor.js.map +1 -0
- package/dist/editor.js +2 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +13 -8
- package/dist/locales/admin/de.d.ts +2 -0
- package/dist/locales/admin/de.js +176 -0
- package/dist/locales/admin/de.js.map +1 -0
- package/dist/locales/admin/en.d.ts +171 -0
- package/dist/locales/admin/en.js +176 -0
- package/dist/locales/admin/en.js.map +1 -0
- package/dist/locales/admin/es.d.ts +2 -0
- package/dist/locales/admin/es.js +176 -0
- package/dist/locales/admin/es.js.map +1 -0
- package/dist/locales/admin/ja.d.ts +2 -0
- package/dist/locales/admin/ja.js +176 -0
- package/dist/locales/admin/ja.js.map +1 -0
- package/dist/locales/admin/ko.d.ts +2 -0
- package/dist/locales/admin/ko.js +176 -0
- package/dist/locales/admin/ko.js.map +1 -0
- package/dist/locales/admin/zh.d.ts +2 -0
- package/dist/locales/admin/zh.js +176 -0
- package/dist/locales/admin/zh.js.map +1 -0
- package/dist/locales/de.js +5 -3
- package/dist/locales/de.js.map +1 -1
- package/dist/locales/en.d.ts +176 -0
- package/dist/locales/en.js +5 -3
- package/dist/locales/en.js.map +1 -1
- package/dist/locales/es.js +5 -3
- package/dist/locales/es.js.map +1 -1
- package/dist/locales/ja.js +5 -3
- package/dist/locales/ja.js.map +1 -1
- package/dist/locales/ko.js +5 -3
- package/dist/locales/ko.js.map +1 -1
- package/dist/locales/social/de.js +8 -1
- package/dist/locales/social/de.js.map +1 -1
- package/dist/locales/social/en.d.ts +7 -0
- package/dist/locales/social/en.js +8 -1
- package/dist/locales/social/en.js.map +1 -1
- package/dist/locales/social/es.js +8 -1
- package/dist/locales/social/es.js.map +1 -1
- package/dist/locales/social/ja.js +8 -1
- package/dist/locales/social/ja.js.map +1 -1
- package/dist/locales/social/ko.js +8 -1
- package/dist/locales/social/ko.js.map +1 -1
- package/dist/locales/social/zh.js +8 -1
- package/dist/locales/social/zh.js.map +1 -1
- package/dist/locales/zh.js +5 -3
- package/dist/locales/zh.js.map +1 -1
- package/dist/provider.d.ts +2 -0
- package/dist/provider.js +23 -19
- package/dist/provider.js.map +1 -1
- package/dist/react/admin.d.ts +55 -0
- package/dist/react/admin.js +97 -0
- package/dist/react/admin.js.map +1 -0
- package/dist/react/comments.d.ts +18 -2
- package/dist/react/comments.js +24 -8
- package/dist/react/comments.js.map +1 -1
- package/dist/react/context.d.ts +7 -1
- package/dist/react/context.js +6 -1
- package/dist/react/context.js.map +1 -1
- package/dist/react/index.d.ts +4 -3
- package/dist/react/polls.js +88 -87
- package/dist/react/polls.js.map +1 -1
- package/dist/react/posts.js +123 -122
- package/dist/react/posts.js.map +1 -1
- package/dist/react/resources.js +3 -0
- package/dist/react/resources.js.map +1 -1
- package/dist/react/use-resource.d.ts +16 -0
- package/dist/react/use-resource.js +20 -1
- package/dist/react/use-resource.js.map +1 -1
- package/dist/react.js +21 -20
- package/dist/styles.css +1 -1
- package/package.json +37 -2
package/README.md
CHANGED
|
@@ -15,6 +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` (PostManager's body editor) | the optional peers `@tiptap/core`, `@tiptap/pm`, `@tiptap/react`, `@tiptap/starter-kit`, `@tiptap/extension-image`, `@tiptap/extensions` (3.31+) |
|
|
18
19
|
| `@openrails/contentkit-ui/locales/{de,es,ja,ko,zh}` | message bundles (English is built in) | |
|
|
19
20
|
| `@openrails/contentkit-ui/styles.css` | the stylesheet, scoped under `.ckui` (the root entry also installs it) | |
|
|
20
21
|
|
|
@@ -81,11 +82,12 @@ operation. This does not change the operation's result or its authentication.
|
|
|
81
82
|
`PUT` from the app's origin with `Content-Type` and `x-amz-checksum-sha256`.
|
|
82
83
|
- **Content modules**, one per resource, each method one route of the
|
|
83
84
|
generated route table with its generated types: `posts`, `comments`,
|
|
84
|
-
`reactions`, `favorites`, `polls`, `bans` (`"owner"` or `"global"`),
|
|
85
|
+
`reactions`, `favorites`, `polls`, `bans` (`"owner"` or `"global"`; `get("global", user)`),
|
|
85
86
|
`moderation`, `taxonomy`, `codes`. Lists take `limit`/`offset` (the review
|
|
86
87
|
queue a `cursor`); staff lists are `posts.adminList` (`q` searches,
|
|
87
|
-
`deleted: true` lists deleted posts for `posts.restore`), `polls.adminList`,
|
|
88
|
-
`comments.adminList
|
|
88
|
+
`deleted: true` lists deleted posts for `posts.restore`), `polls.adminList` (`state`, `q`),
|
|
89
|
+
`comments.adminList` (`contentKind`, `author`); `taxonomy.nodeAssignments(id)`
|
|
90
|
+
pages a node's contents.
|
|
89
91
|
- **Images of posts and polls** go to the item's server-named upload path:
|
|
90
92
|
`media.uploadNamed(ref, file)` resolves the name content routes take;
|
|
91
93
|
`media.uploadInline(postId, file)` resolves a body image's reference
|
|
@@ -159,8 +161,9 @@ const editor = usePost(postId);
|
|
|
159
161
|
Also `useContentConfig` (`client.config()`, read once), `useCommentReplies`,
|
|
160
162
|
`useCanComment` (may the caller comment, may signed-out visitors, the ban
|
|
161
163
|
that stops it, and what it may do to others' comments), `useLatestComments`,
|
|
162
|
-
`usePolls`, `usePosts` (staff: `admin`, `deleted`, `q`), `usePost` (with `restore`), and for staff `useAdminComments
|
|
163
|
-
`useModerationQueue`, `useCommentBans
|
|
164
|
+
`usePolls`, `usePosts` (staff: `admin`, `deleted`, `q`), `usePost` (with `restore`), and for staff `useAdminComments`
|
|
165
|
+
(`contentKind`, `author`), `useModerationQueue`, `useCommentBans`, `useGlobalCommentBan` (one user's), and
|
|
166
|
+
`useStaffAccess`, `useAdminLocation`, `useFlowClient` and `usePaged`, which the admin flows are built from.
|
|
164
167
|
|
|
165
168
|
Also: `useCrop`, `useVideoImages`, `useFrameStrip`, `useVideoFrame`,
|
|
166
169
|
`useVideoPoster`, `useEncodeProgress`, `useHlsPlayer`, `useCarousel`,
|
|
@@ -404,17 +407,102 @@ server allows it (`content.Options.Anonymous`, read from the comment standing
|
|
|
404
407
|
and `client.config()`); elsewhere they are asked to sign in (`onSignIn`, the
|
|
405
408
|
provider's or their own) or, without one, told to.
|
|
406
409
|
|
|
407
|
-
Staff: `
|
|
408
|
-
|
|
409
|
-
the caller's permissions allow and say so when a route refuses; the host
|
|
410
|
-
decides who sees them.
|
|
410
|
+
Staff building blocks: `CommentBans` (paged) with `CommentBanDialog`, and
|
|
411
|
+
`PollEditor` (deleting asks for a typed confirmation). The complete staff screens are the admin flows below.
|
|
411
412
|
|
|
412
413
|
```tsx
|
|
413
414
|
<Comments item={{ kind: "video", id }} count={video.comment_count} userHref={(u) => `/u/${u.username}`} />
|
|
414
415
|
<Poll language={lang} />
|
|
415
|
-
<CommentModeration contentKinds={["video", "post"]} itemHref={(i) => `/${i.kind}/${i.id}`} />
|
|
416
416
|
```
|
|
417
417
|
|
|
418
|
+
## Admin flows
|
|
419
|
+
|
|
420
|
+
Drop-in staff screens for a host's own admin area: each makes its own reads
|
|
421
|
+
and writes, shows loading, empty, error (with retry) and no-access states,
|
|
422
|
+
confirms destructive acts and shows only what the caller's permissions allow.
|
|
423
|
+
The host writes no API calls. Every flow takes:
|
|
424
|
+
|
|
425
|
+
| Prop | |
|
|
426
|
+
| --- | --- |
|
|
427
|
+
| `client`, or `baseUrl` + `auth` | the ContentKit client, or where ContentKit is mounted and auth-ui's `AuthClient` (anything with `authFetch`); else the provider's client |
|
|
428
|
+
| `basePath`, `navigation` | multi-view flows: views are paths under `basePath`, filters and pages its query; `navigation` is the host router (`{ pathname, search, navigate(to, { replace }) }`), else the history API; without `basePath`, views stay in memory |
|
|
429
|
+
| `guard` | runs every write (auth-ui's `useStepUpGuard()`) |
|
|
430
|
+
| `appearance`, `className` | theme `"inherit"` by default: the host's shadcn variables (`--background`, `--primary`, …) and `.dark` |
|
|
431
|
+
| `language`, `messages` | the UI language (its bundle loads) and overrides; default the provider's |
|
|
432
|
+
| `onError` | every failure the flow shows, for a toast or a log |
|
|
433
|
+
|
|
434
|
+
Each has an access hook (`use…Access`) for hiding its tab: per area, whether
|
|
435
|
+
the caller's permission admits it. `useConfirm()` is the flows' promise-based
|
|
436
|
+
confirmation (`typed` for acts that cannot be undone).
|
|
437
|
+
|
|
438
|
+
```tsx
|
|
439
|
+
const location = useLocation();
|
|
440
|
+
const navigate = useNavigate();
|
|
441
|
+
const nav = useMemo(() => ({ pathname: location.pathname, search: location.search, navigate }), [location, navigate]);
|
|
442
|
+
```
|
|
443
|
+
|
|
444
|
+
- **`CommentModeration`**: every comment (deleted, held and rejected ones with
|
|
445
|
+
their text) by content kind or author, to delete, restore or ban its author;
|
|
446
|
+
the review queue; the site's bans. Sections at `basePath`, `/queue`,
|
|
447
|
+
`/bans`; `?kind`, `?author`, `?page`. Props: `contentKinds`, `itemHref`,
|
|
448
|
+
`userHref`, `sections`, `pageSize`. `useCommentModerationAccess()`.
|
|
449
|
+
|
|
450
|
+
```tsx
|
|
451
|
+
<CommentModeration client={contentkit} basePath="/admin/comments" navigation={nav} contentKinds={["video", "post"]} />
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
- **`PollManager`**: every poll by language, month or day, state (live,
|
|
455
|
+
scheduled, closed, inactive) and question; create and edit through
|
|
456
|
+
`PollEditor` at `basePath/new` and `basePath/{id}`; delete with a typed
|
|
457
|
+
confirmation. Props: `languages`, `freeText`, `maxOptions`, `pageSize`.
|
|
458
|
+
`usePollManagerAccess()`.
|
|
459
|
+
|
|
460
|
+
```tsx
|
|
461
|
+
<PollManager client={contentkit} basePath="/admin/polls" navigation={nav} languages={["en", "ja"]} />
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
- **`PostManager`**: every post by language, draft state and text, deleted
|
|
465
|
+
ones to restore; title, slug, language, excerpt, schedule, cover and body
|
|
466
|
+
with inline images; draft or publish; the moderation state. Props:
|
|
467
|
+
`languages`, `renderEditor` (`richTextEditor` from `/editor`, or the
|
|
468
|
+
host's; a plain HTML field without it), `postHref`, `pageSize`.
|
|
469
|
+
`usePostManagerAccess()`.
|
|
470
|
+
|
|
471
|
+
```tsx
|
|
472
|
+
import { richTextEditor } from "@openrails/contentkit-ui/editor";
|
|
473
|
+
<PostManager client={contentkit} basePath="/admin/posts" navigation={nav} renderEditor={richTextEditor} />
|
|
474
|
+
```
|
|
475
|
+
|
|
476
|
+
`RichTextEditor` (`value`, `onChange`, `uploadImage`) is Tiptap: headings,
|
|
477
|
+
emphasis, lists, quotes, links and images picked, pasted or dropped. Its
|
|
478
|
+
HTML keeps to that schema, so bodies stay a small, predictable subset.
|
|
479
|
+
|
|
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
|
+
- **`UserCommentStanding`**: for a user page, the person's site-wide comment
|
|
498
|
+
ban (ban, replace, lift) and their recent comments (delete, restore). Props:
|
|
499
|
+
`user` (their id), `name`, `itemHref`, `pageSize`.
|
|
500
|
+
`useUserCommentStandingAccess()`.
|
|
501
|
+
|
|
502
|
+
```tsx
|
|
503
|
+
<UserCommentStanding client={contentkit} user={u.id} name={u.username} />
|
|
504
|
+
```
|
|
505
|
+
|
|
418
506
|
## Errors
|
|
419
507
|
|
|
420
508
|
Every call rejects with `ContentKitError`: `code` (the server's, or `network`,
|
|
@@ -8,6 +8,8 @@ export declare class BansClient {
|
|
|
8
8
|
constructor(http: Http);
|
|
9
9
|
/** The scope's bans, newest first, expired ones included. */
|
|
10
10
|
list(scope: BanScope, q?: PageQuery, signal?: AbortSignal): Promise<CommentBan[]>;
|
|
11
|
+
/** The user's site-wide ban, expired or not; null when they have none (root:comments:ban). */
|
|
12
|
+
get(scope: "global", user: string, signal?: AbortSignal): Promise<CommentBan | null>;
|
|
11
13
|
/** Bans user from commenting in the scope, replacing any ban there; no until lasts until lifted. */
|
|
12
14
|
ban(scope: BanScope, user: string, input?: BanInput): Promise<CommentBan>;
|
|
13
15
|
/** Lifts user's ban in the scope; idempotent. */
|
|
@@ -1,40 +1,52 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ContentKitError as e } from "../errors.js";
|
|
2
|
+
import { call as t } from "../route.js";
|
|
2
3
|
//#region src/client/content/bans.ts
|
|
3
|
-
var
|
|
4
|
+
var n = class {
|
|
4
5
|
http;
|
|
5
6
|
constructor(e) {
|
|
6
7
|
this.http = e;
|
|
7
8
|
}
|
|
8
|
-
list(
|
|
9
|
-
return
|
|
9
|
+
list(e, n = {}, r) {
|
|
10
|
+
return e === "global" ? t(this.http, "GET", "/global-comment-bans", {
|
|
10
11
|
query: n,
|
|
11
12
|
signal: r
|
|
12
|
-
}) :
|
|
13
|
+
}) : t(this.http, "GET", "/comment-bans", {
|
|
13
14
|
query: n,
|
|
14
15
|
signal: r
|
|
15
16
|
});
|
|
16
17
|
}
|
|
17
|
-
async
|
|
18
|
+
async get(n, r, i) {
|
|
19
|
+
try {
|
|
20
|
+
return await t(this.http, "GET", "/global-comment-bans/{user}", {
|
|
21
|
+
params: { user: r },
|
|
22
|
+
signal: i
|
|
23
|
+
});
|
|
24
|
+
} catch (t) {
|
|
25
|
+
if (t instanceof e && t.code === "not_found") return null;
|
|
26
|
+
throw t;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
async ban(e, n, r = {}) {
|
|
18
30
|
let i = this.http.captureChanges(), a = {
|
|
19
31
|
params: { user: n },
|
|
20
32
|
body: r
|
|
21
|
-
}, o = await (
|
|
33
|
+
}, o = await (e === "global" ? t(this.http, "PUT", "/global-comment-bans/{user}", a) : t(this.http, "PUT", "/comment-bans/{user}", a));
|
|
22
34
|
return i({
|
|
23
35
|
type: "ban.saved",
|
|
24
|
-
scope:
|
|
36
|
+
scope: e,
|
|
25
37
|
ban: o
|
|
26
38
|
}), o;
|
|
27
39
|
}
|
|
28
|
-
async lift(
|
|
40
|
+
async lift(e, n) {
|
|
29
41
|
let r = this.http.captureChanges(), i = { params: { user: n } };
|
|
30
|
-
await (
|
|
42
|
+
await (e === "global" ? t(this.http, "DELETE", "/global-comment-bans/{user}", i) : t(this.http, "DELETE", "/comment-bans/{user}", i)), r({
|
|
31
43
|
type: "ban.lifted",
|
|
32
|
-
scope:
|
|
44
|
+
scope: e,
|
|
33
45
|
user: n
|
|
34
46
|
});
|
|
35
47
|
}
|
|
36
48
|
};
|
|
37
49
|
//#endregion
|
|
38
|
-
export {
|
|
50
|
+
export { n as BansClient };
|
|
39
51
|
|
|
40
52
|
//# sourceMappingURL=bans.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bans.js","names":[],"sources":["../../../src/client/content/bans.ts"],"sourcesContent":["import type { BanInput, CommentBan } from \"../generated/wire.js\";\nimport type { Http } from \"../http.js\";\nimport { call, type PageQuery } from \"../route.js\";\nimport type { BanScope } from \"./types.js\";\n\n/** Comment bans: \"owner\" on the caller's own content, \"global\" across the site (CommentBan). */\nexport class BansClient {\n constructor(private readonly http: Http) {}\n\n /** The scope's bans, newest first, expired ones included. */\n list(scope: BanScope, q: PageQuery = {}, signal?: AbortSignal): Promise<CommentBan[]> {\n return scope === \"global\"\n ? call(this.http, \"GET\", \"/global-comment-bans\", { query: q, signal })\n : call(this.http, \"GET\", \"/comment-bans\", { query: q, signal });\n }\n /** Bans user from commenting in the scope, replacing any ban there; no until lasts until lifted. */\n async ban(scope: BanScope, user: string, input: BanInput = {}): Promise<CommentBan> {\n const emit = this.http.captureChanges();\n const o = { params: { user }, body: input };\n const ban: CommentBan = await (scope === \"global\"\n ? call(this.http, \"PUT\", \"/global-comment-bans/{user}\", o)\n : call(this.http, \"PUT\", \"/comment-bans/{user}\", o));\n emit({ type: \"ban.saved\", scope, ban });\n return ban;\n }\n /** Lifts user's ban in the scope; idempotent. */\n async lift(scope: BanScope, user: string): Promise<void> {\n const emit = this.http.captureChanges();\n const o = { params: { user } };\n await (scope === \"global\" ? call(this.http, \"DELETE\", \"/global-comment-bans/{user}\", o) : call(this.http, \"DELETE\", \"/comment-bans/{user}\", o));\n emit({ type: \"ban.lifted\", scope, user });\n }\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"bans.js","names":[],"sources":["../../../src/client/content/bans.ts"],"sourcesContent":["import { ContentKitError } from \"../errors.js\";\nimport type { BanInput, CommentBan } from \"../generated/wire.js\";\nimport type { Http } from \"../http.js\";\nimport { call, type PageQuery } from \"../route.js\";\nimport type { BanScope } from \"./types.js\";\n\n/** Comment bans: \"owner\" on the caller's own content, \"global\" across the site (CommentBan). */\nexport class BansClient {\n constructor(private readonly http: Http) {}\n\n /** The scope's bans, newest first, expired ones included. */\n list(scope: BanScope, q: PageQuery = {}, signal?: AbortSignal): Promise<CommentBan[]> {\n return scope === \"global\"\n ? call(this.http, \"GET\", \"/global-comment-bans\", { query: q, signal })\n : call(this.http, \"GET\", \"/comment-bans\", { query: q, signal });\n }\n /** The user's site-wide ban, expired or not; null when they have none (root:comments:ban). */\n async get(scope: \"global\", user: string, signal?: AbortSignal): Promise<CommentBan | null> {\n try {\n return await call(this.http, \"GET\", \"/global-comment-bans/{user}\", { params: { user }, signal });\n } catch (e) {\n if (e instanceof ContentKitError && e.code === \"not_found\") return null;\n throw e;\n }\n }\n /** Bans user from commenting in the scope, replacing any ban there; no until lasts until lifted. */\n async ban(scope: BanScope, user: string, input: BanInput = {}): Promise<CommentBan> {\n const emit = this.http.captureChanges();\n const o = { params: { user }, body: input };\n const ban: CommentBan = await (scope === \"global\"\n ? call(this.http, \"PUT\", \"/global-comment-bans/{user}\", o)\n : call(this.http, \"PUT\", \"/comment-bans/{user}\", o));\n emit({ type: \"ban.saved\", scope, ban });\n return ban;\n }\n /** Lifts user's ban in the scope; idempotent. */\n async lift(scope: BanScope, user: string): Promise<void> {\n const emit = this.http.captureChanges();\n const o = { params: { user } };\n await (scope === \"global\" ? call(this.http, \"DELETE\", \"/global-comment-bans/{user}\", o) : call(this.http, \"DELETE\", \"/comment-bans/{user}\", o));\n emit({ type: \"ban.lifted\", scope, user });\n }\n}\n"],"mappings":";;;AAOA,IAAa,IAAb,MAAwB;CACO;CAA7B,YAAY,GAA6B;EAAZ,KAAA,OAAA;CAAa;CAG1C,KAAK,GAAiB,IAAe,CAAC,GAAG,GAA6C;EACpF,OAAO,MAAU,WACb,EAAK,KAAK,MAAM,OAAO,wBAAwB;GAAE,OAAO;GAAG;EAAO,CAAC,IACnE,EAAK,KAAK,MAAM,OAAO,iBAAiB;GAAE,OAAO;GAAG;EAAO,CAAC;CAClE;CAEA,MAAM,IAAI,GAAiB,GAAc,GAAkD;EACzF,IAAI;GACF,OAAO,MAAM,EAAK,KAAK,MAAM,OAAO,+BAA+B;IAAE,QAAQ,EAAE,QAAK;IAAG;GAAO,CAAC;EACjG,SAAS,GAAG;GACV,IAAI,aAAa,KAAmB,EAAE,SAAS,aAAa,OAAO;GACnE,MAAM;EACR;CACF;CAEA,MAAM,IAAI,GAAiB,GAAc,IAAkB,CAAC,GAAwB;EAClF,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAI;GAAE,QAAQ,EAAE,QAAK;GAAG,MAAM;EAAM,GACpC,IAAkB,OAAO,MAAU,WACrC,EAAK,KAAK,MAAM,OAAO,+BAA+B,CAAC,IACvD,EAAK,KAAK,MAAM,OAAO,wBAAwB,CAAC;EAEpD,OADA,EAAK;GAAE,MAAM;GAAa;GAAO;EAAI,CAAC,GAC/B;CACT;CAEA,MAAM,KAAK,GAAiB,GAA6B;EACvD,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAI,EAAE,QAAQ,EAAE,QAAK,EAAE;EAE7B,AADA,OAAO,MAAU,WAAW,EAAK,KAAK,MAAM,UAAU,+BAA+B,CAAC,IAAI,EAAK,KAAK,MAAM,UAAU,wBAAwB,CAAC,IAC7I,EAAK;GAAE,MAAM;GAAc;GAAO;EAAK,CAAC;CAC1C;AACF"}
|
|
@@ -8,6 +8,8 @@ export interface CommentQuery extends PageQuery {
|
|
|
8
8
|
export interface AdminCommentQuery extends PageQuery {
|
|
9
9
|
/** Only comments on this content kind. */
|
|
10
10
|
contentKind?: string;
|
|
11
|
+
/** Only comments by this user id. */
|
|
12
|
+
author?: string;
|
|
11
13
|
}
|
|
12
14
|
/** Comments on an item: threads, replies, edits, tombstones, reactions, standing, the latest feed and moderation. */
|
|
13
15
|
export declare class CommentsClient {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"comments.js","names":[],"sources":["../../../src/client/content/comments.ts"],"sourcesContent":["import type { AdminComment, Comment, CommentInput, CommentStanding, FeedItem, ReactionCounts, RefBody } from \"../generated/wire.js\";\nimport type { Http } from \"../http.js\";\nimport { call, type PageQuery } from \"../route.js\";\nimport { reactionVerb, type Reaction, type Sort } from \"./types.js\";\n\nexport interface CommentQuery extends PageQuery {\n sort?: Sort;\n}\n\nexport interface AdminCommentQuery extends PageQuery {\n /** Only comments on this content kind. */\n contentKind?: string;\n}\n\n// Content ids are the host's opaque text (not only media's UUIDv7s).\nconst target = (ref: RefBody) => ({ kind: ref.kind, id: ref.id });\n\n/** Comments on an item: threads, replies, edits, tombstones, reactions, standing, the latest feed and moderation. */\nexport class CommentsClient {\n constructor(private readonly http: Http) {}\n\n /** The item's top-level comments with reply counts; the caller also gets its own held and rejected ones. */\n list(ref: RefBody, q: CommentQuery = {}, signal?: AbortSignal): Promise<Comment[]> {\n return call(this.http, \"GET\", \"/{kind}/{id}/comments\", { params: target(ref), query: q, signal });\n }\n /** A top-level comment's replies, oldest first. */\n replies(id: string, q: PageQuery = {}, signal?: AbortSignal): Promise<Comment[]> {\n return call(this.http, \"GET\", \"/comments/{cid}/replies\", { params: { cid: id }, query: q, signal });\n }\n /** Comments on the item, or replies to a top-level comment (reply_to_id); anonymous callers give anon_name. */\n async create(ref: RefBody, input: CommentInput): Promise<Comment> {\n const emit = this.http.captureChanges();\n const comment: Comment = await call(this.http, \"POST\", \"/{kind}/{id}/comments\", { params: target(ref), body: input });\n emit({ type: \"comment.created\", ref: target(ref), comment });\n return comment;\n }\n /** Replaces the body: its author, or a moderator. */\n async edit(id: string, body: string): Promise<Comment> {\n const emit = this.http.captureChanges();\n const comment: Comment = await call(this.http, \"PATCH\", \"/comments/{cid}\", { params: { cid: id }, body: { body } });\n emit({ type: \"comment.updated\", comment });\n return comment;\n }\n /** Leaves a tombstone: its author, or a moderator. */\n async delete(id: string): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"DELETE\", \"/comments/{cid}\", { params: { cid: id } });\n emit({ type: \"comment.deleted\", id });\n }\n /** Sets the caller's reaction to a comment. */\n async react(id: string, value: Reaction): Promise<ReactionCounts> {\n const emit = this.http.captureChanges();\n const params = { cid: id };\n const counts: ReactionCounts =\n value === 0 ? await call(this.http, \"DELETE\", \"/comments/{cid}/reaction\", { params }) : await call(this.http, \"POST\", `/comments/{cid}/${reactionVerb(value)}` as const, { params });\n emit({ type: \"comment.reacted\", id, counts });\n return counts;\n }\n /** Whether the caller may comment on the item, the ban that stops it, and what it may do to others' comments. */\n standing(ref: RefBody, signal?: AbortSignal): Promise<CommentStanding> {\n return call(this.http, \"GET\", \"/{kind}/{id}/can-comment\", { params: target(ref), signal });\n }\n /** The newest published comments across the site, with their items; a page may under-fill. */\n latest(q: PageQuery = {}, signal?: AbortSignal): Promise<FeedItem[]> {\n return call(this.http, \"GET\", \"/comments/latest\", { query: q, signal });\n }\n /** Every comment, newest first, deleted, held and rejected ones with their bodies (root:comments:moderate). */\n adminList(q: AdminCommentQuery = {}, signal?: AbortSignal): Promise<AdminComment[]> {\n const { contentKind, ...
|
|
1
|
+
{"version":3,"file":"comments.js","names":[],"sources":["../../../src/client/content/comments.ts"],"sourcesContent":["import type { AdminComment, Comment, CommentInput, CommentStanding, FeedItem, ReactionCounts, RefBody } from \"../generated/wire.js\";\nimport type { Http } from \"../http.js\";\nimport { call, type PageQuery } from \"../route.js\";\nimport { reactionVerb, type Reaction, type Sort } from \"./types.js\";\n\nexport interface CommentQuery extends PageQuery {\n sort?: Sort;\n}\n\nexport interface AdminCommentQuery extends PageQuery {\n /** Only comments on this content kind. */\n contentKind?: string;\n /** Only comments by this user id. */\n author?: string;\n}\n\n// Content ids are the host's opaque text (not only media's UUIDv7s).\nconst target = (ref: RefBody) => ({ kind: ref.kind, id: ref.id });\n\n/** Comments on an item: threads, replies, edits, tombstones, reactions, standing, the latest feed and moderation. */\nexport class CommentsClient {\n constructor(private readonly http: Http) {}\n\n /** The item's top-level comments with reply counts; the caller also gets its own held and rejected ones. */\n list(ref: RefBody, q: CommentQuery = {}, signal?: AbortSignal): Promise<Comment[]> {\n return call(this.http, \"GET\", \"/{kind}/{id}/comments\", { params: target(ref), query: q, signal });\n }\n /** A top-level comment's replies, oldest first. */\n replies(id: string, q: PageQuery = {}, signal?: AbortSignal): Promise<Comment[]> {\n return call(this.http, \"GET\", \"/comments/{cid}/replies\", { params: { cid: id }, query: q, signal });\n }\n /** Comments on the item, or replies to a top-level comment (reply_to_id); anonymous callers give anon_name. */\n async create(ref: RefBody, input: CommentInput): Promise<Comment> {\n const emit = this.http.captureChanges();\n const comment: Comment = await call(this.http, \"POST\", \"/{kind}/{id}/comments\", { params: target(ref), body: input });\n emit({ type: \"comment.created\", ref: target(ref), comment });\n return comment;\n }\n /** Replaces the body: its author, or a moderator. */\n async edit(id: string, body: string): Promise<Comment> {\n const emit = this.http.captureChanges();\n const comment: Comment = await call(this.http, \"PATCH\", \"/comments/{cid}\", { params: { cid: id }, body: { body } });\n emit({ type: \"comment.updated\", comment });\n return comment;\n }\n /** Leaves a tombstone: its author, or a moderator. */\n async delete(id: string): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"DELETE\", \"/comments/{cid}\", { params: { cid: id } });\n emit({ type: \"comment.deleted\", id });\n }\n /** Sets the caller's reaction to a comment. */\n async react(id: string, value: Reaction): Promise<ReactionCounts> {\n const emit = this.http.captureChanges();\n const params = { cid: id };\n const counts: ReactionCounts =\n value === 0 ? await call(this.http, \"DELETE\", \"/comments/{cid}/reaction\", { params }) : await call(this.http, \"POST\", `/comments/{cid}/${reactionVerb(value)}` as const, { params });\n emit({ type: \"comment.reacted\", id, counts });\n return counts;\n }\n /** Whether the caller may comment on the item, the ban that stops it, and what it may do to others' comments. */\n standing(ref: RefBody, signal?: AbortSignal): Promise<CommentStanding> {\n return call(this.http, \"GET\", \"/{kind}/{id}/can-comment\", { params: target(ref), signal });\n }\n /** The newest published comments across the site, with their items; a page may under-fill. */\n latest(q: PageQuery = {}, signal?: AbortSignal): Promise<FeedItem[]> {\n return call(this.http, \"GET\", \"/comments/latest\", { query: q, signal });\n }\n /** Every comment, newest first, deleted, held and rejected ones with their bodies (root:comments:moderate). */\n adminList(q: AdminCommentQuery = {}, signal?: AbortSignal): Promise<AdminComment[]> {\n const { contentKind, ...rest } = q;\n return call(this.http, \"GET\", \"/comments/admin\", { query: { ...rest, content_kind: contentKind }, signal });\n }\n /** Restores a deleted comment (root:comments:moderate). */\n async restore(id: string): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"POST\", \"/comments/{cid}/restore\", { params: { cid: id } });\n emit({ type: \"comment.restored\", id });\n }\n}\n"],"mappings":";;;AAiBA,IAAM,KAAU,OAAkB;CAAE,MAAM,EAAI;CAAM,IAAI,EAAI;AAAG,IAGlD,IAAb,MAA4B;CACG;CAA7B,YAAY,GAA6B;EAAZ,KAAA,OAAA;CAAa;CAG1C,KAAK,GAAc,IAAkB,CAAC,GAAG,GAA0C;EACjF,OAAO,EAAK,KAAK,MAAM,OAAO,yBAAyB;GAAE,QAAQ,EAAO,CAAG;GAAG,OAAO;GAAG;EAAO,CAAC;CAClG;CAEA,QAAQ,GAAY,IAAe,CAAC,GAAG,GAA0C;EAC/E,OAAO,EAAK,KAAK,MAAM,OAAO,2BAA2B;GAAE,QAAQ,EAAE,KAAK,EAAG;GAAG,OAAO;GAAG;EAAO,CAAC;CACpG;CAEA,MAAM,OAAO,GAAc,GAAuC;EAChE,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAmB,MAAM,EAAK,KAAK,MAAM,QAAQ,yBAAyB;GAAE,QAAQ,EAAO,CAAG;GAAG,MAAM;EAAM,CAAC;EAEpH,OADA,EAAK;GAAE,MAAM;GAAmB,KAAK,EAAO,CAAG;GAAG;EAAQ,CAAC,GACpD;CACT;CAEA,MAAM,KAAK,GAAY,GAAgC;EACrD,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAmB,MAAM,EAAK,KAAK,MAAM,SAAS,mBAAmB;GAAE,QAAQ,EAAE,KAAK,EAAG;GAAG,MAAM,EAAE,QAAK;EAAE,CAAC;EAElH,OADA,EAAK;GAAE,MAAM;GAAmB;EAAQ,CAAC,GAClC;CACT;CAEA,MAAM,OAAO,GAA2B;EACtC,IAAM,IAAO,KAAK,KAAK,eAAe;EAEtC,AADA,MAAM,EAAK,KAAK,MAAM,UAAU,mBAAmB,EAAE,QAAQ,EAAE,KAAK,EAAG,EAAE,CAAC,GAC1E,EAAK;GAAE,MAAM;GAAmB;EAAG,CAAC;CACtC;CAEA,MAAM,MAAM,GAAY,GAA0C;EAChE,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAS,EAAE,KAAK,EAAG,GACnB,IACJ,MAAU,IAAI,MAAM,EAAK,KAAK,MAAM,UAAU,4BAA4B,EAAE,UAAO,CAAC,IAAI,MAAM,EAAK,KAAK,MAAM,QAAQ,mBAAmB,EAAa,CAAK,KAAc,EAAE,UAAO,CAAC;EAErL,OADA,EAAK;GAAE,MAAM;GAAmB;GAAI;EAAO,CAAC,GACrC;CACT;CAEA,SAAS,GAAc,GAAgD;EACrE,OAAO,EAAK,KAAK,MAAM,OAAO,4BAA4B;GAAE,QAAQ,EAAO,CAAG;GAAG;EAAO,CAAC;CAC3F;CAEA,OAAO,IAAe,CAAC,GAAG,GAA2C;EACnE,OAAO,EAAK,KAAK,MAAM,OAAO,oBAAoB;GAAE,OAAO;GAAG;EAAO,CAAC;CACxE;CAEA,UAAU,IAAuB,CAAC,GAAG,GAA+C;EAClF,IAAM,EAAE,gBAAa,GAAG,MAAS;EACjC,OAAO,EAAK,KAAK,MAAM,OAAO,mBAAmB;GAAE,OAAO;IAAE,GAAG;IAAM,cAAc;GAAY;GAAG;EAAO,CAAC;CAC5G;CAEA,MAAM,QAAQ,GAA2B;EACvC,IAAM,IAAO,KAAK,KAAK,eAAe;EAEtC,AADA,MAAM,EAAK,KAAK,MAAM,QAAQ,2BAA2B,EAAE,QAAQ,EAAE,KAAK,EAAG,EAAE,CAAC,GAChF,EAAK;GAAE,MAAM;GAAoB;EAAG,CAAC;CACvC;AACF"}
|
|
@@ -9,6 +9,13 @@ export interface PollQuery extends PageQuery {
|
|
|
9
9
|
/** Polls live on this day, YYYY-MM-DD. */
|
|
10
10
|
date?: string;
|
|
11
11
|
}
|
|
12
|
+
/** A poll's state in the staff list. */
|
|
13
|
+
export type PollState = "live" | "scheduled" | "closed" | "inactive";
|
|
14
|
+
export interface PollAdminQuery extends PollQuery {
|
|
15
|
+
state?: PollState;
|
|
16
|
+
/** Only polls whose question contains this text, ignoring case. */
|
|
17
|
+
q?: string;
|
|
18
|
+
}
|
|
12
19
|
/** Site-wide polls: multiple choice or free text; staff write them (root:polls:write). */
|
|
13
20
|
export declare class PollsClient {
|
|
14
21
|
private readonly http;
|
|
@@ -16,8 +23,8 @@ export declare class PollsClient {
|
|
|
16
23
|
constructor(http: Http, media: MediaClient);
|
|
17
24
|
/** Live polls, newest first. */
|
|
18
25
|
list(q?: PollQuery, signal?: AbortSignal): Promise<Poll[]>;
|
|
19
|
-
/** Every poll, scheduled and inactive ones included (root:polls:write). */
|
|
20
|
-
adminList(q?:
|
|
26
|
+
/** Every poll, scheduled and inactive ones included, by state and question (root:polls:write). */
|
|
27
|
+
adminList(q?: PollAdminQuery, signal?: AbortSignal): Promise<Poll[]>;
|
|
21
28
|
/** A poll with the caller's vote or answer. */
|
|
22
29
|
get(id: string, signal?: AbortSignal): Promise<Poll>;
|
|
23
30
|
/** Creates a poll with its options (images are set once it exists). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"polls.js","names":[],"sources":["../../../src/client/content/polls.ts"],"sourcesContent":["import type { Poll, PollImage, PollInput, PollOption, PollOptionPatch, PollUpdate } from \"../generated/wire.js\";\nimport type { Http } from \"../http.js\";\nimport type { MediaClient, NamedOptions } from \"../media/client.js\";\nimport { call, type PageQuery } from \"../route.js\";\n\nexport interface PollQuery extends PageQuery {\n language?: string;\n /** Polls live in this month, YYYY-MM. */\n month?: string;\n /** Polls live on this day, YYYY-MM-DD. */\n date?: string;\n}\n\n/** Site-wide polls: multiple choice or free text; staff write them (root:polls:write). */\nexport class PollsClient {\n constructor(\n private readonly http: Http,\n private readonly media: MediaClient,\n ) {}\n\n /** Live polls, newest first. */\n list(q: PollQuery = {}, signal?: AbortSignal): Promise<Poll[]> {\n return call(this.http, \"GET\", \"/polls\", { query: q, signal });\n }\n /** Every poll, scheduled and inactive ones included (root:polls:write). */\n adminList(q:
|
|
1
|
+
{"version":3,"file":"polls.js","names":[],"sources":["../../../src/client/content/polls.ts"],"sourcesContent":["import type { Poll, PollImage, PollInput, PollOption, PollOptionPatch, PollUpdate } from \"../generated/wire.js\";\nimport type { Http } from \"../http.js\";\nimport type { MediaClient, NamedOptions } from \"../media/client.js\";\nimport { call, type PageQuery } from \"../route.js\";\n\nexport interface PollQuery extends PageQuery {\n language?: string;\n /** Polls live in this month, YYYY-MM. */\n month?: string;\n /** Polls live on this day, YYYY-MM-DD. */\n date?: string;\n}\n\n/** A poll's state in the staff list. */\nexport type PollState = \"live\" | \"scheduled\" | \"closed\" | \"inactive\";\n\nexport interface PollAdminQuery extends PollQuery {\n state?: PollState;\n /** Only polls whose question contains this text, ignoring case. */\n q?: string;\n}\n\n/** Site-wide polls: multiple choice or free text; staff write them (root:polls:write). */\nexport class PollsClient {\n constructor(\n private readonly http: Http,\n private readonly media: MediaClient,\n ) {}\n\n /** Live polls, newest first. */\n list(q: PollQuery = {}, signal?: AbortSignal): Promise<Poll[]> {\n return call(this.http, \"GET\", \"/polls\", { query: q, signal });\n }\n /** Every poll, scheduled and inactive ones included, by state and question (root:polls:write). */\n adminList(q: PollAdminQuery = {}, signal?: AbortSignal): Promise<Poll[]> {\n return call(this.http, \"GET\", \"/polls/admin\", { query: q, signal });\n }\n /** A poll with the caller's vote or answer. */\n get(id: string, signal?: AbortSignal): Promise<Poll> {\n return call(this.http, \"GET\", \"/polls/{id}\", { params: { id }, signal });\n }\n /** Creates a poll with its options (images are set once it exists). */\n async create(input: PollInput): Promise<Poll> {\n const emit = this.http.captureChanges();\n const poll: Poll = await call(this.http, \"POST\", \"/polls\", { body: input });\n emit({ type: \"poll.created\", poll });\n return poll;\n }\n /** Updates the given fields. */\n async update(id: string, patch: PollUpdate): Promise<Poll> {\n const emit = this.http.captureChanges();\n const poll: Poll = await call(this.http, \"PATCH\", \"/polls/{id}\", { params: { id }, body: patch });\n emit({ type: \"poll.updated\", poll });\n return poll;\n }\n /** Deletes the poll and its images. */\n async delete(id: string): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"DELETE\", \"/polls/{id}\", { params: { id } });\n emit({ type: \"poll.deleted\", id });\n }\n /** Votes for an option of an open multiple-choice poll; a vote is final, and voting again changes nothing. */\n async vote(id: string, option: string): Promise<Poll> {\n const emit = this.http.captureChanges();\n const poll: Poll = await call(this.http, \"POST\", \"/polls/{id}/vote\", { params: { id }, body: { option_id: option } });\n emit({ type: \"poll.updated\", poll });\n return poll;\n }\n /** Stores or replaces the signed-in caller's answer to an open free-text poll. */\n async answer(id: string, text: string): Promise<Poll> {\n const emit = this.http.captureChanges();\n const poll: Poll = await call(this.http, \"POST\", \"/polls/{id}/answer\", { params: { id }, body: { text } });\n emit({ type: \"poll.updated\", poll });\n return poll;\n }\n /** Sets the question image to an inline image name of the poll's folder, or clears it; resolves with its URL. */\n async setImage(id: string, image: string | null): Promise<string | null> {\n const emit = this.http.captureChanges();\n const r: PollImage = await call(this.http, \"PUT\", \"/polls/{id}/image\", { params: { id }, body: { image: image ?? \"\" } });\n emit({ type: \"poll.changed\", id });\n return r.image_url;\n }\n /** Uploads file to the poll's folder as the question image (null clears it). */\n async uploadImage(id: string, file: Blob | null, o?: NamedOptions): Promise<string | null> {\n return this.setImage(id, file ? (await this.media.uploadNamed(this.media.pollRef(id), file, o)).name : null);\n }\n /** Adds an option, at the end unless position is given. */\n async addOption(id: string, option: PollOptionPatch): Promise<PollOption> {\n const emit = this.http.captureChanges();\n const o: PollOption = await call(this.http, \"POST\", \"/polls/{id}/options\", { params: { id }, body: option });\n emit({ type: \"poll.changed\", id });\n return o;\n }\n async updateOption(id: string, option: string, patch: PollOptionPatch): Promise<PollOption> {\n const emit = this.http.captureChanges();\n const o: PollOption = await call(this.http, \"PATCH\", \"/polls/{id}/options/{oid}\", { params: { id, oid: option }, body: patch });\n emit({ type: \"poll.changed\", id });\n return o;\n }\n /** Removes an option and its votes; a poll keeps at least two. */\n async deleteOption(id: string, option: string): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"DELETE\", \"/polls/{id}/options/{oid}\", { params: { id, oid: option } });\n emit({ type: \"poll.changed\", id });\n }\n /** Gives the options the positions of their order, patching those that moved. */\n async reorderOptions(id: string, options: readonly Pick<PollOption, \"id\" | \"position\">[]): Promise<void> {\n const emit = this.http.captureChanges();\n for (const [position, o] of options.entries()) {\n if (o.position !== position) await call(this.http, \"PATCH\", \"/polls/{id}/options/{oid}\", { params: { id, oid: o.id }, body: { position } });\n }\n emit({ type: \"poll.changed\", id });\n }\n async setOptionImage(id: string, option: string, image: string | null): Promise<string | null> {\n const emit = this.http.captureChanges();\n const r: PollImage = await call(this.http, \"PUT\", \"/polls/{id}/options/{oid}/image\", { params: { id, oid: option }, body: { image: image ?? \"\" } });\n emit({ type: \"poll.changed\", id });\n return r.image_url;\n }\n /** Uploads file to the poll's folder as the option's image (null clears it). */\n async uploadOptionImage(id: string, option: string, file: Blob | null, o?: NamedOptions): Promise<string | null> {\n return this.setOptionImage(id, option, file ? (await this.media.uploadNamed(this.media.pollRef(id), file, o)).name : null);\n }\n}\n"],"mappings":"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"}
|
|
@@ -190,7 +190,7 @@ export declare const CONTENTKIT_ROUTES: readonly [{
|
|
|
190
190
|
readonly path: "/comments/admin";
|
|
191
191
|
readonly auth: "staff";
|
|
192
192
|
readonly permission: "root:comments:moderate";
|
|
193
|
-
readonly query: readonly ["content_kind", "limit", "offset"];
|
|
193
|
+
readonly query: readonly ["content_kind", "author", "limit", "offset"];
|
|
194
194
|
readonly request: null;
|
|
195
195
|
readonly responses: {
|
|
196
196
|
readonly 200: "AdminComment[]";
|
|
@@ -412,7 +412,7 @@ export declare const CONTENTKIT_ROUTES: readonly [{
|
|
|
412
412
|
readonly path: "/polls/admin";
|
|
413
413
|
readonly auth: "staff";
|
|
414
414
|
readonly permission: "root:polls:write";
|
|
415
|
-
readonly query: readonly ["language", "month", "date", "limit", "offset"];
|
|
415
|
+
readonly query: readonly ["language", "month", "date", "state", "q", "limit", "offset"];
|
|
416
416
|
readonly request: null;
|
|
417
417
|
readonly responses: {
|
|
418
418
|
readonly 200: "Poll[]";
|
|
@@ -614,6 +614,19 @@ export declare const CONTENTKIT_ROUTES: readonly [{
|
|
|
614
614
|
};
|
|
615
615
|
readonly errors: readonly ["unauthorized"];
|
|
616
616
|
readonly errorSets: readonly ["module:content", "auth", "request"];
|
|
617
|
+
}, {
|
|
618
|
+
readonly method: "GET";
|
|
619
|
+
readonly module: "content";
|
|
620
|
+
readonly path: "/global-comment-bans/{user}";
|
|
621
|
+
readonly auth: "staff";
|
|
622
|
+
readonly permission: "root:comments:ban";
|
|
623
|
+
readonly query: readonly [];
|
|
624
|
+
readonly request: null;
|
|
625
|
+
readonly responses: {
|
|
626
|
+
readonly 200: "CommentBan";
|
|
627
|
+
};
|
|
628
|
+
readonly errors: readonly ["not_found", "unauthorized"];
|
|
629
|
+
readonly errorSets: readonly ["module:content", "auth", "request"];
|
|
617
630
|
}, {
|
|
618
631
|
readonly method: "PUT";
|
|
619
632
|
readonly module: "content";
|
|
@@ -926,6 +939,19 @@ export declare const CONTENTKIT_ROUTES: readonly [{
|
|
|
926
939
|
};
|
|
927
940
|
readonly errors: readonly ["not_found"];
|
|
928
941
|
readonly errorSets: readonly ["module:taxonomy", "auth", "request"];
|
|
942
|
+
}, {
|
|
943
|
+
readonly method: "GET";
|
|
944
|
+
readonly module: "taxonomy";
|
|
945
|
+
readonly path: "/nodes/{id}/assignments";
|
|
946
|
+
readonly auth: "staff";
|
|
947
|
+
readonly permission: "root:taxonomy:write";
|
|
948
|
+
readonly query: readonly ["content_kind", "relation", "cursor", "limit"];
|
|
949
|
+
readonly request: null;
|
|
950
|
+
readonly responses: {
|
|
951
|
+
readonly 200: "AssignmentPage";
|
|
952
|
+
};
|
|
953
|
+
readonly errors: readonly ["not_found"];
|
|
954
|
+
readonly errorSets: readonly ["module:taxonomy", "auth", "request"];
|
|
929
955
|
}, {
|
|
930
956
|
readonly method: "POST";
|
|
931
957
|
readonly module: "taxonomy";
|
|
@@ -254,6 +254,7 @@ var e = [
|
|
|
254
254
|
permission: "root:comments:moderate",
|
|
255
255
|
query: [
|
|
256
256
|
"content_kind",
|
|
257
|
+
"author",
|
|
257
258
|
"limit",
|
|
258
259
|
"offset"
|
|
259
260
|
],
|
|
@@ -592,6 +593,8 @@ var e = [
|
|
|
592
593
|
"language",
|
|
593
594
|
"month",
|
|
594
595
|
"date",
|
|
596
|
+
"state",
|
|
597
|
+
"q",
|
|
595
598
|
"limit",
|
|
596
599
|
"offset"
|
|
597
600
|
],
|
|
@@ -853,6 +856,22 @@ var e = [
|
|
|
853
856
|
"request"
|
|
854
857
|
]
|
|
855
858
|
},
|
|
859
|
+
{
|
|
860
|
+
method: "GET",
|
|
861
|
+
module: "content",
|
|
862
|
+
path: "/global-comment-bans/{user}",
|
|
863
|
+
auth: "staff",
|
|
864
|
+
permission: "root:comments:ban",
|
|
865
|
+
query: [],
|
|
866
|
+
request: null,
|
|
867
|
+
responses: { 200: "CommentBan" },
|
|
868
|
+
errors: ["not_found", "unauthorized"],
|
|
869
|
+
errorSets: [
|
|
870
|
+
"module:content",
|
|
871
|
+
"auth",
|
|
872
|
+
"request"
|
|
873
|
+
]
|
|
874
|
+
},
|
|
856
875
|
{
|
|
857
876
|
method: "PUT",
|
|
858
877
|
module: "content",
|
|
@@ -1285,6 +1304,27 @@ var e = [
|
|
|
1285
1304
|
"request"
|
|
1286
1305
|
]
|
|
1287
1306
|
},
|
|
1307
|
+
{
|
|
1308
|
+
method: "GET",
|
|
1309
|
+
module: "taxonomy",
|
|
1310
|
+
path: "/nodes/{id}/assignments",
|
|
1311
|
+
auth: "staff",
|
|
1312
|
+
permission: "root:taxonomy:write",
|
|
1313
|
+
query: [
|
|
1314
|
+
"content_kind",
|
|
1315
|
+
"relation",
|
|
1316
|
+
"cursor",
|
|
1317
|
+
"limit"
|
|
1318
|
+
],
|
|
1319
|
+
request: null,
|
|
1320
|
+
responses: { 200: "AssignmentPage" },
|
|
1321
|
+
errors: ["not_found"],
|
|
1322
|
+
errorSets: [
|
|
1323
|
+
"module:taxonomy",
|
|
1324
|
+
"auth",
|
|
1325
|
+
"request"
|
|
1326
|
+
]
|
|
1327
|
+
},
|
|
1288
1328
|
{
|
|
1289
1329
|
method: "POST",
|
|
1290
1330
|
module: "taxonomy",
|