@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.
Files changed (120) hide show
  1. package/README.md +98 -10
  2. package/dist/client/content/bans.d.ts +2 -0
  3. package/dist/client/content/bans.js +24 -12
  4. package/dist/client/content/bans.js.map +1 -1
  5. package/dist/client/content/comments.d.ts +2 -0
  6. package/dist/client/content/comments.js.map +1 -1
  7. package/dist/client/content/polls.d.ts +9 -2
  8. package/dist/client/content/polls.js.map +1 -1
  9. package/dist/client/generated/routes.d.ts +28 -2
  10. package/dist/client/generated/routes.js +40 -0
  11. package/dist/client/generated/routes.js.map +1 -1
  12. package/dist/client/generated/wire.d.ts +4 -0
  13. package/dist/client/generated/wire.js.map +1 -1
  14. package/dist/client/index.d.ts +2 -2
  15. package/dist/client/taxonomy.d.ts +5 -1
  16. package/dist/client/taxonomy.js +7 -0
  17. package/dist/client/taxonomy.js.map +1 -1
  18. package/dist/components/admin/poll-manager.d.ts +28 -0
  19. package/dist/components/admin/poll-manager.js +297 -0
  20. package/dist/components/admin/poll-manager.js.map +1 -0
  21. package/dist/components/admin/post-manager.d.ts +45 -0
  22. package/dist/components/admin/post-manager.js +602 -0
  23. package/dist/components/admin/post-manager.js.map +1 -0
  24. package/dist/components/admin/shell.d.ts +73 -0
  25. package/dist/components/admin/shell.js +148 -0
  26. package/dist/components/admin/shell.js.map +1 -0
  27. package/dist/components/admin/taxonomy-manager.d.ts +54 -0
  28. package/dist/components/admin/taxonomy-manager.js +976 -0
  29. package/dist/components/admin/taxonomy-manager.js.map +1 -0
  30. package/dist/components/admin/user-comment-standing.d.ts +25 -0
  31. package/dist/components/admin/user-comment-standing.js +229 -0
  32. package/dist/components/admin/user-comment-standing.js.map +1 -0
  33. package/dist/components/social/bans.d.ts +5 -2
  34. package/dist/components/social/bans.js +132 -134
  35. package/dist/components/social/bans.js.map +1 -1
  36. package/dist/components/social/index.d.ts +1 -1
  37. package/dist/components/social/moderation.d.ts +11 -13
  38. package/dist/components/social/moderation.js +299 -218
  39. package/dist/components/social/moderation.js.map +1 -1
  40. package/dist/components/social/parts.d.ts +3 -2
  41. package/dist/components/social/parts.js +74 -48
  42. package/dist/components/social/parts.js.map +1 -1
  43. package/dist/components/social/poll-editor.js +1 -0
  44. package/dist/components/social/poll-editor.js.map +1 -1
  45. package/dist/editor/index.d.ts +1 -0
  46. package/dist/editor/rich-text-editor.d.ts +13 -0
  47. package/dist/editor/rich-text-editor.js +228 -0
  48. package/dist/editor/rich-text-editor.js.map +1 -0
  49. package/dist/editor.js +2 -0
  50. package/dist/index.d.ts +6 -0
  51. package/dist/index.js +13 -8
  52. package/dist/locales/admin/de.d.ts +2 -0
  53. package/dist/locales/admin/de.js +176 -0
  54. package/dist/locales/admin/de.js.map +1 -0
  55. package/dist/locales/admin/en.d.ts +171 -0
  56. package/dist/locales/admin/en.js +176 -0
  57. package/dist/locales/admin/en.js.map +1 -0
  58. package/dist/locales/admin/es.d.ts +2 -0
  59. package/dist/locales/admin/es.js +176 -0
  60. package/dist/locales/admin/es.js.map +1 -0
  61. package/dist/locales/admin/ja.d.ts +2 -0
  62. package/dist/locales/admin/ja.js +176 -0
  63. package/dist/locales/admin/ja.js.map +1 -0
  64. package/dist/locales/admin/ko.d.ts +2 -0
  65. package/dist/locales/admin/ko.js +176 -0
  66. package/dist/locales/admin/ko.js.map +1 -0
  67. package/dist/locales/admin/zh.d.ts +2 -0
  68. package/dist/locales/admin/zh.js +176 -0
  69. package/dist/locales/admin/zh.js.map +1 -0
  70. package/dist/locales/de.js +5 -3
  71. package/dist/locales/de.js.map +1 -1
  72. package/dist/locales/en.d.ts +176 -0
  73. package/dist/locales/en.js +5 -3
  74. package/dist/locales/en.js.map +1 -1
  75. package/dist/locales/es.js +5 -3
  76. package/dist/locales/es.js.map +1 -1
  77. package/dist/locales/ja.js +5 -3
  78. package/dist/locales/ja.js.map +1 -1
  79. package/dist/locales/ko.js +5 -3
  80. package/dist/locales/ko.js.map +1 -1
  81. package/dist/locales/social/de.js +8 -1
  82. package/dist/locales/social/de.js.map +1 -1
  83. package/dist/locales/social/en.d.ts +7 -0
  84. package/dist/locales/social/en.js +8 -1
  85. package/dist/locales/social/en.js.map +1 -1
  86. package/dist/locales/social/es.js +8 -1
  87. package/dist/locales/social/es.js.map +1 -1
  88. package/dist/locales/social/ja.js +8 -1
  89. package/dist/locales/social/ja.js.map +1 -1
  90. package/dist/locales/social/ko.js +8 -1
  91. package/dist/locales/social/ko.js.map +1 -1
  92. package/dist/locales/social/zh.js +8 -1
  93. package/dist/locales/social/zh.js.map +1 -1
  94. package/dist/locales/zh.js +5 -3
  95. package/dist/locales/zh.js.map +1 -1
  96. package/dist/provider.d.ts +2 -0
  97. package/dist/provider.js +23 -19
  98. package/dist/provider.js.map +1 -1
  99. package/dist/react/admin.d.ts +55 -0
  100. package/dist/react/admin.js +97 -0
  101. package/dist/react/admin.js.map +1 -0
  102. package/dist/react/comments.d.ts +18 -2
  103. package/dist/react/comments.js +24 -8
  104. package/dist/react/comments.js.map +1 -1
  105. package/dist/react/context.d.ts +7 -1
  106. package/dist/react/context.js +6 -1
  107. package/dist/react/context.js.map +1 -1
  108. package/dist/react/index.d.ts +4 -3
  109. package/dist/react/polls.js +88 -87
  110. package/dist/react/polls.js.map +1 -1
  111. package/dist/react/posts.js +123 -122
  112. package/dist/react/posts.js.map +1 -1
  113. package/dist/react/resources.js +3 -0
  114. package/dist/react/resources.js.map +1 -1
  115. package/dist/react/use-resource.d.ts +16 -0
  116. package/dist/react/use-resource.js +20 -1
  117. package/dist/react/use-resource.js.map +1 -1
  118. package/dist/react.js +21 -20
  119. package/dist/styles.css +1 -1
  120. 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: `CommentModeration` (every comment, the review queue, the site's
408
- bans), `CommentBans` with `CommentBanDialog`, and `PollEditor`. They show what
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 { call as e } from "../route.js";
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 t = class {
4
+ var n = class {
4
5
  http;
5
6
  constructor(e) {
6
7
  this.http = e;
7
8
  }
8
- list(t, n = {}, r) {
9
- return t === "global" ? e(this.http, "GET", "/global-comment-bans", {
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
- }) : e(this.http, "GET", "/comment-bans", {
13
+ }) : t(this.http, "GET", "/comment-bans", {
13
14
  query: n,
14
15
  signal: r
15
16
  });
16
17
  }
17
- async ban(t, n, r = {}) {
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 (t === "global" ? e(this.http, "PUT", "/global-comment-bans/{user}", a) : e(this.http, "PUT", "/comment-bans/{user}", a));
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: t,
36
+ scope: e,
25
37
  ban: o
26
38
  }), o;
27
39
  }
28
- async lift(t, n) {
40
+ async lift(e, n) {
29
41
  let r = this.http.captureChanges(), i = { params: { user: n } };
30
- await (t === "global" ? e(this.http, "DELETE", "/global-comment-bans/{user}", i) : e(this.http, "DELETE", "/comment-bans/{user}", i)), r({
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: t,
44
+ scope: e,
33
45
  user: n
34
46
  });
35
47
  }
36
48
  };
37
49
  //#endregion
38
- export { t as BansClient };
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":";;AAMA,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,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"}
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, ...page } = q;\n return call(this.http, \"GET\", \"/comments/admin\", { query: { ...page, 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":";;;AAeA,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"}
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?: PollQuery, signal?: AbortSignal): Promise<Poll[]>;
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: PollQuery = {}, 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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"}
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",