@omelhorsite/sdk 0.13.0 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/README.md +26 -3
  2. package/dist/index.js +399 -170
  3. package/dist/types/auth/tokens.d.ts +1 -1
  4. package/dist/types/client.d.ts +3 -0
  5. package/dist/types/resources/admin/llm.d.ts +9 -1
  6. package/dist/types/resources/admin/quotas.d.ts +14 -0
  7. package/dist/types/resources/content/blogs.d.ts +111 -31
  8. package/dist/types/resources/content/index.d.ts +4 -4
  9. package/dist/types/resources/content/news/feeds.d.ts +56 -0
  10. package/dist/types/resources/content/news/index.d.ts +36 -0
  11. package/dist/types/resources/content/news/items.d.ts +115 -0
  12. package/dist/types/resources/content/{intel → news}/scripts.d.ts +35 -35
  13. package/dist/types/resources/content/{intel → news}/sources.d.ts +62 -59
  14. package/dist/types/resources/content/notifications.d.ts +2 -2
  15. package/dist/types/resources/cron.d.ts +209 -0
  16. package/dist/types/resources/index.d.ts +1 -0
  17. package/dist/types/resources/llm.d.ts +71 -0
  18. package/dist/types/resources/music/social.d.ts +121 -81
  19. package/dist/types/resources/music/songs.d.ts +39 -1
  20. package/dist/types/resources/quotas.d.ts +8 -5
  21. package/dist/types/resources/search.d.ts +36 -0
  22. package/package.json +1 -1
  23. package/dist/types/resources/content/intel/articles.d.ts +0 -230
  24. package/dist/types/resources/content/intel/config.d.ts +0 -135
  25. package/dist/types/resources/content/intel/index.d.ts +0 -53
  26. package/dist/types/resources/content/intel/items.d.ts +0 -91
  27. package/dist/types/resources/content/intel/reports.d.ts +0 -108
  28. package/dist/types/resources/content/intel/stats.d.ts +0 -105
  29. package/dist/types/resources/content/intel/types.d.ts +0 -86
