@omelhorsite/sdk 0.3.0 → 0.4.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 +112 -130
- package/dist/index.js +1045 -1242
- package/dist/types/index.d.ts +1 -0
- package/dist/types/internal/attachments.d.ts +17 -0
- package/dist/types/internal/helpers.d.ts +9 -0
- package/dist/types/listing.d.ts +90 -0
- package/dist/types/resources/account.d.ts +5 -2
- package/dist/types/resources/admin/authorizedApplications.d.ts +133 -0
- package/dist/types/resources/admin/chests.d.ts +51 -0
- package/dist/types/resources/admin/eventAlerts.d.ts +60 -0
- package/dist/types/resources/admin/identities.d.ts +99 -0
- package/dist/types/resources/admin/index.d.ts +77 -0
- package/dist/types/resources/admin/jobs.d.ts +97 -0
- package/dist/types/resources/admin/myOauthApplications.d.ts +282 -0
- package/dist/types/resources/admin/notepads.d.ts +49 -0
- package/dist/types/resources/admin/oauthApplications.d.ts +309 -0
- package/dist/types/resources/admin/quotas.d.ts +114 -0
- package/dist/types/resources/admin/shortLinks.d.ts +201 -0
- package/dist/types/resources/admin/types.d.ts +222 -0
- package/dist/types/resources/admin/vocalSeparations.d.ts +98 -0
- package/dist/types/resources/admin.d.ts +17 -13
- package/dist/types/resources/auth/sessions.d.ts +6 -9
- package/dist/types/resources/content/analysis.d.ts +62 -0
- package/dist/types/resources/content/blogs.d.ts +471 -0
- package/dist/types/resources/content/feedbacks.d.ts +263 -0
- package/dist/types/resources/content/index.d.ts +52 -0
- package/dist/types/resources/content/intel/articles.d.ts +230 -0
- package/dist/types/resources/content/intel/config.d.ts +135 -0
- package/dist/types/resources/content/intel/index.d.ts +53 -0
- package/dist/types/resources/content/intel/items.d.ts +91 -0
- package/dist/types/resources/content/intel/reports.d.ts +108 -0
- package/dist/types/resources/content/intel/scripts.d.ts +152 -0
- package/dist/types/resources/content/intel/sources.d.ts +236 -0
- package/dist/types/resources/content/intel/stats.d.ts +105 -0
- package/dist/types/resources/content/intel/types.d.ts +86 -0
- package/dist/types/resources/content/jokes.d.ts +93 -0
- package/dist/types/resources/content/notifications.d.ts +147 -0
- package/dist/types/resources/content/serviceUsages.d.ts +73 -0
- package/dist/types/resources/content/servicesStatus.d.ts +194 -0
- package/dist/types/resources/content/siteConfig.d.ts +43 -0
- package/dist/types/resources/content/spaceInvaders.d.ts +154 -0
- package/dist/types/resources/content.d.ts +41 -236
- package/dist/types/resources/jobs.d.ts +7 -4
- package/dist/types/resources/library/annotations.d.ts +162 -0
- package/dist/types/resources/library/books.d.ts +534 -0
- package/dist/types/resources/library/chat.d.ts +259 -0
- package/dist/types/resources/library/index.d.ts +39 -0
- package/dist/types/resources/library/shelves.d.ts +237 -0
- package/dist/types/resources/library/types.d.ts +120 -0
- package/dist/types/resources/library.d.ts +20 -22
- package/dist/types/resources/movies/addons.d.ts +388 -0
- package/dist/types/resources/movies/collections.d.ts +352 -0
- package/dist/types/resources/movies/index.d.ts +29 -0
- package/dist/types/resources/movies/types.d.ts +50 -0
- package/dist/types/resources/movies/watchProgress.d.ts +277 -0
- package/dist/types/resources/movies.d.ts +27 -53
- package/dist/types/resources/music/artists.d.ts +3 -1
- package/dist/types/resources/music/imports.d.ts +9 -8
- package/dist/types/resources/music/playlists.d.ts +8 -7
- package/dist/types/resources/music/songs.d.ts +5 -21
- package/dist/types/resources/shortLinks.d.ts +5 -2
- package/dist/types/resources/social/groupChats.d.ts +458 -0
- package/dist/types/resources/social/index.d.ts +19 -0
- package/dist/types/resources/social/messages.d.ts +424 -0
- package/dist/types/resources/social/relationships.d.ts +322 -0
- package/dist/types/resources/social/types.d.ts +37 -0
- package/dist/types/resources/social.d.ts +21 -3
- package/dist/types/resources/storage.d.ts +24 -6
- package/dist/types/resources/tickets.d.ts +19 -10
- package/package.json +1 -1
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
/** Blogs, blog posts and subscriptions. */
|
|
2
|
+
import { type ApiClient, Resource } from "../../http";
|
|
3
|
+
import type { Id, RequestOptions, Timestamp } from "../../types";
|
|
4
|
+
/** Primary key of a blog. An INTEGER: `blogs` kept its auto-increment id. */
|
|
5
|
+
export type BlogId = number;
|
|
6
|
+
/** Primary key of a blog post. An integer, like the blog it hangs off. */
|
|
7
|
+
export type BlogPostId = number;
|
|
8
|
+
/** The author of a blog, embedded in {@link Blog}. Not a full user record. */
|
|
9
|
+
export interface BlogAuthor {
|
|
10
|
+
/** User id. A STRING, unlike every other id in this section. */
|
|
11
|
+
readonly id: Id;
|
|
12
|
+
readonly handle: string;
|
|
13
|
+
readonly name: string;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* A blog: one per user, created lazily.
|
|
17
|
+
*
|
|
18
|
+
* Deliberately NOT a `BaseRecord`: the payload has `created_at` and NO
|
|
19
|
+
* `updated_at`. Do not reach for one.
|
|
20
|
+
*/
|
|
21
|
+
export interface Blog {
|
|
22
|
+
readonly id: BlogId;
|
|
23
|
+
/**
|
|
24
|
+
* URL-safe handle of the blog, and the ONLY way to address it on the read
|
|
25
|
+
* routes. Matches `/\A[a-z0-9][a-z0-9_-]*\z/`, 1-64 characters, unique
|
|
26
|
+
* across the whole table. Defaults to the owner's handle, lowercased.
|
|
27
|
+
*/
|
|
28
|
+
readonly slug: string;
|
|
29
|
+
/** Display name. Defaults to `"<name>'s blog"`. Up to 80 characters. */
|
|
30
|
+
readonly name: string;
|
|
31
|
+
/** Up to 240 characters, or `null`. */
|
|
32
|
+
readonly description: string | null;
|
|
33
|
+
/** Who owns it. One blog per user, enforced by a unique index on `user_id`. */
|
|
34
|
+
readonly user: BlogAuthor;
|
|
35
|
+
/**
|
|
36
|
+
* Subscribers with a `confirmed_at`, counted live on every render.
|
|
37
|
+
*
|
|
38
|
+
* In practice that is every subscriber: the only reachable way to subscribe
|
|
39
|
+
* requires a session, and a signed-in subscription is confirmed on the spot.
|
|
40
|
+
* See {@link BlogsNamespace.subscribe}.
|
|
41
|
+
*/
|
|
42
|
+
readonly followers_count: number;
|
|
43
|
+
/** Posts with a `published_at`, counted live on every render. */
|
|
44
|
+
readonly published_posts_count: number;
|
|
45
|
+
readonly created_at: Timestamp;
|
|
46
|
+
/**
|
|
47
|
+
* Whether the CALLING user subscribes to this blog. Computed against the
|
|
48
|
+
* caller, so the same row differs per identity - never cache it across
|
|
49
|
+
* identities, and note it is `false` (not `null`) for an anonymous caller.
|
|
50
|
+
*/
|
|
51
|
+
readonly is_following: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* A post as it appears in a listing: the summary view.
|
|
55
|
+
*
|
|
56
|
+
* Like {@link Blog}, this is not a `BaseRecord`: the summary carries neither
|
|
57
|
+
* `created_at` nor `updated_at`. They appear only on {@link BlogPost}, the
|
|
58
|
+
* `:extended` view, which is this shape PLUS extras, never a subset.
|
|
59
|
+
*/
|
|
60
|
+
export interface BlogPostSummary {
|
|
61
|
+
readonly id: BlogPostId;
|
|
62
|
+
/** URL-safe, unique within the blog. Derived from the title when omitted. */
|
|
63
|
+
readonly slug: string;
|
|
64
|
+
/** Up to 200 characters. */
|
|
65
|
+
readonly title: string;
|
|
66
|
+
/**
|
|
67
|
+
* Up to 240 characters, derived from the first characters of `content_md`
|
|
68
|
+
* with the markdown punctuation stripped, unless the author wrote one. The
|
|
69
|
+
* derivation runs in a `before_save`, so it is refreshed on every write
|
|
70
|
+
* where the excerpt is blank - and never once it is not.
|
|
71
|
+
*/
|
|
72
|
+
readonly excerpt: string | null;
|
|
73
|
+
/** `null` for a draft. Presence of this field IS the published flag. */
|
|
74
|
+
readonly published_at: Timestamp | null;
|
|
75
|
+
/**
|
|
76
|
+
* Estimated reading time, recomputed on every save at 220 words per minute
|
|
77
|
+
* and floored at 1. Server-owned: sending it is ignored.
|
|
78
|
+
*/
|
|
79
|
+
readonly reading_minutes: number;
|
|
80
|
+
/** Lowercased, de-duplicated, at most 10. Never `null` in the payload. */
|
|
81
|
+
readonly tags: string[];
|
|
82
|
+
/** The blog it belongs to, trimmed to three fields. */
|
|
83
|
+
readonly blog: {
|
|
84
|
+
readonly id: BlogId;
|
|
85
|
+
readonly slug: string;
|
|
86
|
+
readonly name: string;
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
/** A post with its body: the `:extended` view, returned by every single-post route. */
|
|
90
|
+
export interface BlogPost extends BlogPostSummary {
|
|
91
|
+
/**
|
|
92
|
+
* The markdown source, up to 200 000 characters.
|
|
93
|
+
*
|
|
94
|
+
* There is a `content_html` column next to it in the database, rendered on
|
|
95
|
+
* write - but no response exposes it, so the client renders the markdown
|
|
96
|
+
* itself.
|
|
97
|
+
*/
|
|
98
|
+
readonly content_md: string | null;
|
|
99
|
+
readonly created_at: Timestamp;
|
|
100
|
+
readonly updated_at: Timestamp;
|
|
101
|
+
/** Whether the CALLING user may edit it. Per-viewer, like `is_following`. */
|
|
102
|
+
readonly is_owner: boolean;
|
|
103
|
+
}
|
|
104
|
+
/** A {@link Blog} plus the posts the caller may see. Returned by `show` and `mine`. */
|
|
105
|
+
export interface BlogWithPosts extends Blog {
|
|
106
|
+
/**
|
|
107
|
+
* Newest first (`published_at DESC, created_at DESC`).
|
|
108
|
+
*
|
|
109
|
+
* NOT paginated and NOT capped: `blog.blog_posts.viewable_by(...).recent`
|
|
110
|
+
* runs with no `limit`, so a blog with a thousand posts returns a thousand
|
|
111
|
+
* summaries in one response. This is the one listing in the file with no
|
|
112
|
+
* ceiling of any kind.
|
|
113
|
+
*
|
|
114
|
+
* On `show` this is published posts only, unless the caller owns the blog,
|
|
115
|
+
* in which case drafts are included too. On `mine` it is every post,
|
|
116
|
+
* published or not.
|
|
117
|
+
*/
|
|
118
|
+
readonly posts: BlogPostSummary[];
|
|
119
|
+
}
|
|
120
|
+
/** Fields {@link BlogsNamespace.updateMine} may change. */
|
|
121
|
+
export interface UpdateBlogInput {
|
|
122
|
+
/**
|
|
123
|
+
* New slug. Must match `/\A[a-z0-9][a-z0-9_-]*\z/` (1-64 chars) and be free
|
|
124
|
+
* across the whole table, or the call is `400`. Changing it BREAKS every
|
|
125
|
+
* link already published against the old one: there is no redirect and no
|
|
126
|
+
* history table.
|
|
127
|
+
*/
|
|
128
|
+
readonly slug?: string;
|
|
129
|
+
/** Up to 80 characters. */
|
|
130
|
+
readonly name?: string;
|
|
131
|
+
/** Up to 240 characters. */
|
|
132
|
+
readonly description?: string | null;
|
|
133
|
+
}
|
|
134
|
+
/** Result of a subscribe call. */
|
|
135
|
+
export interface BlogSubscribeResult {
|
|
136
|
+
readonly ok: boolean;
|
|
137
|
+
/**
|
|
138
|
+
* `true` when the subscription is live.
|
|
139
|
+
*
|
|
140
|
+
* In practice it is ALWAYS `true` today. The field exists because the
|
|
141
|
+
* controller can also create an unconfirmed, email-only subscription - but
|
|
142
|
+
* that branch is unreachable over HTTP (see
|
|
143
|
+
* {@link BlogsNamespace.subscribe}), so every row this route can actually
|
|
144
|
+
* create is a signed-in one, and `set_confirmed_at_for_user_subs` confirms
|
|
145
|
+
* those on insert.
|
|
146
|
+
*
|
|
147
|
+
* Were a `false` ever to reach you, there would be nothing to do about it:
|
|
148
|
+
* the row carries an `unsubscribe_token`, but no route in the application
|
|
149
|
+
* reads it, so there is no confirmation step to complete.
|
|
150
|
+
*/
|
|
151
|
+
readonly confirmed: boolean;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* The `blogs` namespace: one blog per user, markdown posts, and a subscriber
|
|
155
|
+
* list.
|
|
156
|
+
*
|
|
157
|
+
* The read routes address a blog by its SLUG, never by its id - the lookup is
|
|
158
|
+
* by lowercased slug and nothing else, so passing the numeric id gets
|
|
159
|
+
* `404 "Blog not found"`. The two subscribe routes are the exception: they try
|
|
160
|
+
* the slug first and then fall back to the id, so they accept either.
|
|
161
|
+
*
|
|
162
|
+
* Reads (`GET /blogs`, `GET /blogs/:slug`, `GET /blog_posts`,
|
|
163
|
+
* `GET /blog_posts/:id`, `GET /blogs/:blog/posts/:slug`) are open to anonymous
|
|
164
|
+
* callers; everything else needs a session.
|
|
165
|
+
*/
|
|
166
|
+
export declare class BlogsNamespace extends Resource {
|
|
167
|
+
/** Posts, blog metadata and publishing. Also mounted as `oms.blogPosts`. */
|
|
168
|
+
readonly posts: BlogPostsNamespace;
|
|
169
|
+
constructor(http: ApiClient);
|
|
170
|
+
/**
|
|
171
|
+
* `GET /blogs` - the discovery feed: the 30 most recent PUBLISHED posts
|
|
172
|
+
* across every blog on the site.
|
|
173
|
+
*
|
|
174
|
+
* Despite the path this returns POSTS, not blogs, and there is no endpoint
|
|
175
|
+
* anywhere that lists blogs. The wire shape is `{"posts": [...]}`, one of
|
|
176
|
+
* the two envelopes in this file; the array is unwrapped here.
|
|
177
|
+
*
|
|
178
|
+
* Fixed at 30 rows, newest first. No paging, no filters, no `search` - the
|
|
179
|
+
* action is `BlogPost.published.recent.limit(30)` and reads nothing off the
|
|
180
|
+
* query string, so anything you add to it is ignored rather than rejected.
|
|
181
|
+
* To go deeper than 30, there is nothing to page: this is a front page, not
|
|
182
|
+
* an archive.
|
|
183
|
+
*
|
|
184
|
+
* Anonymous-safe, and drafts never leak into it regardless of who asks.
|
|
185
|
+
*/
|
|
186
|
+
discover(options?: RequestOptions): Promise<BlogPostSummary[]>;
|
|
187
|
+
/**
|
|
188
|
+
* `GET /blogs/:slug` - one blog with all of its visible posts.
|
|
189
|
+
*
|
|
190
|
+
* The slug is lowercased by the server before the lookup, so case does not
|
|
191
|
+
* matter. A numeric id does NOT work here; use the slug.
|
|
192
|
+
*
|
|
193
|
+
* Published posts only, unless the caller OWNS the blog, in which case their
|
|
194
|
+
* drafts are included. `BlogPost.viewable_by` keys on `blog.user_id` alone,
|
|
195
|
+
* so an admin looking at somebody else's blog sees exactly what the public
|
|
196
|
+
* sees. The `posts` array is unbounded - see {@link BlogWithPosts.posts}.
|
|
197
|
+
*
|
|
198
|
+
* @throws {OmsApiError} 404 `"Blog not found"`.
|
|
199
|
+
*/
|
|
200
|
+
show(slug: string, options?: RequestOptions): Promise<BlogWithPosts>;
|
|
201
|
+
/**
|
|
202
|
+
* `GET /blogs/mine` - the caller's own blog, drafts included.
|
|
203
|
+
*
|
|
204
|
+
* **This read has a side effect.** `Blog.find_or_create_for` CREATES the
|
|
205
|
+
* blog row on first call, with the slug defaulted to the caller's handle and
|
|
206
|
+
* the name defaulted to `"<name>'s blog"`, and the creation fires a Discord
|
|
207
|
+
* `blog_created` alert. So "does this user have a blog" is not a question
|
|
208
|
+
* this endpoint can answer - by the time it replies, they do. Call it when
|
|
209
|
+
* the user opens their blog dashboard, not to probe.
|
|
210
|
+
*
|
|
211
|
+
* The default slug is the user's handle, which can collide with a blog
|
|
212
|
+
* somebody already owns under that slug - handles and blog slugs are
|
|
213
|
+
* separate namespaces and nothing keeps them apart. `create!` then raises
|
|
214
|
+
* `ActiveRecord::RecordInvalid`, which reaches the caller as a `422` with a
|
|
215
|
+
* Rails error page rather than this API's usual bare string, and fires a
|
|
216
|
+
* Discord error alert on the way out. Rare, and unfixable from the client:
|
|
217
|
+
* the endpoint takes no arguments.
|
|
218
|
+
*
|
|
219
|
+
* @throws {OmsApiError} 401 `"Session required to access this resource."`.
|
|
220
|
+
* The action also carries its own `unauthorized!("Not authenticated")`
|
|
221
|
+
* guard, but `allow_unauthenticated_access` covers only `index` and `show`,
|
|
222
|
+
* so the framework filter fires first and that message never ships.
|
|
223
|
+
*/
|
|
224
|
+
mine(options?: RequestOptions): Promise<BlogWithPosts>;
|
|
225
|
+
/**
|
|
226
|
+
* `PATCH /blogs/mine` - renames or re-slugs the caller's blog.
|
|
227
|
+
*
|
|
228
|
+
* Creates the blog first if there is none, exactly like {@link mine}, so
|
|
229
|
+
* this can be the very first call a client makes.
|
|
230
|
+
*
|
|
231
|
+
* Answers the blog ALONE - no `posts` key, unlike every other blog route.
|
|
232
|
+
* That asymmetry is the reason this returns {@link Blog} and not
|
|
233
|
+
* {@link BlogWithPosts}.
|
|
234
|
+
*
|
|
235
|
+
* Only `slug`, `name` and `description` are permitted; anything else in the
|
|
236
|
+
* body is dropped in silence. Re-slugging breaks published links - see
|
|
237
|
+
* {@link UpdateBlogInput.slug}.
|
|
238
|
+
*
|
|
239
|
+
* @throws {OmsApiError} 400 with the validation sentence when the slug is
|
|
240
|
+
* taken or malformed; 401 `"Session required to access this resource."`.
|
|
241
|
+
*/
|
|
242
|
+
updateMine(input: UpdateBlogInput, options?: RequestOptions): Promise<Blog>;
|
|
243
|
+
/**
|
|
244
|
+
* `POST /blogs/:slug/subscribe` - follows a blog.
|
|
245
|
+
*
|
|
246
|
+
* **Signed-in callers only, despite appearances.** The action reads like it
|
|
247
|
+
* supports anonymous email subscriptions - there is a whole branch for it,
|
|
248
|
+
* ending in `400 "Email required for anonymous subscribe"` - but
|
|
249
|
+
* `allow_unauthenticated_access` covers only `index` and `show`, so
|
|
250
|
+
* `require_authentication` rejects an anonymous caller with
|
|
251
|
+
* `401 "Session required to access this resource."` long before that branch
|
|
252
|
+
* runs. The email path is dead code today.
|
|
253
|
+
*
|
|
254
|
+
* Which means `email` is effectively ignored: with a session present the
|
|
255
|
+
* controller always takes the user branch, the subscription is attached to
|
|
256
|
+
* the account, and it is confirmed on insert, so `confirmed` is always
|
|
257
|
+
* `true` and `followers_count` moves. The parameter is kept here because the
|
|
258
|
+
* server accepts it and because the branch could be revived by one line in
|
|
259
|
+
* the controller - not because sending it changes anything today.
|
|
260
|
+
*
|
|
261
|
+
* Idempotent by construction: `find_or_initialize_by` on
|
|
262
|
+
* `(blog, user, email)` means subscribing twice is a no-op that answers
|
|
263
|
+
* `200` both times, so this is one of the few POSTs here where a retry
|
|
264
|
+
* cannot duplicate anything.
|
|
265
|
+
*
|
|
266
|
+
* Accepts either the slug or the numeric id in the path - this route and its
|
|
267
|
+
* `DELETE` twin are the only ones in the file that do.
|
|
268
|
+
*
|
|
269
|
+
* @throws {OmsApiError} 404 `"Blog not found"`; 401 without a session.
|
|
270
|
+
*/
|
|
271
|
+
subscribe(slugOrId: string | BlogId, input?: {
|
|
272
|
+
readonly email?: string;
|
|
273
|
+
}, options?: RequestOptions): Promise<BlogSubscribeResult>;
|
|
274
|
+
/**
|
|
275
|
+
* `DELETE /blogs/:slug/subscribe` - unfollows a blog.
|
|
276
|
+
*
|
|
277
|
+
* Signed-in callers only, and it removes only the CALLER's own subscription:
|
|
278
|
+
* the scope is `where(blog:, user: Current.user)`, so an email-only row
|
|
279
|
+
* (were one to exist) could not be removed through here at all.
|
|
280
|
+
*
|
|
281
|
+
* Answers `{"ok": true}` whether or not a subscription existed - it is a
|
|
282
|
+
* `delete_all` on a scope, so "not subscribed" and "unsubscribed" are the
|
|
283
|
+
* same answer, and a double call is harmless.
|
|
284
|
+
*
|
|
285
|
+
* @throws {OmsApiError} 404 `"Blog not found"`; 401
|
|
286
|
+
* `"Session required to access this resource."`.
|
|
287
|
+
*/
|
|
288
|
+
unsubscribe(slugOrId: string | BlogId, options?: RequestOptions): Promise<{
|
|
289
|
+
ok: boolean;
|
|
290
|
+
}>;
|
|
291
|
+
}
|
|
292
|
+
/** Arguments for {@link BlogPostsNamespace.create}. */
|
|
293
|
+
export interface CreateBlogPostInput {
|
|
294
|
+
/** Required, up to 200 characters. */
|
|
295
|
+
readonly title: string;
|
|
296
|
+
/**
|
|
297
|
+
* URL-safe slug, unique within the blog. Omit it and the server derives one
|
|
298
|
+
* from the title (lowercased, non-alphanumerics collapsed to `-`, trimmed to
|
|
299
|
+
* 80 characters), falling back to `post-<6 hex>` when the title has no
|
|
300
|
+
* alphanumerics at all - a title written entirely in a non-Latin script
|
|
301
|
+
* therefore gets a random slug, not a transliterated one.
|
|
302
|
+
*/
|
|
303
|
+
readonly slug?: string;
|
|
304
|
+
/** Markdown source, up to 200 000 characters. */
|
|
305
|
+
readonly content_md?: string;
|
|
306
|
+
/**
|
|
307
|
+
* Up to 280 characters by the model, but only 240 are ever written by the
|
|
308
|
+
* derivation. Leave it out and the server writes the first 240 characters of
|
|
309
|
+
* the stripped markdown; it is re-derived on every save where it is blank,
|
|
310
|
+
* so clearing it back to `""` re-enables the automatic one.
|
|
311
|
+
*/
|
|
312
|
+
readonly excerpt?: string;
|
|
313
|
+
/**
|
|
314
|
+
* Up to 10 tags. Lowercased, trimmed, de-duplicated and blank-filtered by
|
|
315
|
+
* the controller, and anything past the tenth is dropped in silence.
|
|
316
|
+
*/
|
|
317
|
+
readonly tags?: readonly string[];
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Arguments for {@link BlogPostsNamespace.update}.
|
|
321
|
+
*
|
|
322
|
+
* `tags` is optional in the type and DANGEROUS to omit. `post_params` ends
|
|
323
|
+
* with an unconditional `raw[:tags] = (raw[:tags] || []) ...`, so a PATCH that
|
|
324
|
+
* does not mention tags assigns the EMPTY ARRAY over whatever the post had.
|
|
325
|
+
* There is no partial-update semantics for this field: resend the tags you
|
|
326
|
+
* already hold on every update, or watch them disappear. Same shape of bug as
|
|
327
|
+
* `manifest_json` on movie addons.
|
|
328
|
+
*/
|
|
329
|
+
export interface UpdateBlogPostInput {
|
|
330
|
+
readonly title?: string;
|
|
331
|
+
/** Changing it breaks published links; uniqueness is scoped to the blog. */
|
|
332
|
+
readonly slug?: string;
|
|
333
|
+
readonly content_md?: string;
|
|
334
|
+
readonly excerpt?: string;
|
|
335
|
+
/** ALWAYS send this. Omitting it clears the post's tags. See the interface docs. */
|
|
336
|
+
readonly tags?: readonly string[];
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Posts, reachable as `oms.content.blogs.posts`.
|
|
340
|
+
*
|
|
341
|
+
* A post lives under exactly one blog and a user has exactly one blog, so
|
|
342
|
+
* there is no "which blog" argument anywhere: {@link create} always writes to
|
|
343
|
+
* the caller's own, creating it if needed.
|
|
344
|
+
*/
|
|
345
|
+
export declare class BlogPostsNamespace extends Resource {
|
|
346
|
+
/**
|
|
347
|
+
* `GET /blog_posts` - the 50 most recent posts the caller may see, newest
|
|
348
|
+
* first, optionally narrowed to one blog.
|
|
349
|
+
*
|
|
350
|
+
* Envelope: the wire shape is `{"posts": [...]}` and the array is unwrapped
|
|
351
|
+
* here.
|
|
352
|
+
*
|
|
353
|
+
* NOT the list DSL, despite the plural path. `blog_slug` is the only
|
|
354
|
+
* parameter the action reads; `search`, `exact_search` and `modifiers` are
|
|
355
|
+
* ignored rather than rejected, and the limit of 50 is not negotiable. There
|
|
356
|
+
* is no way to page past it, so this is a feed and not an archive - to walk
|
|
357
|
+
* a whole blog, read {@link BlogsNamespace.show}, whose `posts` array is
|
|
358
|
+
* uncapped.
|
|
359
|
+
*
|
|
360
|
+
* Visibility follows the caller: published posts always, plus the caller's
|
|
361
|
+
* OWN drafts. An anonymous caller sees published posts only.
|
|
362
|
+
*
|
|
363
|
+
* @param input.blogSlug Restrict to one blog. An unknown slug does NOT 404 -
|
|
364
|
+
* `find_by` returns nil and the action silently falls back to the
|
|
365
|
+
* site-wide listing, so a typo here returns everybody's posts instead of
|
|
366
|
+
* an empty list. Check the `blog` on each row if that distinction matters.
|
|
367
|
+
*/
|
|
368
|
+
list(input?: {
|
|
369
|
+
readonly blogSlug?: string;
|
|
370
|
+
}, options?: RequestOptions): Promise<BlogPostSummary[]>;
|
|
371
|
+
/**
|
|
372
|
+
* `GET /blog_posts/:id` - one post by numeric id, with its body.
|
|
373
|
+
*
|
|
374
|
+
* @throws {OmsApiError} 404 `"Post not found"`; **401**
|
|
375
|
+
* `"Draft only visible to author"` when the post exists but is
|
|
376
|
+
* unpublished and the caller is not its author. Note that this is a 401
|
|
377
|
+
* rather than a 404, so it confirms that a draft with that id exists.
|
|
378
|
+
*/
|
|
379
|
+
get(id: BlogPostId, options?: RequestOptions): Promise<BlogPost>;
|
|
380
|
+
/**
|
|
381
|
+
* `GET /blogs/:blogSlug/posts/:slug` - one post by the pair of slugs, which
|
|
382
|
+
* is the shape a public permalink has.
|
|
383
|
+
*
|
|
384
|
+
* **This route needs a session, and the id route does not.** That is almost
|
|
385
|
+
* certainly a mistake in the backend and it is worth knowing before you
|
|
386
|
+
* build a public permalink on it: an anonymous reader following a shared
|
|
387
|
+
* link gets `401 "Session required to access this resource."` here, while
|
|
388
|
+
* {@link get} hands them the very same published post. Until that is fixed,
|
|
389
|
+
* render public permalinks through {@link get} with the numeric id, or
|
|
390
|
+
* expect signed-in readers only.
|
|
391
|
+
*
|
|
392
|
+
* Both slugs are lowercased server-side before the lookup. The route is
|
|
393
|
+
* declared with `constraints: { blog_slug: /[^\/]+/, slug: /[^\/]+/ }`, so a
|
|
394
|
+
* slug containing a slash cannot reach it at all - not a concern for
|
|
395
|
+
* server-minted slugs, which are `[a-z0-9_-]` only.
|
|
396
|
+
*
|
|
397
|
+
* @throws {OmsApiError} 401 without a session, before anything else is
|
|
398
|
+
* checked; 404 `"Blog not found"` or `"Post not found"`; 401
|
|
399
|
+
* `"Draft only visible to author"`.
|
|
400
|
+
*/
|
|
401
|
+
getBySlugs(blogSlug: string, slug: string, options?: RequestOptions): Promise<BlogPost>;
|
|
402
|
+
/**
|
|
403
|
+
* `POST /blog_posts` - writes a new post to the caller's own blog. `201`.
|
|
404
|
+
*
|
|
405
|
+
* There is no blog argument because there is no choice: the controller calls
|
|
406
|
+
* `Blog.find_or_create_for(Current.user)`, so this CREATES the caller's blog
|
|
407
|
+
* as a side effect on their very first post, exactly like
|
|
408
|
+
* {@link BlogsNamespace.mine}.
|
|
409
|
+
*
|
|
410
|
+
* The post starts as a DRAFT - `published_at` is not settable here and no
|
|
411
|
+
* amount of arguments will publish it. Publishing is a second call, and it
|
|
412
|
+
* is {@link setPublished}, not {@link update}.
|
|
413
|
+
*
|
|
414
|
+
* Rides the general ceiling: there is no per-user cap on how many posts may
|
|
415
|
+
* be created, and no length cap beyond the model's 200 000 characters of
|
|
416
|
+
* markdown.
|
|
417
|
+
*
|
|
418
|
+
* @throws {OmsApiError} 401 `"Session required to access this resource."`;
|
|
419
|
+
* 400 with the validation sentence, most often the slug already existing
|
|
420
|
+
* in this blog.
|
|
421
|
+
*/
|
|
422
|
+
create(input: CreateBlogPostInput, options?: RequestOptions): Promise<BlogPost>;
|
|
423
|
+
/**
|
|
424
|
+
* `PATCH /blog_posts/:id` - edits a post's fields.
|
|
425
|
+
*
|
|
426
|
+
* Do NOT put `publish` in this body. The controller checks for it FIRST and,
|
|
427
|
+
* when it is a boolean or the string `"true"`/`"false"`, publishes or
|
|
428
|
+
* unpublishes and returns immediately - `ok!` raises the response - so every
|
|
429
|
+
* other field in the same request is discarded without a word. That is a
|
|
430
|
+
* silent data loss, not an error you can catch. Use {@link setPublished} for
|
|
431
|
+
* the flag and this method for the content; two calls, in either order.
|
|
432
|
+
*
|
|
433
|
+
* Always send `tags`, including when they have not changed. See
|
|
434
|
+
* {@link UpdateBlogPostInput}.
|
|
435
|
+
*
|
|
436
|
+
* Editing does not change `published_at`, so an edit to a published post
|
|
437
|
+
* stays published and does not move in the feed's ordering.
|
|
438
|
+
*
|
|
439
|
+
* @throws {OmsApiError} 404 `"Post not found"`; 401 `"Not your post"`; 400
|
|
440
|
+
* with the validation sentence.
|
|
441
|
+
*/
|
|
442
|
+
update(id: BlogPostId, input: UpdateBlogPostInput, options?: RequestOptions): Promise<BlogPost>;
|
|
443
|
+
/**
|
|
444
|
+
* `PATCH /blog_posts/:id` with `{ publish }` - the publish switch, on its
|
|
445
|
+
* own.
|
|
446
|
+
*
|
|
447
|
+
* Separated from {@link update} because the controller treats it as an
|
|
448
|
+
* early-return branch rather than as a field: a body carrying `publish`
|
|
449
|
+
* never reaches `post.update(post_params)`, so mixing the two loses the
|
|
450
|
+
* content edit. Sending it alone is the only safe way to use it.
|
|
451
|
+
*
|
|
452
|
+
* `publish: true` stamps `published_at` with the current time - and moves
|
|
453
|
+
* the post to the top of every `recent` ordering. Re-publishing an already
|
|
454
|
+
* published post is a no-op that still answers `200` with the ORIGINAL
|
|
455
|
+
* `published_at`, so this cannot be used to bump a post. `publish: false`
|
|
456
|
+
* clears `published_at`, which unlists the post everywhere and, for a
|
|
457
|
+
* non-owner, turns {@link get} into a 401.
|
|
458
|
+
*
|
|
459
|
+
* @throws {OmsApiError} 404 `"Post not found"`; 401 `"Not your post"`.
|
|
460
|
+
*/
|
|
461
|
+
setPublished(id: BlogPostId, publish: boolean, options?: RequestOptions): Promise<BlogPost>;
|
|
462
|
+
/**
|
|
463
|
+
* `DELETE /blog_posts/:id` - permanent. `204`, no body.
|
|
464
|
+
*
|
|
465
|
+
* Takes the attached `cover_image` with it (`dependent: :destroy`). There is
|
|
466
|
+
* no trash and no undo.
|
|
467
|
+
*
|
|
468
|
+
* @throws {OmsApiError} 404 `"Post not found"`; 401 `"Not your post"`.
|
|
469
|
+
*/
|
|
470
|
+
destroy(id: BlogPostId, options?: RequestOptions): Promise<void>;
|
|
471
|
+
}
|