@openrails/contentkit-ui 0.70.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 +4 -2
- package/dist/client/content/comments.js.map +1 -1
- package/dist/client/content/polls.d.ts +10 -3
- package/dist/client/content/polls.js.map +1 -1
- package/dist/client/content/posts.d.ts +4 -4
- package/dist/client/content/posts.js.map +1 -1
- package/dist/client/generated/error-codes.js +2 -2
- package/dist/client/generated/error-codes.js.map +1 -1
- package/dist/client/generated/routes.d.ts +146 -120
- package/dist/client/generated/routes.js +245 -117
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +5 -0
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/index.d.ts +2 -2
- package/dist/client/taxonomy.d.ts +6 -2
- 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.d.ts +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.d.ts +2 -2
- package/dist/react/polls.js +88 -87
- package/dist/react/polls.js.map +1 -1
- package/dist/react/posts.d.ts +3 -3
- 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 {
|
|
@@ -29,8 +31,8 @@ export declare class CommentsClient {
|
|
|
29
31
|
standing(ref: RefBody, signal?: AbortSignal): Promise<CommentStanding>;
|
|
30
32
|
/** The newest published comments across the site, with their items; a page may under-fill. */
|
|
31
33
|
latest(q?: PageQuery, signal?: AbortSignal): Promise<FeedItem[]>;
|
|
32
|
-
/** Every comment, newest first, deleted, held and rejected ones with their bodies (
|
|
34
|
+
/** Every comment, newest first, deleted, held and rejected ones with their bodies (root:comments:moderate). */
|
|
33
35
|
adminList(q?: AdminCommentQuery, signal?: AbortSignal): Promise<AdminComment[]>;
|
|
34
|
-
/** Restores a deleted comment (
|
|
36
|
+
/** Restores a deleted comment (root:comments:moderate). */
|
|
35
37
|
restore(id: string): Promise<void>;
|
|
36
38
|
}
|
|
@@ -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 (
|
|
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,15 +9,22 @@ export interface PollQuery extends PageQuery {
|
|
|
9
9
|
/** Polls live on this day, YYYY-MM-DD. */
|
|
10
10
|
date?: string;
|
|
11
11
|
}
|
|
12
|
-
/**
|
|
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
|
+
}
|
|
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;
|
|
15
22
|
private readonly media;
|
|
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 (
|
|
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 (
|
|
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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"}
|
|
@@ -33,15 +33,15 @@ export declare class PostsClient {
|
|
|
33
33
|
constructor(http: Http, media: MediaClient);
|
|
34
34
|
/** Published posts. */
|
|
35
35
|
list(q?: PostQuery, signal?: AbortSignal): Promise<Post[]>;
|
|
36
|
-
/** Every post for staff: drafts, scheduled, held and rejected ones included; deleted ones on their own; q searches (
|
|
36
|
+
/** Every post for staff: drafts, scheduled, held and rejected ones included; deleted ones on their own; q searches (root:posts:write). */
|
|
37
37
|
adminList(q?: PostAdminQuery, signal?: AbortSignal): Promise<Post[]>;
|
|
38
38
|
get(id: string, signal?: AbortSignal): Promise<Post>;
|
|
39
|
-
/** Creates a post (
|
|
39
|
+
/** Creates a post (root:posts:write); moderation "held" when the moderator holds it. */
|
|
40
40
|
create(input: PostInput): Promise<Post>;
|
|
41
|
-
/** Updates the given fields (
|
|
41
|
+
/** Updates the given fields (root:posts:write). */
|
|
42
42
|
update(id: string, input: PostInput): Promise<Post>;
|
|
43
43
|
delete(id: string): Promise<void>;
|
|
44
|
-
/** Restores a deleted post as it was (
|
|
44
|
+
/** Restores a deleted post as it was (root:posts:write); conflict when a live post took its slug. */
|
|
45
45
|
restore(id: string): Promise<Post>;
|
|
46
46
|
/** Sets the cover to an inline image name ("i-{uuid}") of the post's folder, or clears it; resolves with its public URL (null until it has one). */
|
|
47
47
|
setCover(id: string, image: string | null): Promise<string | null>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"posts.js","names":[],"sources":["../../../src/client/content/posts.ts"],"sourcesContent":["import type { InlineImage, Post, PostCover, PostInput } 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\";\nimport type { Sort } from \"./types.js\";\n\n/** The URL scheme of an image reference in a post body. */\nexport const IMAGE_SCHEME = \"contentkit:\";\n\n/**\n * The reference a post body stores for one of its images, by name\n * (\"contentkit:i-{uuid}\"), where the image's URL would go: reads resolve it to\n * the image's current public file (`Post.images`).\n */\nexport const imageRef = (name: string) => IMAGE_SCHEME + name;\n\n/** Matches every image reference; the name is group 1. */\nexport const imageRefs = () => /contentkit:(i-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/g;\n\nexport interface PostQuery extends PageQuery {\n language?: string;\n sort?: Sort;\n}\n\nexport interface PostAdminQuery extends PageQuery {\n language?: string;\n /** true: only drafts; false: only posts that are not drafts. */\n draft?: boolean;\n /** true: only deleted posts (with deleted_at); otherwise only live ones. */\n deleted?: boolean;\n /** Only posts whose title, excerpt or body contains this text, ignoring case. */\n q?: string;\n}\n\n/** Posts: the published list, staff CRUD, search and restore, reactions, the cover and body images. */\nexport class PostsClient {\n constructor(\n private readonly http: Http,\n private readonly media: MediaClient,\n ) {}\n\n /** Published posts. */\n list(q: PostQuery = {}, signal?: AbortSignal): Promise<Post[]> {\n return call(this.http, \"GET\", \"/posts\", { query: q, signal });\n }\n /** Every post for staff: drafts, scheduled, held and rejected ones included; deleted ones on their own; q searches (
|
|
1
|
+
{"version":3,"file":"posts.js","names":[],"sources":["../../../src/client/content/posts.ts"],"sourcesContent":["import type { InlineImage, Post, PostCover, PostInput } 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\";\nimport type { Sort } from \"./types.js\";\n\n/** The URL scheme of an image reference in a post body. */\nexport const IMAGE_SCHEME = \"contentkit:\";\n\n/**\n * The reference a post body stores for one of its images, by name\n * (\"contentkit:i-{uuid}\"), where the image's URL would go: reads resolve it to\n * the image's current public file (`Post.images`).\n */\nexport const imageRef = (name: string) => IMAGE_SCHEME + name;\n\n/** Matches every image reference; the name is group 1. */\nexport const imageRefs = () => /contentkit:(i-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/g;\n\nexport interface PostQuery extends PageQuery {\n language?: string;\n sort?: Sort;\n}\n\nexport interface PostAdminQuery extends PageQuery {\n language?: string;\n /** true: only drafts; false: only posts that are not drafts. */\n draft?: boolean;\n /** true: only deleted posts (with deleted_at); otherwise only live ones. */\n deleted?: boolean;\n /** Only posts whose title, excerpt or body contains this text, ignoring case. */\n q?: string;\n}\n\n/** Posts: the published list, staff CRUD, search and restore, reactions, the cover and body images. */\nexport class PostsClient {\n constructor(\n private readonly http: Http,\n private readonly media: MediaClient,\n ) {}\n\n /** Published posts. */\n list(q: PostQuery = {}, signal?: AbortSignal): Promise<Post[]> {\n return call(this.http, \"GET\", \"/posts\", { query: q, signal });\n }\n /** Every post for staff: drafts, scheduled, held and rejected ones included; deleted ones on their own; q searches (root:posts:write). */\n adminList(q: PostAdminQuery = {}, signal?: AbortSignal): Promise<Post[]> {\n return call(this.http, \"GET\", \"/posts/admin\", { query: q, signal });\n }\n get(id: string, signal?: AbortSignal): Promise<Post> {\n return call(this.http, \"GET\", \"/posts/{id}\", { params: { id }, signal });\n }\n /** Creates a post (root:posts:write); moderation \"held\" when the moderator holds it. */\n async create(input: PostInput): Promise<Post> {\n const emit = this.http.captureChanges();\n const post: Post = await call(this.http, \"POST\", \"/posts\", { body: input });\n emit({ type: \"post.created\", post });\n return post;\n }\n /** Updates the given fields (root:posts:write). */\n async update(id: string, input: PostInput): Promise<Post> {\n const emit = this.http.captureChanges();\n const post: Post = await call(this.http, \"PATCH\", \"/posts/{id}\", { params: { id }, body: input });\n emit({ type: \"post.updated\", post });\n return post;\n }\n async delete(id: string): Promise<void> {\n const emit = this.http.captureChanges();\n await call(this.http, \"DELETE\", \"/posts/{id}\", { params: { id } });\n emit({ type: \"post.deleted\", id });\n }\n /** Restores a deleted post as it was (root:posts:write); conflict when a live post took its slug. */\n async restore(id: string): Promise<Post> {\n const emit = this.http.captureChanges();\n const post: Post = await call(this.http, \"POST\", \"/posts/{id}/restore\", { params: { id } });\n emit({ type: \"post.restored\", post });\n return post;\n }\n /** Sets the cover to an inline image name (\"i-{uuid}\") of the post's folder, or clears it; resolves with its public URL (null until it has one). */\n async setCover(id: string, image: string | null): Promise<string | null> {\n const emit = this.http.captureChanges();\n const r: PostCover = await call(this.http, \"PUT\", \"/posts/{id}/cover\", { params: { id }, body: { image: image ?? \"\" } });\n emit({ type: \"post.changed\", id });\n return r.cover_url;\n }\n /** Uploads file to the post's folder and makes it the cover (null clears it); resolves with its public URL (null until it has one). */\n async uploadCover(id: string, file: Blob | null, o?: NamedOptions): Promise<string | null> {\n if (!file) return this.setCover(id, null);\n const up = await this.media.uploadNamed(this.media.postRef(id), file, o);\n return this.setCover(id, up.name);\n }\n /** An inline image of the post's folder: the reference to store in its body and a URL that shows it to the editor now (null while none exists). */\n inlineImage(id: string, image: string, signal?: AbortSignal): Promise<InlineImage> {\n return call(this.http, \"POST\", \"/posts/{id}/images\", { params: { id }, body: { image }, signal });\n }\n}\n"],"mappings":";;AAOA,IAAa,IAAe,eAOf,KAAY,MAAiB,IAAe,GAG5C,UAAkB,gFAkBlB,IAAb,MAAyB;CAEJ;CACA;CAFnB,YACE,GACA,GACA;EADiB,AADA,KAAA,OAAA,GACA,KAAA,QAAA;CAChB;CAGH,KAAK,IAAe,CAAC,GAAG,GAAuC;EAC7D,OAAO,EAAK,KAAK,MAAM,OAAO,UAAU;GAAE,OAAO;GAAG;EAAO,CAAC;CAC9D;CAEA,UAAU,IAAoB,CAAC,GAAG,GAAuC;EACvE,OAAO,EAAK,KAAK,MAAM,OAAO,gBAAgB;GAAE,OAAO;GAAG;EAAO,CAAC;CACpE;CACA,IAAI,GAAY,GAAqC;EACnD,OAAO,EAAK,KAAK,MAAM,OAAO,eAAe;GAAE,QAAQ,EAAE,MAAG;GAAG;EAAO,CAAC;CACzE;CAEA,MAAM,OAAO,GAAiC;EAC5C,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAa,MAAM,EAAK,KAAK,MAAM,QAAQ,UAAU,EAAE,MAAM,EAAM,CAAC;EAE1E,OADA,EAAK;GAAE,MAAM;GAAgB;EAAK,CAAC,GAC5B;CACT;CAEA,MAAM,OAAO,GAAY,GAAiC;EACxD,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAa,MAAM,EAAK,KAAK,MAAM,SAAS,eAAe;GAAE,QAAQ,EAAE,MAAG;GAAG,MAAM;EAAM,CAAC;EAEhG,OADA,EAAK;GAAE,MAAM;GAAgB;EAAK,CAAC,GAC5B;CACT;CACA,MAAM,OAAO,GAA2B;EACtC,IAAM,IAAO,KAAK,KAAK,eAAe;EAEtC,AADA,MAAM,EAAK,KAAK,MAAM,UAAU,eAAe,EAAE,QAAQ,EAAE,MAAG,EAAE,CAAC,GACjE,EAAK;GAAE,MAAM;GAAgB;EAAG,CAAC;CACnC;CAEA,MAAM,QAAQ,GAA2B;EACvC,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAa,MAAM,EAAK,KAAK,MAAM,QAAQ,uBAAuB,EAAE,QAAQ,EAAE,MAAG,EAAE,CAAC;EAE1F,OADA,EAAK;GAAE,MAAM;GAAiB;EAAK,CAAC,GAC7B;CACT;CAEA,MAAM,SAAS,GAAY,GAA8C;EACvE,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAe,MAAM,EAAK,KAAK,MAAM,OAAO,qBAAqB;GAAE,QAAQ,EAAE,MAAG;GAAG,MAAM,EAAE,OAAO,KAAS,GAAG;EAAE,CAAC;EAEvH,OADA,EAAK;GAAE,MAAM;GAAgB;EAAG,CAAC,GAC1B,EAAE;CACX;CAEA,MAAM,YAAY,GAAY,GAAmB,GAA0C;EACzF,IAAI,CAAC,GAAM,OAAO,KAAK,SAAS,GAAI,IAAI;EACxC,IAAM,IAAK,MAAM,KAAK,MAAM,YAAY,KAAK,MAAM,QAAQ,CAAE,GAAG,GAAM,CAAC;EACvE,OAAO,KAAK,SAAS,GAAI,EAAG,IAAI;CAClC;CAEA,YAAY,GAAY,GAAe,GAA4C;EACjF,OAAO,EAAK,KAAK,MAAM,QAAQ,sBAAsB;GAAE,QAAQ,EAAE,MAAG;GAAG,MAAM,EAAE,SAAM;GAAG;EAAO,CAAC;CAClG;AACF"}
|
|
@@ -102,11 +102,11 @@ var e = {
|
|
|
102
102
|
},
|
|
103
103
|
unauthorized: {
|
|
104
104
|
status: 401,
|
|
105
|
-
meaning: "The
|
|
105
|
+
meaning: "The request needs a valid credential: it has none where the route needs one, or one that is expired, revoked or invalid. WWW-Authenticate says which."
|
|
106
106
|
},
|
|
107
107
|
unavailable: {
|
|
108
108
|
status: 503,
|
|
109
|
-
meaning: "
|
|
109
|
+
meaning: "The host's auth or media storage cannot be reached, or a commit's recovery is pending; retry."
|
|
110
110
|
},
|
|
111
111
|
upgrade_required: {
|
|
112
112
|
status: 503,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"error-codes.js","names":[],"sources":["../../../src/client/generated/error-codes.ts"],"sourcesContent":["// Generated by `go generate ./internal/contract` from ContentKit's error-code registry. Do not edit.\n\nexport type ErrorCode =\n | \"animation_not_allowed\"\n | \"animation_too_long\"\n | \"animation_unsupported\"\n | \"checksum_mismatch\"\n | \"comment_banned\"\n | \"comment_too_long\"\n | \"conflict\"\n | \"forbidden\"\n | \"gone\"\n | \"image_too_large\"\n | \"image_too_small\"\n | \"image_unreadable\"\n | \"incomplete\"\n | \"internal_error\"\n | \"invalid_request\"\n | \"moderation_rejected\"\n | \"not_configured\"\n | \"not_found\"\n | \"not_uploaded\"\n | \"quota_exceeded\"\n | \"rate_limited\"\n | \"tenant_mismatch\"\n | \"too_large\"\n | \"too_many_files\"\n | \"type_not_allowed\"\n | \"unauthorized\"\n | \"unavailable\"\n | \"upgrade_required\"\n | \"video_aspect_unsupported\"\n | \"video_over_budget\"\n | \"video_too_large\"\n | \"video_too_long\"\n;\n\n// Each code's HTTP status and meaning. A message on the wire is for people;\n// classify by code.\nexport const CONTENTKIT_ERROR_CODES: Readonly<Record<ErrorCode, { status: number; meaning: string }>> = {\n animation_not_allowed: { status: 422, meaning: \"An animated image where the upload path refuses animation.\" },\n animation_too_long: { status: 422, meaning: \"The animation has more frames or seconds than the processor allows.\" },\n animation_unsupported: { status: 415, meaning: \"An AVIF or HEIF image sequence, which is decoded as one frame.\" },\n checksum_mismatch: { status: 422, meaning: \"The stored bytes differ from the declared SHA-256.\" },\n comment_banned: { status: 403, meaning: \"The actor is banned from commenting on this target; `ban` says the scope, the reason and when it ends.\" },\n comment_too_long: { status: 422, meaning: \"The comment is longer than the site allows; `details.max` is the limit in characters.\" },\n conflict: { status: 409, meaning: \"A concurrent change, a path or slug already taken, or an operation id already used for another commit.\" },\n forbidden: { status: 403, meaning: \"The actor may not do this.\" },\n gone: { status: 410, meaning: \"The content was removed.\" },\n image_too_large: { status: 413, meaning: \"The image has more pixels or frames than the processor decodes.\" },\n image_too_small: { status: 422, meaning: \"The edited image is narrower than its public preset's minimum width.\" },\n image_unreadable: { status: 422, meaning: \"The file is not a decodable image of its declared type.\" },\n incomplete: { status: 409, meaning: \"A multipart upload is missing parts.\" },\n internal_error: { status: 500, meaning: \"A server fault; the cause is in the server log.\" },\n invalid_request: { status: 400, meaning: \"The request is malformed: its body, a query parameter or a path value.\" },\n moderation_rejected: { status: 422, meaning: \"The moderator refused the text; `error` says why.\" },\n not_configured: { status: 501, meaning: \"The capability needs a port the host did not configure; retrying does not help.\" },\n not_found: { status: 404, meaning: \"Nothing by that name, or nothing the actor may see.\" },\n not_uploaded: { status: 409, meaning: \"A commit names an upload that has not landed; `blobs` lists the ones to upload again.\" },\n quota_exceeded: { status: 413, meaning: \"The uploader's storage quota is used up.\" },\n rate_limited: { status: 429, meaning: \"Too many requests; retry after `retry_after` seconds (also the Retry-After header).\" },\n tenant_mismatch: { status: 500, meaning: \"A host port answered with another tenant's data: a configuration fault.\" },\n too_large: { status: 413, meaning: \"The file is larger than its upload path allows; `details` has `size` and `max_bytes`.\" },\n too_many_files: { status: 409, meaning: \"The commit would put more files in an upload path, or the item, than allowed; `details.max` is the limit.\" },\n type_not_allowed: { status: 415, meaning: \"The file type is not allowed in the upload path; `details.allowed` lists the types.\" },\n unauthorized: { status: 401, meaning: \"The
|
|
1
|
+
{"version":3,"file":"error-codes.js","names":[],"sources":["../../../src/client/generated/error-codes.ts"],"sourcesContent":["// Generated by `go generate ./internal/contract` from ContentKit's error-code registry. Do not edit.\n\nexport type ErrorCode =\n | \"animation_not_allowed\"\n | \"animation_too_long\"\n | \"animation_unsupported\"\n | \"checksum_mismatch\"\n | \"comment_banned\"\n | \"comment_too_long\"\n | \"conflict\"\n | \"forbidden\"\n | \"gone\"\n | \"image_too_large\"\n | \"image_too_small\"\n | \"image_unreadable\"\n | \"incomplete\"\n | \"internal_error\"\n | \"invalid_request\"\n | \"moderation_rejected\"\n | \"not_configured\"\n | \"not_found\"\n | \"not_uploaded\"\n | \"quota_exceeded\"\n | \"rate_limited\"\n | \"tenant_mismatch\"\n | \"too_large\"\n | \"too_many_files\"\n | \"type_not_allowed\"\n | \"unauthorized\"\n | \"unavailable\"\n | \"upgrade_required\"\n | \"video_aspect_unsupported\"\n | \"video_over_budget\"\n | \"video_too_large\"\n | \"video_too_long\"\n;\n\n// Each code's HTTP status and meaning. A message on the wire is for people;\n// classify by code.\nexport const CONTENTKIT_ERROR_CODES: Readonly<Record<ErrorCode, { status: number; meaning: string }>> = {\n animation_not_allowed: { status: 422, meaning: \"An animated image where the upload path refuses animation.\" },\n animation_too_long: { status: 422, meaning: \"The animation has more frames or seconds than the processor allows.\" },\n animation_unsupported: { status: 415, meaning: \"An AVIF or HEIF image sequence, which is decoded as one frame.\" },\n checksum_mismatch: { status: 422, meaning: \"The stored bytes differ from the declared SHA-256.\" },\n comment_banned: { status: 403, meaning: \"The actor is banned from commenting on this target; `ban` says the scope, the reason and when it ends.\" },\n comment_too_long: { status: 422, meaning: \"The comment is longer than the site allows; `details.max` is the limit in characters.\" },\n conflict: { status: 409, meaning: \"A concurrent change, a path or slug already taken, or an operation id already used for another commit.\" },\n forbidden: { status: 403, meaning: \"The actor may not do this.\" },\n gone: { status: 410, meaning: \"The content was removed.\" },\n image_too_large: { status: 413, meaning: \"The image has more pixels or frames than the processor decodes.\" },\n image_too_small: { status: 422, meaning: \"The edited image is narrower than its public preset's minimum width.\" },\n image_unreadable: { status: 422, meaning: \"The file is not a decodable image of its declared type.\" },\n incomplete: { status: 409, meaning: \"A multipart upload is missing parts.\" },\n internal_error: { status: 500, meaning: \"A server fault; the cause is in the server log.\" },\n invalid_request: { status: 400, meaning: \"The request is malformed: its body, a query parameter or a path value.\" },\n moderation_rejected: { status: 422, meaning: \"The moderator refused the text; `error` says why.\" },\n not_configured: { status: 501, meaning: \"The capability needs a port the host did not configure; retrying does not help.\" },\n not_found: { status: 404, meaning: \"Nothing by that name, or nothing the actor may see.\" },\n not_uploaded: { status: 409, meaning: \"A commit names an upload that has not landed; `blobs` lists the ones to upload again.\" },\n quota_exceeded: { status: 413, meaning: \"The uploader's storage quota is used up.\" },\n rate_limited: { status: 429, meaning: \"Too many requests; retry after `retry_after` seconds (also the Retry-After header).\" },\n tenant_mismatch: { status: 500, meaning: \"A host port answered with another tenant's data: a configuration fault.\" },\n too_large: { status: 413, meaning: \"The file is larger than its upload path allows; `details` has `size` and `max_bytes`.\" },\n too_many_files: { status: 409, meaning: \"The commit would put more files in an upload path, or the item, than allowed; `details.max` is the limit.\" },\n type_not_allowed: { status: 415, meaning: \"The file type is not allowed in the upload path; `details.allowed` lists the types.\" },\n unauthorized: { status: 401, meaning: \"The request needs a valid credential: it has none where the route needs one, or one that is expired, revoked or invalid. WWW-Authenticate says which.\" },\n unavailable: { status: 503, meaning: \"The host's auth or media storage cannot be reached, or a commit's recovery is pending; retry.\" },\n upgrade_required: { status: 503, meaning: \"The media item was stored before v0.68 and is served once the host's media upgrade (contentkit_media_upgrade) has converted it.\" },\n video_aspect_unsupported: { status: 422, meaning: \"The video's display aspect is outside what its upload path accepts; `details` has `min_aspect` and `max_aspect` (width/height).\" },\n video_over_budget: { status: 422, meaning: \"The planned encode costs more than its upload path allows, or the source averages under a frame a second.\" },\n video_too_large: { status: 422, meaning: \"The video's frames are larger than its upload path allows.\" },\n video_too_long: { status: 422, meaning: \"The video or audio runs longer than its upload path allows.\" },\n};\n"],"mappings":";AAuCA,IAAa,IAA2F;CACtG,uBAAuB;EAAE,QAAQ;EAAK,SAAS;CAA6D;CAC5G,oBAAoB;EAAE,QAAQ;EAAK,SAAS;CAAsE;CAClH,uBAAuB;EAAE,QAAQ;EAAK,SAAS;CAAiE;CAChH,mBAAmB;EAAE,QAAQ;EAAK,SAAS;CAAqD;CAChG,gBAAgB;EAAE,QAAQ;EAAK,SAAS;CAAyG;CACjJ,kBAAkB;EAAE,QAAQ;EAAK,SAAS;CAAwF;CAClI,UAAU;EAAE,QAAQ;EAAK,SAAS;CAAyG;CAC3I,WAAW;EAAE,QAAQ;EAAK,SAAS;CAA6B;CAChE,MAAM;EAAE,QAAQ;EAAK,SAAS;CAA2B;CACzD,iBAAiB;EAAE,QAAQ;EAAK,SAAS;CAAkE;CAC3G,iBAAiB;EAAE,QAAQ;EAAK,SAAS;CAAuE;CAChH,kBAAkB;EAAE,QAAQ;EAAK,SAAS;CAA0D;CACpG,YAAY;EAAE,QAAQ;EAAK,SAAS;CAAuC;CAC3E,gBAAgB;EAAE,QAAQ;EAAK,SAAS;CAAkD;CAC1F,iBAAiB;EAAE,QAAQ;EAAK,SAAS;CAAyE;CAClH,qBAAqB;EAAE,QAAQ;EAAK,SAAS;CAAoD;CACjG,gBAAgB;EAAE,QAAQ;EAAK,SAAS;CAAkF;CAC1H,WAAW;EAAE,QAAQ;EAAK,SAAS;CAAsD;CACzF,cAAc;EAAE,QAAQ;EAAK,SAAS;CAAwF;CAC9H,gBAAgB;EAAE,QAAQ;EAAK,SAAS;CAA2C;CACnF,cAAc;EAAE,QAAQ;EAAK,SAAS;CAAsF;CAC5H,iBAAiB;EAAE,QAAQ;EAAK,SAAS;CAA0E;CACnH,WAAW;EAAE,QAAQ;EAAK,SAAS;CAAwF;CAC3H,gBAAgB;EAAE,QAAQ;EAAK,SAAS;CAA4G;CACpJ,kBAAkB;EAAE,QAAQ;EAAK,SAAS;CAAsF;CAChI,cAAc;EAAE,QAAQ;EAAK,SAAS;CAAwJ;CAC9L,aAAa;EAAE,QAAQ;EAAK,SAAS;CAAgG;CACrI,kBAAkB;EAAE,QAAQ;EAAK,SAAS;CAAkI;CAC5K,0BAA0B;EAAE,QAAQ;EAAK,SAAS;CAAkI;CACpL,mBAAmB;EAAE,QAAQ;EAAK,SAAS;CAA4G;CACvJ,iBAAiB;EAAE,QAAQ;EAAK,SAAS;CAA6D;CACtG,gBAAgB;EAAE,QAAQ;EAAK,SAAS;CAA8D;AACxG"}
|