@@ -93,7 +93,7 @@ export interface TokenStore {
93
93
  * narrowest set the product actually uses: every extra scope makes the
94
94
  * approval page scarier for no benefit.
95
95
  */
96
- export declare const OMS_SCOPES: readonly ["openid", "profile", "email", "tools:read", "tools:write", "storage:read", "storage:write", "tickets:write"];
96
+ export declare const OMS_SCOPES: readonly ["openid", "profile", "email", "tools:read", "tools:write", "storage:read", "storage:write", "tickets:write", "llm", "blogs:read", "blogs:write", "news:read", "news:write", "cron:read", "cron:write"];
97
97
  /** One of {@link OMS_SCOPES}. */
98
98
  export type OmsScope = (typeof OMS_SCOPES)[number];
99
99
  /** Refresh this long before the real expiry unless the host says otherwise. */
@@ -19,6 +19,7 @@ import { PasskeysNamespace } from "./resources/auth/passkeys";
19
19
  import { AuthSessionsNamespace } from "./resources/auth/sessions";
20
20
  import { ChestsNamespace } from "./resources/chests";
21
21
  import { ContentNamespace } from "./resources/content";
22
+ import { CronNamespace } from "./resources/cron";
22
23
  import { DynamicQrsNamespace } from "./resources/dynamicQrs";
23
24
  import { FormsNamespace } from "./resources/forms";
24
25
  import { IpLookupNamespace } from "./resources/ipLookup";
@@ -183,6 +184,8 @@ export declare class Oms {
183
184
  readonly search: SearchNamespace;
184
185
  /** The language models the signed-in person may pick, and their own usage. */
185
186
  readonly llm: LlmNamespace;
187
+ /** TypeScript scripts the server runs on a schedule as the signed-in person. */
188
+ readonly cron: CronNamespace;
186
189
  /**
187
190
  * The WebSocket connection: playback handoff, jams, notifications, job
188
191
  * progress. Opens nothing until {@link RealtimeNamespace.connect} is called,
@@ -117,6 +117,12 @@ export interface LlmModel {
117
117
  readonly enabled: boolean;
118
118
  /** Whether signed-in people may pick it (see `oms.llm.models`). */
119
119
  readonly visible_in_chat: boolean;
120
+ /**
121
+ * Who may pick it by name: `0` everyone, `1` trusted accounts, `2`
122
+ * administrators. An account reaches the models at or below its own tier
123
+ * (`oms.admin.quotas.setLlmTier`).
124
+ */
125
+ readonly tier: number;
120
126
  readonly context_window: number | null;
121
127
  readonly max_output_tokens: number | null;
122
128
  readonly input_price_per_million: number | null;
@@ -134,6 +140,8 @@ export interface CreateLlmModelInput {
134
140
  readonly name: string;
135
141
  readonly enabled?: boolean;
136
142
  readonly visibleInChat?: boolean;
143
+ /** `0` to `2`; see {@link LlmModel.tier}. */
144
+ readonly tier?: number;
137
145
  readonly contextWindow?: number | null;
138
146
  readonly maxOutputTokens?: number | null;
139
147
  readonly inputPricePerMillion?: number | null;
@@ -145,7 +153,7 @@ export interface CreateLlmModelInput {
145
153
  /** The provider and the `model_id` are fixed after creation. */
146
154
  export type UpdateLlmModelInput = Partial<Omit<CreateLlmModelInput, "llmProviderId" | "modelId">>;
147
155
  /** Filter columns of `GET /admin/llm_models`. */
148
- export declare const ADMIN_LLM_MODEL_FILTER_COLUMNS: readonly ["llm_provider_id", "model_id", "name", "enabled", "visible_in_chat", "free"];
156
+ export declare const ADMIN_LLM_MODEL_FILTER_COLUMNS: readonly ["llm_provider_id", "model_id", "name", "enabled", "visible_in_chat", "tier", "free"];
149
157
  export interface ListAdminLlmModelsParams extends ListParams<(typeof ADMIN_LLM_MODEL_FILTER_COLUMNS)[number]> {
150
158
  }
151
159
  /**
@@ -54,6 +54,11 @@ export interface AdminUserQuotaEntry {
54
54
  export interface AdminUserQuotas {
55
55
  readonly user_id: Id;
56
56
  readonly handle: string;
57
+ /**
58
+ * Which language models the person may pick by name: every model whose
59
+ * `tier` is at or below this. `0` for a new account. See {@link AdminQuotasNamespace.setLlmTier}.
60
+ */
61
+ readonly llm_tier: number;
57
62
  /**
58
63
  * **Every** resource in the catalogue, including the storage and music
59
64
  * ceilings. Unlike the anonymous answer from `oms.quotas.list()`, nothing is
@@ -111,4 +116,13 @@ export declare class AdminQuotasNamespace extends Resource {
111
116
  * @throws {OmsAuthError} 403 for a non-admin.
112
117
  */
113
118
  update(user: Id | string, overrides: readonly AdminQuotaOverride[], options?: RequestOptions): Promise<AdminUserQuotas>;
119
+ /**
120
+ * `PUT /admin/users/:user/quotas` with `llm_tier` only - which language
121
+ * models the person may pick by name (`0` everyone's, `1` adds the trusted
122
+ * ones, `2` adds the administrators' ones). Quota overrides are untouched.
123
+ *
124
+ * @throws {OmsApiError} 400 for a tier outside `0..2`; 404 `"User not found"`.
125
+ * @throws {OmsAuthError} 403 for a non-admin.
126
+ */
127
+ setLlmTier(user: Id | string, tier: number, options?: RequestOptions): Promise<AdminUserQuotas>;
114
128
  }
@@ -13,7 +13,19 @@ export interface BlogAuthor {
13
13
  readonly name: string;
14
14
  }
15
15
  /**
16
- * A blog: one per user, created lazily.
16
+ * Who can read a blog.
17
+ *
18
+ * - `"public"`: listed on the discovery feed and open to everyone;
19
+ * - `"unlisted"`: open to anyone who has the link, never listed;
20
+ * - `"private"`: the owner, administrators and the invited members only.
21
+ * Anonymous readers get `401`, signed-in strangers `403` with
22
+ * `error: "private"`.
23
+ */
24
+ export declare const BLOG_VISIBILITIES: readonly ["public", "unlisted", "private"];
25
+ export type BlogVisibility = (typeof BLOG_VISIBILITIES)[number];
26
+ /**
27
+ * A blog. A person may own several; the oldest is their default one (the one
28
+ * `mine` answers and posts land in when no blog is named).
17
29
  *
18
30
  * Deliberately NOT a `BaseRecord`: the payload has `created_at` and NO
19
31
  * `updated_at`. Do not reach for one.
@@ -23,15 +35,23 @@ export interface Blog {
23
35
  /**
24
36
  * URL-safe handle of the blog, and the ONLY way to address it on the read
25
37
  * 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.
38
+ * across the whole table. Defaults to the owner's handle, lowercased, with
39
+ * a numeric suffix for each further blog created without a slug.
27
40
  */
28
41
  readonly slug: string;
29
42
  /** Display name. Defaults to `"<name>'s blog"`. Up to 80 characters. */
30
43
  readonly name: string;
31
44
  /** Up to 240 characters, or `null`. */
32
45
  readonly description: string | null;
33
- /** Who owns it. One blog per user, enforced by a unique index on `user_id`. */
46
+ /** Who owns it. */
34
47
  readonly user: BlogAuthor;
48
+ readonly visibility: BlogVisibility | string;
49
+ /** Invited members (private blogs). Counted live. */
50
+ readonly members_count: number;
51
+ /** Whether the CALLING user owns it. Per-viewer, like `is_following`. */
52
+ readonly is_owner: boolean;
53
+ /** Whether the CALLING user is an invited member. Per-viewer. */
54
+ readonly is_member: boolean;
35
55
  /**
36
56
  * Subscribers with a `confirmed_at`, counted live on every render.
37
57
  *
@@ -79,11 +99,14 @@ export interface BlogPostSummary {
79
99
  readonly reading_minutes: number;
80
100
  /** Lowercased, de-duplicated, at most 10. Never `null` in the payload. */
81
101
  readonly tags: string[];
82
- /** The blog it belongs to, trimmed to three fields. */
102
+ /** `"user"` when written in the editor, `"api"` when a program posted it with an access token. */
103
+ readonly source: "user" | "api" | string;
104
+ /** The blog it belongs to, trimmed to four fields. */
83
105
  readonly blog: {
84
106
  readonly id: BlogId;
85
107
  readonly slug: string;
86
108
  readonly name: string;
109
+ readonly visibility: BlogVisibility | string;
87
110
  };
88
111
  }
89
112
  /** A post with its body: the `:extended` view, returned by every single-post route. */
@@ -130,6 +153,64 @@ export interface UpdateBlogInput {
130
153
  readonly name?: string;
131
154
  /** Up to 240 characters. */
132
155
  readonly description?: string | null;
156
+ readonly visibility?: BlogVisibility;
157
+ }
158
+ /** Arguments for {@link OwnBlogsNamespace.create}. Everything is optional: the defaults are the same as the first blog's. */
159
+ export interface CreateBlogInput {
160
+ readonly slug?: string;
161
+ readonly name?: string;
162
+ readonly description?: string | null;
163
+ /** Defaults to `"public"`. */
164
+ readonly visibility?: BlogVisibility;
165
+ }
166
+ /** An invited member of one of the caller's blogs. Being a member also subscribes the person to the blog's news. */
167
+ export interface BlogMember {
168
+ readonly id: number;
169
+ readonly blog_id: BlogId;
170
+ readonly user: BlogAuthor;
171
+ readonly created_at: Timestamp;
172
+ }
173
+ /** At most this many blogs per account; creating one more answers `400`. */
174
+ export declare const BLOGS_PER_ACCOUNT = 20;
175
+ /**
176
+ * The caller's own blogs, reachable as `oms.content.blogs.own`. Needs the
177
+ * `blogs:read` scope to read and `blogs:write` to change anything.
178
+ *
179
+ * A blog is addressed by its numeric id or its slug on every route here.
180
+ */
181
+ export declare class OwnBlogsNamespace extends Resource {
182
+ /** `GET /my_blogs` - every blog the caller owns, oldest first. The first one is the default. */
183
+ list(options?: RequestOptions): Promise<Blog[]>;
184
+ /**
185
+ * `GET /my_blogs/:id` - one of the caller's blogs with ALL of its posts,
186
+ * drafts included, newest first.
187
+ *
188
+ * @throws {OmsApiError} 404 `"Blog not found"` for a blog the caller does not own.
189
+ */
190
+ get(idOrSlug: BlogId | string, options?: RequestOptions): Promise<BlogWithPosts>;
191
+ /**
192
+ * `POST /my_blogs` - a further blog. Without a slug the server takes the
193
+ * handle with a numeric suffix.
194
+ *
195
+ * @throws {OmsApiError} 400 with the validation sentence (taken or
196
+ * malformed slug, unknown visibility) or `"blog limit reached (20)"`.
197
+ */
198
+ create(input?: CreateBlogInput, options?: RequestOptions): Promise<Blog>;
199
+ /** `PATCH /my_blogs/:id` - name, slug, description or visibility. Re-slugging breaks published links. */
200
+ update(idOrSlug: BlogId | string, input: UpdateBlogInput, options?: RequestOptions): Promise<Blog>;
201
+ /** `DELETE /my_blogs/:id` - the blog and every post, subscriber and member in it. */
202
+ delete(idOrSlug: BlogId | string, options?: RequestOptions): Promise<void>;
203
+ /** `GET /my_blogs/:id/members` - the invited members, oldest first. */
204
+ members(idOrSlug: BlogId | string, options?: RequestOptions): Promise<BlogMember[]>;
205
+ /**
206
+ * `POST /my_blogs/:id/members` - invites a person of the site by handle (a
207
+ * leading `@` is fine). Idempotent: inviting twice answers the same member.
208
+ *
209
+ * @throws {OmsApiError} 404 `"User not found"`; 400 when the handle is the owner's own.
210
+ */
211
+ addMember(idOrSlug: BlogId | string, handle: string, options?: RequestOptions): Promise<BlogMember>;
212
+ /** `DELETE /my_blogs/:id/members/:member` - by member id or by the member's user id. Their subscription goes too. */
213
+ removeMember(idOrSlug: BlogId | string, memberOrUserId: number | Id, options?: RequestOptions): Promise<void>;
133
214
  }
134
215
  /** Result of a subscribe call. */
135
216
  export interface BlogSubscribeResult {
@@ -166,6 +247,8 @@ export interface BlogSubscribeResult {
166
247
  export declare class BlogsNamespace extends Resource {
167
248
  /** Posts, blog metadata and publishing. Also mounted as `oms.blogPosts`. */
168
249
  readonly posts: BlogPostsNamespace;
250
+ /** The caller's own blogs: create more, change visibility, invite members. */
251
+ readonly own: OwnBlogsNamespace;
169
252
  constructor(http: ApiClient);
170
253
  /**
171
254
  * `GET /blogs` - the discovery feed: the 30 most recent PUBLISHED posts
@@ -291,6 +374,11 @@ export declare class BlogsNamespace extends Resource {
291
374
  }
292
375
  /** Arguments for {@link BlogPostsNamespace.create}. */
293
376
  export interface CreateBlogPostInput {
377
+ /** Which of the caller's blogs gets the post. Omit both for the default (oldest) blog. */
378
+ readonly blogId?: BlogId;
379
+ readonly blogSlug?: string;
380
+ /** Publish at once instead of saving a draft. */
381
+ readonly publish?: boolean;
294
382
  /** Required, up to 200 characters. */
295
383
  readonly title: string;
296
384
  /**
@@ -379,45 +467,37 @@ export declare class BlogPostsNamespace extends Resource {
379
467
  get(id: BlogPostId, options?: RequestOptions): Promise<BlogPost>;
380
468
  /**
381
469
  * `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
470
+ * is the shape a public permalink has. Open to anonymous readers for a
471
+ * published post of a public or unlisted blog.
472
+ *
473
+ * Both slugs are lowercased server-side before the lookup. A slug
474
+ * containing a slash cannot reach the route at all - not a concern for
395
475
  * server-minted slugs, which are `[a-z0-9_-]` only.
396
476
  *
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"`.
477
+ * @throws {OmsApiError} 404 `"Blog not found"` or `"Post not found"`; 401
478
+ * `"Draft only visible to author"`; for a private blog, 401 without a
479
+ * session and 403 `error: "private"` with one.
400
480
  */
401
481
  getBySlugs(blogSlug: string, slug: string, options?: RequestOptions): Promise<BlogPost>;
402
482
  /**
403
- * `POST /blog_posts` - writes a new post to the caller's own blog. `201`.
483
+ * `POST /blog_posts` - writes a new post. `201`.
404
484
  *
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}.
485
+ * `blogId` or `blogSlug` picks one of the caller's own blogs; with neither
486
+ * the post lands in the default (oldest) blog, which is created on the spot
487
+ * if the caller has none yet, exactly like {@link BlogsNamespace.mine}.
409
488
  *
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}.
489
+ * The post starts as a DRAFT unless `publish: true` is sent, which stamps
490
+ * `published_at` at once. Later changes to the flag go through
491
+ * {@link setPublished}, not {@link update}. A post written with an access
492
+ * token carries `source: "api"`.
413
493
  *
414
494
  * Rides the general ceiling: there is no per-user cap on how many posts may
415
495
  * be created, and no length cap beyond the model's 200 000 characters of
416
- * markdown.
496
+ * markdown. Needs the `blogs:write` scope on an OAuth token.
417
497
  *
418
498
  * @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.
499
+ * 404 `"Blog not found"` for a blog the caller does not own; 400 with the
500
+ * validation sentence, most often the slug already existing in this blog.
421
501
  */
422
502
  create(input: CreateBlogPostInput, options?: RequestOptions): Promise<BlogPost>;
423
503
  /**
@@ -3,7 +3,7 @@ import { type ApiClient, Resource } from "../../http";
3
3
  import { AnalysisNamespace } from "./analysis";
4
4
  import { BlogsNamespace } from "./blogs";
5
5
  import { FeedbacksNamespace } from "./feedbacks";
6
- import { IntelNamespace } from "./intel/index";
6
+ import { NewsNamespace } from "./news/index";
7
7
  import { JokesNamespace } from "./jokes";
8
8
  import { NotificationsNamespace } from "./notifications";
9
9
  import { ServiceUsagesNamespace } from "./serviceUsages";
@@ -13,7 +13,7 @@ import { SpaceInvadersNamespace } from "./spaceInvaders";
13
13
  export * from "./analysis";
14
14
  export * from "./blogs";
15
15
  export * from "./feedbacks";
16
- export * from "./intel/index";
16
+ export * from "./news/index";
17
17
  export * from "./jokes";
18
18
  export * from "./notifications";
19
19
  export * from "./serviceUsages";
@@ -46,7 +46,7 @@ export declare class ContentNamespace extends Resource {
46
46
  readonly analysis: AnalysisNamespace;
47
47
  /** The Space Invaders leaderboard. */
48
48
  readonly spaceInvaders: SpaceInvadersNamespace;
49
- /** Intel: articles, reports, sources, scripts, items, config and stats. See {@link IntelNamespace}. */
50
- readonly intel: IntelNamespace;
49
+ /** News: feeds, sources, scripts and the items they produce. See {@link NewsNamespace}. */
50
+ readonly news: NewsNamespace;
51
51
  constructor(http: ApiClient);
52
52
  }
@@ -0,0 +1,56 @@
1
+ /** News feeds: the named sets of sources a person follows. */
2
+ import { Resource } from "../../../http";
3
+ import type { ListParams } from "../../../listing";
4
+ import type { Id, Paginated, RequestOptions, Timestamp } from "../../../types";
5
+ /** At most this many feeds per account; one more is a `400`. */
6
+ export declare const NEWS_FEEDS_PER_ACCOUNT = 10;
7
+ /** `retention_days` outside this range is a `400`. */
8
+ export declare const NEWS_FEED_MIN_RETENTION_DAYS = 7;
9
+ export declare const NEWS_FEED_MAX_RETENTION_DAYS = 3650;
10
+ /**
11
+ * A feed: a named set of {@link NewsSource}s and the {@link NewsItem}s they
12
+ * produce. Several per account, unique by name; the oldest is the default
13
+ * one a source lands in when it names no feed.
14
+ */
15
+ export interface NewsFeed {
16
+ readonly id: Id;
17
+ readonly created_at: Timestamp;
18
+ readonly updated_at: Timestamp;
19
+ /** Up to 80 characters, whitespace-squished, unique per account. */
20
+ readonly name: string;
21
+ /** Up to 500 characters. */
22
+ readonly description: string | null;
23
+ /** Items older than this are pruned. Default 90. */
24
+ readonly retention_days: number;
25
+ /** A disabled feed's sources are not polled. */
26
+ readonly enabled: boolean;
27
+ }
28
+ /** `GET /news_feeds/:id` adds two live counters. */
29
+ export interface NewsFeedDetail extends NewsFeed {
30
+ readonly sources_count: number;
31
+ readonly items_count: number;
32
+ }
33
+ /** Filter columns of `GET /news_feeds`, on top of {@link BASE_FILTER_COLUMNS}. */
34
+ export declare const NEWS_FEED_FILTER_COLUMNS: readonly ["name", "enabled"];
35
+ export interface ListNewsFeedsParams extends ListParams<(typeof NEWS_FEED_FILTER_COLUMNS)[number]> {
36
+ }
37
+ export interface CreateNewsFeedInput {
38
+ readonly name: string;
39
+ readonly description?: string | null;
40
+ readonly retentionDays?: number;
41
+ readonly enabled?: boolean;
42
+ }
43
+ export type UpdateNewsFeedInput = Partial<CreateNewsFeedInput>;
44
+ /** `/news_feeds` - your feeds. Needs `news:read` to read and `news:write` to change. */
45
+ export declare class NewsFeedsNamespace extends Resource {
46
+ /** `GET /news_feeds` - your feeds, oldest first. */
47
+ list(params?: ListNewsFeedsParams, options?: RequestOptions): Promise<Paginated<NewsFeed>>;
48
+ /** `GET /news_feeds/:id` - one feed with its counters. 404 when it is not yours. */
49
+ get(id: Id, options?: RequestOptions): Promise<NewsFeedDetail>;
50
+ /** `POST /news_feeds`. `201`. 400 for a duplicate name or past the cap. */
51
+ create(input: CreateNewsFeedInput, options?: RequestOptions): Promise<NewsFeed>;
52
+ /** `PATCH /news_feeds/:id`. */
53
+ update(id: Id, input: UpdateNewsFeedInput, options?: RequestOptions): Promise<NewsFeed>;
54
+ /** `DELETE /news_feeds/:id` - the feed, its sources and every item. `204`. */
55
+ delete(id: Id, options?: RequestOptions): Promise<void>;
56
+ }
@@ -0,0 +1,36 @@
1
+ /** The `news` namespace and everything under it. */
2
+ import { type ApiClient, Resource } from "../../../http";
3
+ import { NewsFeedsNamespace } from "./feeds";
4
+ import { NewsItemsNamespace } from "./items";
5
+ import { NewsScriptsNamespace } from "./scripts";
6
+ import { NewsSourcesNamespace } from "./sources";
7
+ export * from "./feeds";
8
+ export * from "./items";
9
+ export * from "./scripts";
10
+ export * from "./sources";
11
+ /**
12
+ * The `news` namespace, reachable as `oms.content.news`: the ingestion side
13
+ * of following the web.
14
+ *
15
+ * 1. a {@link NewsScript} knows HOW to fetch one kind of source (RSS, a
16
+ * Telegram channel, a YouTube channel, a page with a selector);
17
+ * 2. a {@link NewsSource} is that script plus its settings, inside a
18
+ * {@link NewsFeed} - a named set of sources;
19
+ * 3. polling a source writes {@link NewsItem} rows: raw, one per thing the
20
+ * source published, full-text searchable and readable incrementally.
21
+ *
22
+ * Open to every account within its quotas (`news_sources` in
23
+ * `oms.quotas.list()`). Needs the `news:read` and `news:write` scopes on an
24
+ * OAuth token. Ids are strings throughout.
25
+ */
26
+ export declare class NewsNamespace extends Resource {
27
+ /** Named sets of sources. Full CRUD. */
28
+ readonly feeds: NewsFeedsNamespace;
29
+ /** The sources you follow. Full CRUD, plus a manual run. */
30
+ readonly sources: NewsSourcesNamespace;
31
+ /** The fetchers. Full CRUD over yours; the built-ins are read-only. */
32
+ readonly scripts: NewsScriptsNamespace;
33
+ /** What the sources produced. Read plus delete. */
34
+ readonly items: NewsItemsNamespace;
35
+ constructor(http: ApiClient);
36
+ }
@@ -0,0 +1,115 @@
1
+ /** News items: what the sources produced, raw. */
2
+ import { Resource } from "../../../http";
3
+ import type { ListParams } from "../../../listing";
4
+ import type { Id, Paginated, RequestOptions, Timestamp } from "../../../types";
5
+ /**
6
+ * A raw item, exactly as a script returned it.
7
+ *
8
+ * Written only by the ingest job; over HTTP it is read-only plus a delete.
9
+ * Items are the substrate everything downstream (a report, a story, a cron
10
+ * script) is built from - nothing copies the body, it points here.
11
+ */
12
+ export interface NewsItem {
13
+ readonly id: Id;
14
+ readonly created_at: Timestamp;
15
+ readonly updated_at: Timestamp;
16
+ /** The feed the source belonged to when the item was written. */
17
+ readonly news_feed_id: Id;
18
+ /** Which source produced it. */
19
+ readonly news_source_id: Id;
20
+ /**
21
+ * The script's own id for this item, unique per source. This is the
22
+ * de-duplication key: a second poll that returns the same `external_id` does
23
+ * not create a second row.
24
+ */
25
+ readonly external_id: string;
26
+ readonly title: string | null;
27
+ /** The body the script extracted. Can be large; a listing carries all of it. */
28
+ readonly content: string | null;
29
+ readonly url: string | null;
30
+ readonly author: string | null;
31
+ /** Publication time as the feed reported it, not as we saw it. */
32
+ readonly published_at: Timestamp | null;
33
+ /** When the poll that produced this item ran. Never null. */
34
+ readonly fetched_at: Timestamp;
35
+ /**
36
+ * Set when the item is a VIDEO the script discovered (YouTube, RTP Play):
37
+ * the server downloads the audio, transcribes it and splits it into news
38
+ * items. The video row itself stays as it is; the news it yields are child
39
+ * items pointing back via {@link parent_id}.
40
+ */
41
+ readonly media_url: string | null;
42
+ /**
43
+ * Transcription state of a video row: `pending` → `processing` →
44
+ * `transcribed` (the `content` now holds the `[m:ss] text` transcript) →
45
+ * `done`, or `failed` with {@link media_error}. `null` on non-video items.
46
+ */
47
+ readonly media_status: NewsMediaStatus | null;
48
+ readonly media_error: string | null;
49
+ /** On a news item cut from a video: the video (parent) item's id. */
50
+ readonly parent_id: Id | null;
51
+ /** On a news item cut from a video: where in the video it starts, in seconds. */
52
+ readonly media_offset_s: number | null;
53
+ }
54
+ /** Lifecycle of a video item's transcription. */
55
+ export type NewsMediaStatus = "pending" | "processing" | "transcribed" | "done" | "failed";
56
+ /** Filter columns of `GET /news_items`, on top of {@link BASE_FILTER_COLUMNS}. */
57
+ export declare const NEWS_ITEM_FILTER_COLUMNS: readonly ["news_feed_id", "news_source_id", "external_id", "title", "content", "url", "media_status", "parent_id"];
58
+ /** Filters for {@link NewsItemsNamespace.list}. */
59
+ export interface ListNewsItemsParams extends ListParams<(typeof NEWS_ITEM_FILTER_COLUMNS)[number]> {
60
+ /** Only items of one feed. Sent as `exact_search[news_feed_id]`. */
61
+ readonly feedId?: Id;
62
+ /** Only items produced by one source. Sent as `exact_search[news_source_id]`. */
63
+ readonly sourceId?: Id;
64
+ /**
65
+ * Full-text search over title and body, in Portuguese (stemmed, so
66
+ * `mesquitas` finds `mesquita`). Web-search syntax: quotes for a phrase,
67
+ * `-` to exclude, `or` between words. Results come by relevance when this
68
+ * is set, whatever `order` says.
69
+ */
70
+ readonly query?: string;
71
+ /** Only items written at or after this instant (ISO 8601). The incremental read a script wants. */
72
+ readonly since?: string;
73
+ /** Only items written at or before this instant (ISO 8601). */
74
+ readonly until?: string;
75
+ }
76
+ /**
77
+ * `/news_items` - the raw material.
78
+ *
79
+ * Read-only plus a delete: items are written by the ingest job and by
80
+ * nothing else.
81
+ */
82
+ export declare class NewsItemsNamespace extends Resource {
83
+ /**
84
+ * `GET /news_items` - raw items, newest first.
85
+ *
86
+ * **Heavy.** Every row carries {@link NewsItem.content} in full - the whole
87
+ * article text a script scraped - and there is no lighter view. The SDK
88
+ * defaults to a page of 25 for that reason; raising it is how you get a
89
+ * multi-megabyte response.
90
+ *
91
+ * For an incremental reader, remember the newest `created_at` you saw and
92
+ * pass it back as `since` with `order: "created_at:asc"`.
93
+ *
94
+ * The controller sets no ordering; the SDK sends `created_at:desc`.
95
+ *
96
+ * @throws {OmsApiError} 400 when `since` or `until` is not ISO 8601.
97
+ */
98
+ list(params?: ListNewsItemsParams, options?: RequestOptions): Promise<Paginated<NewsItem>>;
99
+ /**
100
+ * `GET /news_items/:id` - one raw item. Same shape a listing row has.
101
+ *
102
+ * @throws {OmsApiError} 404 when the item is not yours.
103
+ */
104
+ get(id: Id, options?: RequestOptions): Promise<NewsItem>;
105
+ /**
106
+ * `DELETE /news_items/:id`. `204`, empty body.
107
+ *
108
+ * Rarely what you want. The item's `external_id` uniqueness is what stops the
109
+ * next poll re-fetching it, so deleting one invites it straight back on the
110
+ * following run. Delete the SOURCE, or leave items alone.
111
+ *
112
+ * @throws {OmsApiError} 404 when the item is not yours.
113
+ */
114
+ delete(id: Id, options?: RequestOptions): Promise<void>;
115
+ }