@openrails/contentkit-ui 0.69.0 → 0.70.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 +17 -13
- package/dist/client/content/comments.js +3 -3
- package/dist/client/content/comments.js.map +1 -1
- package/dist/client/content/posts.d.ts +16 -8
- package/dist/client/content/posts.js +5 -13
- package/dist/client/content/posts.js.map +1 -1
- package/dist/client/content/reactions.js +4 -4
- package/dist/client/content/reactions.js.map +1 -1
- package/dist/client/content/types.d.ts +2 -2
- package/dist/client/content/types.js +1 -1
- package/dist/client/content/types.js.map +1 -1
- package/dist/client/generated/routes.d.ts +2 -54
- package/dist/client/generated/routes.js +2 -74
- package/dist/client/generated/routes.js.map +1 -1
- package/dist/client/generated/wire.d.ts +5 -1
- package/dist/client/generated/wire.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/media/client.d.ts +7 -5
- package/dist/client/media/client.js +1 -1
- package/dist/client/media/client.js.map +1 -1
- package/dist/client/media/rules.d.ts +2 -2
- package/dist/client/media/rules.js +1 -5
- package/dist/client/media/rules.js.map +1 -1
- package/dist/client.js +5 -5
- package/dist/react/posts.d.ts +9 -7
- package/dist/react/posts.js +132 -99
- package/dist/react/posts.js.map +1 -1
- package/dist/react/public.d.ts +2 -2
- package/dist/react/public.js +7 -4
- package/dist/react/public.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -88,11 +88,14 @@ operation. This does not change the operation's result or its authentication.
|
|
|
88
88
|
`comments.adminList`.
|
|
89
89
|
- **Images of posts and polls** go to the item's server-named upload path:
|
|
90
90
|
`media.uploadNamed(ref, file)` resolves the name content routes take;
|
|
91
|
-
`media.uploadInline(postId, file)` resolves a body image's
|
|
92
|
-
`
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
91
|
+
`media.uploadInline(postId, file)` resolves a body image's reference
|
|
92
|
+
(`ref`, `contentkit:i-{uuid}`, what the body stores: `imageRef(name)`) and
|
|
93
|
+
a URL that shows it now; `posts.uploadCover`, `polls.uploadImage` and
|
|
94
|
+
`polls.uploadOptionImage` do both steps. Reads resolve references: a
|
|
95
|
+
post's `body` shows the images' current public files and `images` maps
|
|
96
|
+
each name to its URL. `folders` renames the post and poll media kinds. A
|
|
97
|
+
post's public image files exist only while it is published; `usePost`
|
|
98
|
+
shows an unpublished post's images to its editors (below).
|
|
96
99
|
- **`client.config()`** says what the content module allows: which
|
|
97
100
|
interactions signed-out visitors may make (`content.Options.Anonymous`,
|
|
98
101
|
none by default) and the longest comment (`CommentMaxLength`, 2,200 by
|
|
@@ -142,15 +145,15 @@ const editor = usePollEditor(pollId); // staff
|
|
|
142
145
|
|
|
143
146
|
A post editor puts `editorBody` in its rich-text field and inserts what
|
|
144
147
|
`uploadImage(file)` resolves: URLs that show the images now (the file for a
|
|
145
|
-
fresh upload, signed editor views of an unpublished post's
|
|
146
|
-
refreshed as needed). `update({ body })` stores
|
|
147
|
-
(`storedBody(html)` does the same for a
|
|
148
|
-
the cover.
|
|
148
|
+
fresh upload, public files, signed editor views of an unpublished post's
|
|
149
|
+
images, read and refreshed as needed). `update({ body })` stores each of
|
|
150
|
+
those URLs as the image's reference (`storedBody(html)` does the same for a
|
|
151
|
+
host's own save); `coverSrc` shows the cover, `imageSrc(name)` any image.
|
|
149
152
|
|
|
150
153
|
```tsx
|
|
151
154
|
const editor = usePost(postId);
|
|
152
155
|
<RichText value={editor.editorBody} onImage={editor.uploadImage} onSave={(html) => editor.update({ body: html })} />
|
|
153
|
-
<img src={editor.
|
|
156
|
+
<img src={editor.coverSrc} alt="" />
|
|
154
157
|
```
|
|
155
158
|
|
|
156
159
|
Also `useContentConfig` (`client.config()`, read once), `useCommentReplies`,
|
|
@@ -226,9 +229,10 @@ const { image, rule, isDefault } = usePublicImage("user", userId, "avatar");
|
|
|
226
229
|
|
|
227
230
|
An item's image for a public preset: the exact renditions from a read's
|
|
228
231
|
`public`, or from a host listing passed as `image` (no read), else the
|
|
229
|
-
kind's default image
|
|
230
|
-
|
|
231
|
-
`GET /media/presets`) gives the
|
|
232
|
+
kind's default image when the preset has one (`rule.default`), else none.
|
|
233
|
+
Published files carry a generation, so a URL built from a preset template
|
|
234
|
+
only ever names the default; `rule` (from `GET /media/presets`) gives the
|
|
235
|
+
shape, widths and narrowest edit.
|
|
232
236
|
|
|
233
237
|
### useCanonicalContent
|
|
234
238
|
|
|
@@ -52,12 +52,12 @@ var n = (e) => ({
|
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
async react(n, r) {
|
|
55
|
-
let i = this.http.captureChanges(), a = await e(this.http, "POST", `/comments/{cid}/${t(r)}`, { params:
|
|
55
|
+
let i = this.http.captureChanges(), a = { cid: n }, o = r === 0 ? await e(this.http, "DELETE", "/comments/{cid}/reaction", { params: a }) : await e(this.http, "POST", `/comments/{cid}/${t(r)}`, { params: a });
|
|
56
56
|
return i({
|
|
57
57
|
type: "comment.reacted",
|
|
58
58
|
id: n,
|
|
59
|
-
counts:
|
|
60
|
-
}),
|
|
59
|
+
counts: o
|
|
60
|
+
}), o;
|
|
61
61
|
}
|
|
62
62
|
standing(t, r) {
|
|
63
63
|
return e(this.http, "GET", "/{kind}/{id}/can-comment", {
|
|
@@ -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 counts: ReactionCounts
|
|
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 (CommentModerate). */\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 (CommentModerate). */\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,8 +1,18 @@
|
|
|
1
|
-
import { Post, PostInput } from '../generated/wire.js';
|
|
1
|
+
import { InlineImage, Post, PostInput } from '../generated/wire.js';
|
|
2
2
|
import { Http } from '../http.js';
|
|
3
3
|
import { MediaClient, NamedOptions } from '../media/client.js';
|
|
4
4
|
import { PageQuery } from '../route.js';
|
|
5
|
-
import {
|
|
5
|
+
import { Sort } from './types.js';
|
|
6
|
+
/** The URL scheme of an image reference in a post body. */
|
|
7
|
+
export declare const IMAGE_SCHEME = "contentkit:";
|
|
8
|
+
/**
|
|
9
|
+
* The reference a post body stores for one of its images, by name
|
|
10
|
+
* ("contentkit:i-{uuid}"), where the image's URL would go: reads resolve it to
|
|
11
|
+
* the image's current public file (`Post.images`).
|
|
12
|
+
*/
|
|
13
|
+
export declare const imageRef: (name: string) => string;
|
|
14
|
+
/** Matches every image reference; the name is group 1. */
|
|
15
|
+
export declare const imageRefs: () => RegExp;
|
|
6
16
|
export interface PostQuery extends PageQuery {
|
|
7
17
|
language?: string;
|
|
8
18
|
sort?: Sort;
|
|
@@ -33,12 +43,10 @@ export declare class PostsClient {
|
|
|
33
43
|
delete(id: string): Promise<void>;
|
|
34
44
|
/** Restores a deleted post as it was (PostWrite); conflict when a live post took its slug. */
|
|
35
45
|
restore(id: string): Promise<Post>;
|
|
36
|
-
/** Sets the
|
|
37
|
-
react(id: string, value: Reaction): Promise<Post>;
|
|
38
|
-
/** Sets the cover to an inline image name ("i-{uuid}") of the post's folder, or clears it; resolves with its URL. */
|
|
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). */
|
|
39
47
|
setCover(id: string, image: string | null): Promise<string | null>;
|
|
40
|
-
/** Uploads file to the post's folder and makes it the cover (null clears it); resolves with its URL. */
|
|
48
|
+
/** 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). */
|
|
41
49
|
uploadCover(id: string, file: Blob | null, o?: NamedOptions): Promise<string | null>;
|
|
42
|
-
/**
|
|
43
|
-
|
|
50
|
+
/** 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). */
|
|
51
|
+
inlineImage(id: string, image: string, signal?: AbortSignal): Promise<InlineImage>;
|
|
44
52
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { call as e } from "../route.js";
|
|
2
|
-
import { reactionVerb as t } from "./types.js";
|
|
3
2
|
//#region src/client/content/posts.ts
|
|
4
|
-
var n = class {
|
|
3
|
+
var t = "contentkit:", n = (e) => t + e, r = () => /contentkit:(i-[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/g, i = class {
|
|
5
4
|
http;
|
|
6
5
|
media;
|
|
7
6
|
constructor(e, t) {
|
|
@@ -56,13 +55,6 @@ var n = class {
|
|
|
56
55
|
post: r
|
|
57
56
|
}), r;
|
|
58
57
|
}
|
|
59
|
-
async react(n, r) {
|
|
60
|
-
let i = this.http.captureChanges(), a = await e(this.http, "POST", `/posts/{id}/${t(r)}`, { params: { id: n } });
|
|
61
|
-
return i({
|
|
62
|
-
type: "post.updated",
|
|
63
|
-
post: a
|
|
64
|
-
}), a;
|
|
65
|
-
}
|
|
66
58
|
async setCover(t, n) {
|
|
67
59
|
let r = this.http.captureChanges(), i = await e(this.http, "PUT", "/posts/{id}/cover", {
|
|
68
60
|
params: { id: t },
|
|
@@ -78,15 +70,15 @@ var n = class {
|
|
|
78
70
|
let r = await this.media.uploadNamed(this.media.postRef(e), t, n);
|
|
79
71
|
return this.setCover(e, r.name);
|
|
80
72
|
}
|
|
81
|
-
|
|
82
|
-
return
|
|
73
|
+
inlineImage(t, n, r) {
|
|
74
|
+
return e(this.http, "POST", "/posts/{id}/images", {
|
|
83
75
|
params: { id: t },
|
|
84
76
|
body: { image: n },
|
|
85
77
|
signal: r
|
|
86
|
-
})
|
|
78
|
+
});
|
|
87
79
|
}
|
|
88
80
|
};
|
|
89
81
|
//#endregion
|
|
90
|
-
export {
|
|
82
|
+
export { t as IMAGE_SCHEME, i as PostsClient, n as imageRef, r as imageRefs };
|
|
91
83
|
|
|
92
84
|
//# sourceMappingURL=posts.js.map
|
|
@@ -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
|
|
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 (PostWrite). */\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 (PostWrite); 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 (PostWrite). */\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 (PostWrite); 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"}
|
|
@@ -16,18 +16,18 @@ var n = class {
|
|
|
16
16
|
});
|
|
17
17
|
}
|
|
18
18
|
async set(n, r) {
|
|
19
|
-
let i = this.http.captureChanges(), a =
|
|
19
|
+
let i = this.http.captureChanges(), a = {
|
|
20
20
|
kind: n.kind,
|
|
21
21
|
id: n.id
|
|
22
|
-
} });
|
|
22
|
+
}, o = r === 0 ? await e(this.http, "DELETE", "/{kind}/{id}/reaction", { params: a }) : await e(this.http, "POST", `/{kind}/{id}/${t(r)}`, { params: a });
|
|
23
23
|
return i({
|
|
24
24
|
type: "reaction.changed",
|
|
25
25
|
ref: {
|
|
26
26
|
kind: n.kind,
|
|
27
27
|
id: n.id
|
|
28
28
|
},
|
|
29
|
-
counts:
|
|
30
|
-
}),
|
|
29
|
+
counts: o
|
|
30
|
+
}), o;
|
|
31
31
|
}
|
|
32
32
|
};
|
|
33
33
|
//#endregion
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reactions.js","names":[],"sources":["../../../src/client/content/reactions.ts"],"sourcesContent":["import type { ReactionCounts, RefBody } from \"../generated/wire.js\";\nimport type { Http } from \"../http.js\";\nimport { call } from \"../route.js\";\nimport { reactionVerb, type Reaction } from \"./types.js\";\n\n/** Likes and dislikes of an item (a host kind, or \"post\"). */\nexport class ReactionsClient {\n constructor(private readonly http: Http) {}\n\n /** The item's counts and the caller's own reaction. */\n get(ref: RefBody, signal?: AbortSignal): Promise<ReactionCounts> {\n return call(this.http, \"GET\", \"/{kind}/{id}/reaction\", { params: { kind: ref.kind, id: ref.id }, signal });\n }\n /** Sets the caller's reaction (0 clears it); resolves with the new counts. */\n async set(ref: RefBody, value: Reaction): Promise<ReactionCounts> {\n const emit = this.http.captureChanges();\n const counts: ReactionCounts
|
|
1
|
+
{"version":3,"file":"reactions.js","names":[],"sources":["../../../src/client/content/reactions.ts"],"sourcesContent":["import type { ReactionCounts, RefBody } from \"../generated/wire.js\";\nimport type { Http } from \"../http.js\";\nimport { call } from \"../route.js\";\nimport { reactionVerb, type Reaction } from \"./types.js\";\n\n/** Likes and dislikes of an item (a host kind, or \"post\"). */\nexport class ReactionsClient {\n constructor(private readonly http: Http) {}\n\n /** The item's counts and the caller's own reaction. */\n get(ref: RefBody, signal?: AbortSignal): Promise<ReactionCounts> {\n return call(this.http, \"GET\", \"/{kind}/{id}/reaction\", { params: { kind: ref.kind, id: ref.id }, signal });\n }\n /** Sets the caller's reaction (0 clears it); resolves with the new counts. */\n async set(ref: RefBody, value: Reaction): Promise<ReactionCounts> {\n const emit = this.http.captureChanges();\n const params = { kind: ref.kind, id: ref.id };\n const counts: ReactionCounts =\n value === 0 ? await call(this.http, \"DELETE\", \"/{kind}/{id}/reaction\", { params }) : await call(this.http, \"POST\", `/{kind}/{id}/${reactionVerb(value)}` as const, { params });\n emit({ type: \"reaction.changed\", ref: { kind: ref.kind, id: ref.id }, counts });\n return counts;\n }\n}\n"],"mappings":";;;AAMA,IAAa,IAAb,MAA6B;CACE;CAA7B,YAAY,GAA6B;EAAZ,KAAA,OAAA;CAAa;CAG1C,IAAI,GAAc,GAA+C;EAC/D,OAAO,EAAK,KAAK,MAAM,OAAO,yBAAyB;GAAE,QAAQ;IAAE,MAAM,EAAI;IAAM,IAAI,EAAI;GAAG;GAAG;EAAO,CAAC;CAC3G;CAEA,MAAM,IAAI,GAAc,GAA0C;EAChE,IAAM,IAAO,KAAK,KAAK,eAAe,GAChC,IAAS;GAAE,MAAM,EAAI;GAAM,IAAI,EAAI;EAAG,GACtC,IACJ,MAAU,IAAI,MAAM,EAAK,KAAK,MAAM,UAAU,yBAAyB,EAAE,UAAO,CAAC,IAAI,MAAM,EAAK,KAAK,MAAM,QAAQ,gBAAgB,EAAa,CAAK,KAAc,EAAE,UAAO,CAAC;EAE/K,OADA,EAAK;GAAE,MAAM;GAAoB,KAAK;IAAE,MAAM,EAAI;IAAM,IAAI,EAAI;GAAG;GAAG;EAAO,CAAC,GACvE;CACT;AACF"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { CommentBan, CommentStanding, Comment, Poll, Post, ReactionCounts, RefBody, ResolveInput } from '../generated/wire.js';
|
|
2
2
|
/** A reaction: like 1, dislike -1, none 0. */
|
|
3
3
|
export type Reaction = -1 | 0 | 1;
|
|
4
|
-
/** The route verb that sets a reaction. */
|
|
5
|
-
export declare function reactionVerb(value:
|
|
4
|
+
/** The route verb that sets a like or dislike; clearing is DELETE …/reaction. */
|
|
5
|
+
export declare function reactionVerb(value: -1 | 1): "like" | "dislike";
|
|
6
6
|
/** Comment and post order: newest (the default), likes (most liked) or best (Wilson lower bound). */
|
|
7
7
|
export type Sort = "newest" | "likes" | "best";
|
|
8
8
|
/** A ban route family: "owner" bans from the caller's own content, "global" from the whole site. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","names":[],"sources":["../../../src/client/content/types.ts"],"sourcesContent":["import type { CommentBan, CommentStanding, Comment, Poll, Post, ReactionCounts, RefBody, ResolveInput } from \"../generated/wire.js\";\n\n/** A reaction: like 1, dislike -1, none 0. */\nexport type Reaction = -1 | 0 | 1;\n\n/** The route verb that sets a reaction. */\nexport function reactionVerb(value:
|
|
1
|
+
{"version":3,"file":"types.js","names":[],"sources":["../../../src/client/content/types.ts"],"sourcesContent":["import type { CommentBan, CommentStanding, Comment, Poll, Post, ReactionCounts, RefBody, ResolveInput } from \"../generated/wire.js\";\n\n/** A reaction: like 1, dislike -1, none 0. */\nexport type Reaction = -1 | 0 | 1;\n\n/** The route verb that sets a like or dislike; clearing is DELETE …/reaction. */\nexport function reactionVerb(value: -1 | 1): \"like\" | \"dislike\" {\n return value === 1 ? \"like\" : \"dislike\";\n}\n\n/** Comment and post order: newest (the default), likes (most liked) or best (Wilson lower bound). */\nexport type Sort = \"newest\" | \"likes\" | \"best\";\n\n/** A ban route family: \"owner\" bans from the caller's own content, \"global\" from the whole site. */\nexport type BanScope = CommentStanding[\"ban_scopes\"][number];\n\n/** What the review queue holds. */\nexport type HeldKind = \"comment\" | \"post\";\n\n/** A reviewer's decision on a held item. */\nexport type Decision = Exclude<ResolveInput[\"decision\"], \"review\">;\n\n/** A content-module mutation made through the client. */\nexport type ContentChange =\n | { type: \"post.created\"; post: Post }\n | { type: \"post.updated\"; post: Post }\n /** The cover changed: refetch the post. */\n | { type: \"post.changed\"; id: string }\n | { type: \"post.deleted\"; id: string }\n | { type: \"post.restored\"; post: Post }\n /** ref is the commented item. */\n | { type: \"comment.created\"; ref: RefBody; comment: Comment }\n | { type: \"comment.updated\"; comment: Comment }\n | { type: \"comment.deleted\"; id: string }\n | { type: \"comment.restored\"; id: string }\n | { type: \"comment.reacted\"; id: string; counts: ReactionCounts }\n | { type: \"reaction.changed\"; ref: RefBody; counts: ReactionCounts }\n | { type: \"favorite.changed\"; ref: RefBody; favorited: boolean; count: number }\n /** Created, updated, voted or answered: the poll as the server now answers it. */\n | { type: \"poll.created\"; poll: Poll }\n | { type: \"poll.updated\"; poll: Poll }\n /** An option or image changed: refetch the poll. */\n | { type: \"poll.changed\"; id: string }\n | { type: \"poll.deleted\"; id: string }\n | { type: \"ban.saved\"; scope: BanScope; ban: CommentBan }\n | { type: \"ban.lifted\"; scope: BanScope; user: string }\n | { type: \"moderation.resolved\"; kind: HeldKind; id: string; decision: Decision }\n | { type: \"taxonomy.changed\" };\n"],"mappings":";AAMA,SAAgB,EAAa,GAAmC;CAC9D,OAAO,MAAU,IAAI,SAAS;AAChC"}
|
|
@@ -118,45 +118,6 @@ export declare const CONTENTKIT_ROUTES: readonly [{
|
|
|
118
118
|
};
|
|
119
119
|
readonly errors: readonly ["conflict", "not_found"];
|
|
120
120
|
readonly errorSets: readonly ["module:content", "tier:staff", "request"];
|
|
121
|
-
}, {
|
|
122
|
-
readonly method: "POST";
|
|
123
|
-
readonly module: "content";
|
|
124
|
-
readonly path: "/posts/{id}/like";
|
|
125
|
-
readonly auth: "public";
|
|
126
|
-
readonly permission: null;
|
|
127
|
-
readonly query: readonly [];
|
|
128
|
-
readonly request: null;
|
|
129
|
-
readonly responses: {
|
|
130
|
-
readonly 200: "Post";
|
|
131
|
-
};
|
|
132
|
-
readonly errors: readonly ["forbidden", "invalid_request", "not_found", "rate_limited", "unauthorized"];
|
|
133
|
-
readonly errorSets: readonly ["module:content", "request"];
|
|
134
|
-
}, {
|
|
135
|
-
readonly method: "POST";
|
|
136
|
-
readonly module: "content";
|
|
137
|
-
readonly path: "/posts/{id}/dislike";
|
|
138
|
-
readonly auth: "public";
|
|
139
|
-
readonly permission: null;
|
|
140
|
-
readonly query: readonly [];
|
|
141
|
-
readonly request: null;
|
|
142
|
-
readonly responses: {
|
|
143
|
-
readonly 200: "Post";
|
|
144
|
-
};
|
|
145
|
-
readonly errors: readonly ["forbidden", "invalid_request", "not_found", "rate_limited", "unauthorized"];
|
|
146
|
-
readonly errorSets: readonly ["module:content", "request"];
|
|
147
|
-
}, {
|
|
148
|
-
readonly method: "POST";
|
|
149
|
-
readonly module: "content";
|
|
150
|
-
readonly path: "/posts/{id}/neutral";
|
|
151
|
-
readonly auth: "public";
|
|
152
|
-
readonly permission: null;
|
|
153
|
-
readonly query: readonly [];
|
|
154
|
-
readonly request: null;
|
|
155
|
-
readonly responses: {
|
|
156
|
-
readonly 200: "Post";
|
|
157
|
-
};
|
|
158
|
-
readonly errors: readonly ["forbidden", "invalid_request", "not_found", "rate_limited", "unauthorized"];
|
|
159
|
-
readonly errorSets: readonly ["module:content", "request"];
|
|
160
121
|
}, {
|
|
161
122
|
readonly method: "PUT";
|
|
162
123
|
readonly module: "content";
|
|
@@ -316,9 +277,9 @@ export declare const CONTENTKIT_ROUTES: readonly [{
|
|
|
316
277
|
readonly errors: readonly ["forbidden", "invalid_request", "not_found", "rate_limited", "unauthorized"];
|
|
317
278
|
readonly errorSets: readonly ["module:content", "request"];
|
|
318
279
|
}, {
|
|
319
|
-
readonly method: "
|
|
280
|
+
readonly method: "DELETE";
|
|
320
281
|
readonly module: "content";
|
|
321
|
-
readonly path: "/comments/{cid}/
|
|
282
|
+
readonly path: "/comments/{cid}/reaction";
|
|
322
283
|
readonly auth: "public";
|
|
323
284
|
readonly permission: null;
|
|
324
285
|
readonly query: readonly [];
|
|
@@ -354,19 +315,6 @@ export declare const CONTENTKIT_ROUTES: readonly [{
|
|
|
354
315
|
};
|
|
355
316
|
readonly errors: readonly ["forbidden", "invalid_request", "not_found", "rate_limited", "unauthorized"];
|
|
356
317
|
readonly errorSets: readonly ["module:content", "request"];
|
|
357
|
-
}, {
|
|
358
|
-
readonly method: "POST";
|
|
359
|
-
readonly module: "content";
|
|
360
|
-
readonly path: "/{kind}/{id}/neutral";
|
|
361
|
-
readonly auth: "public";
|
|
362
|
-
readonly permission: null;
|
|
363
|
-
readonly query: readonly [];
|
|
364
|
-
readonly request: null;
|
|
365
|
-
readonly responses: {
|
|
366
|
-
readonly 200: "ReactionCounts";
|
|
367
|
-
};
|
|
368
|
-
readonly errors: readonly ["forbidden", "invalid_request", "not_found", "rate_limited", "unauthorized"];
|
|
369
|
-
readonly errorSets: readonly ["module:content", "request"];
|
|
370
318
|
}, {
|
|
371
319
|
readonly method: "DELETE";
|
|
372
320
|
readonly module: "content";
|
|
@@ -143,60 +143,6 @@ var e = [
|
|
|
143
143
|
"request"
|
|
144
144
|
]
|
|
145
145
|
},
|
|
146
|
-
{
|
|
147
|
-
method: "POST",
|
|
148
|
-
module: "content",
|
|
149
|
-
path: "/posts/{id}/like",
|
|
150
|
-
auth: "public",
|
|
151
|
-
permission: null,
|
|
152
|
-
query: [],
|
|
153
|
-
request: null,
|
|
154
|
-
responses: { 200: "Post" },
|
|
155
|
-
errors: [
|
|
156
|
-
"forbidden",
|
|
157
|
-
"invalid_request",
|
|
158
|
-
"not_found",
|
|
159
|
-
"rate_limited",
|
|
160
|
-
"unauthorized"
|
|
161
|
-
],
|
|
162
|
-
errorSets: ["module:content", "request"]
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
method: "POST",
|
|
166
|
-
module: "content",
|
|
167
|
-
path: "/posts/{id}/dislike",
|
|
168
|
-
auth: "public",
|
|
169
|
-
permission: null,
|
|
170
|
-
query: [],
|
|
171
|
-
request: null,
|
|
172
|
-
responses: { 200: "Post" },
|
|
173
|
-
errors: [
|
|
174
|
-
"forbidden",
|
|
175
|
-
"invalid_request",
|
|
176
|
-
"not_found",
|
|
177
|
-
"rate_limited",
|
|
178
|
-
"unauthorized"
|
|
179
|
-
],
|
|
180
|
-
errorSets: ["module:content", "request"]
|
|
181
|
-
},
|
|
182
|
-
{
|
|
183
|
-
method: "POST",
|
|
184
|
-
module: "content",
|
|
185
|
-
path: "/posts/{id}/neutral",
|
|
186
|
-
auth: "public",
|
|
187
|
-
permission: null,
|
|
188
|
-
query: [],
|
|
189
|
-
request: null,
|
|
190
|
-
responses: { 200: "Post" },
|
|
191
|
-
errors: [
|
|
192
|
-
"forbidden",
|
|
193
|
-
"invalid_request",
|
|
194
|
-
"not_found",
|
|
195
|
-
"rate_limited",
|
|
196
|
-
"unauthorized"
|
|
197
|
-
],
|
|
198
|
-
errorSets: ["module:content", "request"]
|
|
199
|
-
},
|
|
200
146
|
{
|
|
201
147
|
method: "PUT",
|
|
202
148
|
module: "content",
|
|
@@ -399,9 +345,9 @@ var e = [
|
|
|
399
345
|
errorSets: ["module:content", "request"]
|
|
400
346
|
},
|
|
401
347
|
{
|
|
402
|
-
method: "
|
|
348
|
+
method: "DELETE",
|
|
403
349
|
module: "content",
|
|
404
|
-
path: "/comments/{cid}/
|
|
350
|
+
path: "/comments/{cid}/reaction",
|
|
405
351
|
auth: "public",
|
|
406
352
|
permission: null,
|
|
407
353
|
query: [],
|
|
@@ -452,24 +398,6 @@ var e = [
|
|
|
452
398
|
],
|
|
453
399
|
errorSets: ["module:content", "request"]
|
|
454
400
|
},
|
|
455
|
-
{
|
|
456
|
-
method: "POST",
|
|
457
|
-
module: "content",
|
|
458
|
-
path: "/{kind}/{id}/neutral",
|
|
459
|
-
auth: "public",
|
|
460
|
-
permission: null,
|
|
461
|
-
query: [],
|
|
462
|
-
request: null,
|
|
463
|
-
responses: { 200: "ReactionCounts" },
|
|
464
|
-
errors: [
|
|
465
|
-
"forbidden",
|
|
466
|
-
"invalid_request",
|
|
467
|
-
"not_found",
|
|
468
|
-
"rate_limited",
|
|
469
|
-
"unauthorized"
|
|
470
|
-
],
|
|
471
|
-
errorSets: ["module:content", "request"]
|
|
472
|
-
},
|
|
473
401
|
{
|
|
474
402
|
method: "DELETE",
|
|
475
403
|
module: "content",
|