instapaper-api 0.1.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.
@@ -0,0 +1,452 @@
1
+ /** The subset of `RequestInit` this SDK passes to `fetch`. */
2
+ interface FetchInit {
3
+ method: string;
4
+ headers: Record<string, string>;
5
+ body?: string;
6
+ signal?: AbortSignal;
7
+ /** Always `manual`, so credentials are never resent to wherever a redirect points. */
8
+ redirect: 'manual';
9
+ }
10
+ /** The subset of `Response` this SDK reads. */
11
+ interface FetchResponse {
12
+ status: number;
13
+ ok: boolean;
14
+ text(): Promise<string>;
15
+ }
16
+ /** A `fetch`-compatible function. The global `fetch` satisfies this. */
17
+ type FetchLike = (url: string, init: FetchInit) => Promise<FetchResponse>;
18
+ type QueryValue = string | number | boolean | undefined | null;
19
+ interface TransportOptions {
20
+ baseUrl?: string;
21
+ /** Request timeout in milliseconds. `0` disables it. Defaults to 30 seconds. */
22
+ timeout?: number;
23
+ /** A custom `fetch`. Defaults to the global one. */
24
+ fetch?: FetchLike;
25
+ }
26
+ interface SendOptions {
27
+ query?: Record<string, QueryValue>;
28
+ headers?: Record<string, string>;
29
+ body?: string;
30
+ }
31
+ interface RawResponse {
32
+ status: number;
33
+ ok: boolean;
34
+ text: string;
35
+ }
36
+ /** Low-level request plumbing shared by the API client and the OAuth helper. */
37
+ declare class Transport {
38
+ readonly baseUrl: string;
39
+ readonly timeout: number;
40
+ private readonly fetchImpl;
41
+ constructor(options?: TransportOptions);
42
+ url(path: string, query?: Record<string, QueryValue>): string;
43
+ send(method: string, path: string, options?: SendOptions): Promise<RawResponse>;
44
+ }
45
+ interface RequestOptions {
46
+ query?: Record<string, QueryValue>;
47
+ json?: unknown;
48
+ /** Whether a successful response must be a JSON object. `false` for empty-body endpoints. */
49
+ expectJson?: boolean;
50
+ }
51
+ /** JSON API requests with bearer auth and error mapping. */
52
+ declare class ApiClient {
53
+ private readonly transport;
54
+ private readonly accessToken;
55
+ constructor(transport: Transport, accessToken: string);
56
+ request<T>(method: string, path: string, options?: RequestOptions): Promise<T>;
57
+ }
58
+
59
+ /**
60
+ * Response types for the Instapaper API v2.
61
+ *
62
+ * Field names match the JSON the API returns exactly (snake_case), so there is
63
+ * no mapping layer between what the server sends and what you get back.
64
+ */
65
+ /** Which list of bookmarks to read. */
66
+ type BookmarkSection = 'home' | 'archive' | 'liked' | 'folder' | 'tag';
67
+ /**
68
+ * Known values of `Bookmark.category`. New categories may be added, so treat
69
+ * an unknown value as an article.
70
+ */
71
+ declare const BookmarkCategory: {
72
+ readonly Article: 0;
73
+ readonly Email: 1;
74
+ readonly Video: 2;
75
+ readonly PDF: 3;
76
+ readonly Social: 4;
77
+ };
78
+ type BookmarkCategory = (typeof BookmarkCategory)[keyof typeof BookmarkCategory];
79
+ interface User {
80
+ /** Stable numeric ID. Store this as your reference to the user. */
81
+ id: number;
82
+ /** Usually an email address. Display only; it can change. */
83
+ username: string;
84
+ /** Whether the account has an active Instapaper Premium subscription. */
85
+ premium: boolean;
86
+ }
87
+ interface Tag {
88
+ id: number;
89
+ name: string;
90
+ slug: string;
91
+ count: number;
92
+ /** Reserved for Instapaper's own clients; always `null` here. */
93
+ baton: string | null;
94
+ }
95
+ interface Progress {
96
+ /** Reading progress from 0.0 to 1.0. */
97
+ percentage: number;
98
+ /** When the progress was recorded, as a Unix timestamp. */
99
+ timestamp: number;
100
+ }
101
+ interface Bookmark {
102
+ id: number;
103
+ /** `null` for private content saved without a URL. */
104
+ url: string | null;
105
+ title: string | null;
106
+ description: string | null;
107
+ image: string | null;
108
+ progress: Progress;
109
+ liked: boolean;
110
+ archived: boolean;
111
+ /** When the bookmark was saved, as a Unix timestamp. */
112
+ time: number;
113
+ /** When the article was published, as a Unix timestamp, if known. */
114
+ pubtime: number | null;
115
+ author: string | null;
116
+ /** The folder it's in, or `null` when it's in the home list. */
117
+ folder_id: number | null;
118
+ tags: Tag[];
119
+ private_source: string | null;
120
+ /** See {@link BookmarkCategory}. May hold values this SDK doesn't know yet. */
121
+ category: number;
122
+ }
123
+ interface Folder {
124
+ id: number;
125
+ title: string;
126
+ slug: string;
127
+ position: number;
128
+ public: boolean;
129
+ count: number;
130
+ }
131
+ interface Highlight {
132
+ id: number;
133
+ bookmark_id: number;
134
+ text: string;
135
+ note: string | null;
136
+ /** Which occurrence of `text` in the article body this highlight marks, counting from 0. */
137
+ position: number;
138
+ /** When it was created, as a Unix timestamp. */
139
+ time: number;
140
+ }
141
+ interface ArticleAuthor {
142
+ name: string;
143
+ url: string | null;
144
+ }
145
+ interface ArticleMetadata {
146
+ title: string | null;
147
+ author: ArticleAuthor | null;
148
+ pubtime: number | null;
149
+ thumbnail: string | null;
150
+ description: string | null;
151
+ private_source: string | null;
152
+ category: number;
153
+ }
154
+ interface ArticleContent {
155
+ /** Article HTML, UTF-8, with scripts stripped. */
156
+ body: string | null;
157
+ images: string[];
158
+ words: number | null;
159
+ paywalled: boolean;
160
+ /** `ltr` or `rtl`. */
161
+ direction: string | null;
162
+ }
163
+ interface ParsedArticle {
164
+ metadata: ArticleMetadata;
165
+ content: ArticleContent;
166
+ }
167
+ interface BookmarkList {
168
+ bookmarks: Bookmark[];
169
+ /** Size of the whole section, not of this page. */
170
+ total: number;
171
+ }
172
+ interface BookmarkChanges {
173
+ bookmarks: Bookmark[];
174
+ /** IDs of bookmarks deleted since the timestamp. */
175
+ deleted_ids: number[];
176
+ /** Number of changed bookmarks. */
177
+ total: number;
178
+ }
179
+ interface TagChanges {
180
+ /** Tags this call created. */
181
+ created_tags: Tag[];
182
+ /** The bookmark's full tag list afterwards. */
183
+ tags: Tag[];
184
+ }
185
+ /** The user included in a token response. */
186
+ interface TokenUser {
187
+ id: number;
188
+ username: string;
189
+ }
190
+ interface AccessToken {
191
+ access_token: string;
192
+ token_type: string;
193
+ user: TokenUser;
194
+ }
195
+
196
+ interface ListBookmarksOptions {
197
+ /** Defaults to `home`, or to the section implied by `folderId` or `tag`. */
198
+ section?: BookmarkSection;
199
+ folderId?: number;
200
+ /** Tag name. Can't be combined with `folderId`. */
201
+ tag?: string;
202
+ /** 1 to 500. Defaults to 25. */
203
+ limit?: number;
204
+ offset?: number;
205
+ }
206
+ interface IterateBookmarksOptions {
207
+ section?: BookmarkSection;
208
+ folderId?: number;
209
+ tag?: string;
210
+ /** Bookmarks fetched per request, 1 to 500. Defaults to 100. */
211
+ pageSize?: number;
212
+ }
213
+ interface ChangesOptions {
214
+ /** 1 to 500. Defaults to 500. */
215
+ limit?: number;
216
+ offset?: number;
217
+ }
218
+ interface SyncOptions {
219
+ /** Changes fetched per request, 1 to 500. Defaults to 500. */
220
+ pageSize?: number;
221
+ }
222
+ interface SaveBookmarkOptions {
223
+ /** Required unless `privateSource` is set. */
224
+ url?: string;
225
+ /** Send it if you have it; otherwise the title is looked up, which is slower. */
226
+ title?: string;
227
+ description?: string;
228
+ folderId?: number;
229
+ archived?: boolean;
230
+ /** `false` skips resolving redirects and canonicalizing the URL. */
231
+ canonicalize?: boolean;
232
+ /** Tag names. Tags that don't exist yet are created. */
233
+ tags?: string[];
234
+ /** Full article HTML, if you already have it. Required with `privateSource`. */
235
+ content?: string;
236
+ /** A short label naming where private content came from. Used instead of `url`. */
237
+ privateSource?: string;
238
+ }
239
+ interface UpdateBookmarkOptions {
240
+ title?: string;
241
+ description?: string;
242
+ /** Reading progress from 0.0 to 1.0. */
243
+ progress?: number;
244
+ /** When the progress was recorded, as a Unix timestamp. Defaults to now. */
245
+ progressTimestamp?: number;
246
+ }
247
+ interface UpdateTagsOptions {
248
+ /** Tag names (created if needed) or tag IDs to add. */
249
+ add?: Array<string | number>;
250
+ /** Tag IDs to remove. */
251
+ remove?: number[];
252
+ }
253
+ interface ParseOptions {
254
+ /** `false` bypasses the parser cache. Defaults to `true`. */
255
+ useCache?: boolean;
256
+ /** Force a re-parse rather than serving a stored copy. Defaults to `false`. */
257
+ force?: boolean;
258
+ /** HTML you already have for the article, parsed instead of fetching the URL. */
259
+ content?: string;
260
+ /** Your Instaparser key, required for non-personal use. */
261
+ instaparserApiKey?: string;
262
+ }
263
+ /** List, save, update, move, like, tag, delete, and parse bookmarks. */
264
+ declare class Bookmarks {
265
+ private readonly api;
266
+ constructor(api: ApiClient);
267
+ /** One page of bookmarks from a section. */
268
+ list(options?: ListBookmarksOptions): Promise<BookmarkList>;
269
+ /** Every bookmark in a section, fetching pages as you go. */
270
+ iterate(options?: IterateBookmarksOptions): AsyncIterableIterator<Bookmark>;
271
+ /** One page of bookmarks changed since a time, across every section, plus deleted IDs. */
272
+ changes(since: number | Date, options?: ChangesOptions): Promise<BookmarkChanges>;
273
+ /**
274
+ * Everything changed since a time, fetching every page. Record when you
275
+ * started the sync and pass it as `since` next time.
276
+ */
277
+ sync(since: number | Date, options?: SyncOptions): Promise<BookmarkChanges>;
278
+ /** Save a URL, or private content. Saving a URL twice updates the existing bookmark. */
279
+ save(options: SaveBookmarkOptions): Promise<Bookmark>;
280
+ /** Change a bookmark's title, description, or reading progress. */
281
+ update(bookmarkId: number, options: UpdateBookmarkOptions): Promise<Bookmark>;
282
+ /** Permanently delete a bookmark. This is not the same as archiving. */
283
+ delete(bookmarkId: number): Promise<void>;
284
+ archive(bookmarkId: number): Promise<Bookmark>;
285
+ /** Move a bookmark back to the home list. */
286
+ unarchive(bookmarkId: number): Promise<Bookmark>;
287
+ moveToFolder(bookmarkId: number, folderId: number): Promise<Bookmark>;
288
+ like(bookmarkId: number): Promise<Bookmark>;
289
+ unlike(bookmarkId: number): Promise<Bookmark>;
290
+ /** Add tags (by name or ID) to a bookmark and remove tags (by ID) from it. */
291
+ updateTags(bookmarkId: number, options: UpdateTagsOptions): Promise<TagChanges>;
292
+ /** Instapaper's parsed, reader-ready version of a saved article. */
293
+ parse(bookmarkId: number, options?: ParseOptions): Promise<ParsedArticle>;
294
+ private move;
295
+ }
296
+
297
+ interface FolderPosition {
298
+ folderId: number;
299
+ position: number;
300
+ }
301
+ /** List, create, reorder, and delete a user's folders. */
302
+ declare class Folders {
303
+ private readonly api;
304
+ constructor(api: ApiClient);
305
+ /** The user's folders, in their own order. */
306
+ list(): Promise<Folder[]>;
307
+ create(title: string): Promise<Folder>;
308
+ /** Delete a folder. Its bookmarks move back to the home list. */
309
+ delete(folderId: number): Promise<void>;
310
+ /**
311
+ * Set folder positions, as a `{ folderId: position }` map or a list. Folders
312
+ * you leave out keep their positions. Returns every folder in its new order.
313
+ */
314
+ reorder(positions: Record<number, number> | FolderPosition[]): Promise<Folder[]>;
315
+ }
316
+
317
+ interface CreateHighlightOptions {
318
+ /** The highlighted text. Leading and trailing whitespace is trimmed by the API. */
319
+ text: string;
320
+ note?: string;
321
+ /**
322
+ * Which occurrence of `text` in the article body to highlight, counting
323
+ * from 0. Defaults to 0, the first occurrence.
324
+ */
325
+ position?: number;
326
+ }
327
+ /** Read, create, and delete highlights on a bookmark. */
328
+ declare class Highlights {
329
+ private readonly api;
330
+ constructor(api: ApiClient);
331
+ list(bookmarkId: number): Promise<Highlight[]>;
332
+ /**
333
+ * Create a highlight. Accounts without Premium can create five per month;
334
+ * past that this throws a `PermissionDeniedError`.
335
+ */
336
+ create(bookmarkId: number, options: CreateHighlightOptions): Promise<Highlight>;
337
+ /**
338
+ * Delete a highlight. Throws `BadRequestError` if the highlight doesn't
339
+ * exist, belongs to someone else, or was already deleted.
340
+ */
341
+ delete(highlightId: number): Promise<void>;
342
+ }
343
+
344
+ /** List, create, and rename a user's tags. */
345
+ declare class Tags {
346
+ private readonly api;
347
+ constructor(api: ApiClient);
348
+ list(): Promise<Tag[]>;
349
+ create(name: string): Promise<Tag>;
350
+ rename(tagId: number, name: string): Promise<Tag>;
351
+ }
352
+
353
+ interface InstapaperOptions extends TransportOptions {
354
+ /** A personal access token, or one issued through the OAuth flow. */
355
+ accessToken: string;
356
+ }
357
+ /** Client for the Instapaper API v2. */
358
+ declare class Instapaper {
359
+ readonly bookmarks: Bookmarks;
360
+ readonly folders: Folders;
361
+ readonly tags: Tags;
362
+ readonly highlights: Highlights;
363
+ private readonly api;
364
+ constructor(options: InstapaperOptions);
365
+ /** The account the access token belongs to. */
366
+ me(): Promise<User>;
367
+ }
368
+
369
+ interface OAuthOptions extends TransportOptions {
370
+ clientId: string;
371
+ clientSecret: string;
372
+ /** Must match one of the application's registered callback URIs exactly. */
373
+ redirectUri: string;
374
+ }
375
+ interface AuthorizationUrlOptions {
376
+ /** An opaque value echoed back to your redirect URI. Use it to defend against CSRF. */
377
+ state?: string;
378
+ }
379
+ /** Helpers for the OAuth 2 authorization code flow. */
380
+ declare class OAuth {
381
+ readonly clientId: string;
382
+ readonly redirectUri: string;
383
+ private readonly clientSecret;
384
+ private readonly transport;
385
+ constructor(options: OAuthOptions);
386
+ /** The URL to send the user to so they can authorize your application. */
387
+ authorizationUrl(options?: AuthorizationUrlOptions): string;
388
+ /** Exchange the code from your redirect URI for an access token. Codes work once. */
389
+ exchangeCode(code: string): Promise<AccessToken>;
390
+ }
391
+
392
+ /** Base class for every error this SDK throws. */
393
+ declare class InstapaperError extends Error {
394
+ constructor(message: string, options?: {
395
+ cause?: unknown;
396
+ });
397
+ }
398
+ /** The API answered with an error status. */
399
+ declare class APIError extends InstapaperError {
400
+ /** HTTP status code. */
401
+ readonly status: number;
402
+ /** The parsed JSON body, the raw text if it wasn't JSON, or `undefined` if empty. */
403
+ readonly body: unknown;
404
+ constructor(message: string, status: number, body?: unknown);
405
+ }
406
+ /** 400: the request was malformed, or an argument was missing or invalid. */
407
+ declare class BadRequestError extends APIError {
408
+ constructor(message: string, status?: number, body?: unknown);
409
+ }
410
+ /** 401: the access token is missing, unknown, or revoked. */
411
+ declare class AuthenticationError extends APIError {
412
+ constructor(message: string, status?: number, body?: unknown);
413
+ }
414
+ /** 402: an external content quota is exhausted (e.g. Instaparser credits). */
415
+ declare class QuotaExceededError extends APIError {
416
+ constructor(message: string, status?: number, body?: unknown);
417
+ }
418
+ /** 403: authenticated, but not allowed (unapproved or suspended app, or a Premium feature). */
419
+ declare class PermissionDeniedError extends APIError {
420
+ constructor(message: string, status?: number, body?: unknown);
421
+ }
422
+ /** 404: no such endpoint. */
423
+ declare class NotFoundError extends APIError {
424
+ constructor(message: string, status?: number, body?: unknown);
425
+ }
426
+ /** 429: rate limited. Back off and retry later. */
427
+ declare class RateLimitError extends APIError {
428
+ constructor(message: string, status?: number, body?: unknown);
429
+ }
430
+ /** 5xx: something went wrong on Instapaper's side. Retry with backoff. */
431
+ declare class ServerError extends APIError {
432
+ constructor(message: string, status?: number, body?: unknown);
433
+ }
434
+ /** The OAuth token endpoint rejected a request (RFC 6749 error response). */
435
+ declare class OAuthError extends InstapaperError {
436
+ readonly status: number;
437
+ /** The OAuth error code, e.g. `invalid_grant`. */
438
+ readonly error: string;
439
+ readonly description: string;
440
+ constructor(status: number, error: string, description: string);
441
+ }
442
+ /** The request never got a response: a network failure or a timeout. */
443
+ declare class InstapaperConnectionError extends InstapaperError {
444
+ constructor(message: string, options?: {
445
+ cause?: unknown;
446
+ });
447
+ }
448
+
449
+ /** The SDK version, sent in the User-Agent header where the runtime allows it. */
450
+ declare const VERSION = "0.1.0";
451
+
452
+ export { APIError, type AccessToken, type ArticleAuthor, type ArticleContent, type ArticleMetadata, AuthenticationError, type AuthorizationUrlOptions, BadRequestError, type Bookmark, BookmarkCategory, type BookmarkChanges, type BookmarkList, type BookmarkSection, Bookmarks, type ChangesOptions, type CreateHighlightOptions, type FetchInit, type FetchLike, type FetchResponse, type Folder, type FolderPosition, Folders, type Highlight, Highlights, Instapaper, InstapaperConnectionError, InstapaperError, type InstapaperOptions, type IterateBookmarksOptions, type ListBookmarksOptions, NotFoundError, OAuth, OAuthError, type OAuthOptions, type ParseOptions, type ParsedArticle, PermissionDeniedError, type Progress, QuotaExceededError, RateLimitError, type SaveBookmarkOptions, ServerError, type SyncOptions, type Tag, type TagChanges, Tags, type TokenUser, type UpdateBookmarkOptions, type UpdateTagsOptions, type User, VERSION };