UNPKG

instapaper-ts

Version:

A type-safe API client for Instapaper.

115 lines (114 loc) 3.94 kB
// src/index.ts import assert from "assert"; import crypto from "crypto"; import OAuth from "oauth-1.0a"; var Instapaper = class _Instapaper { baseUrl = "https://www.instapaper.com/api"; oauth; token; constructor({ consumerKey, consumerSecret, token }) { this.oauth = new OAuth({ consumer: { key: consumerKey, secret: consumerSecret }, signature_method: "HMAC-SHA1", hash_function: (base_string, key) => crypto.createHmac("sha1", key).update(base_string).digest("base64") }); this.token = token; } static async fetchToken({ consumerKey, consumerSecret, username, password }) { const oauth = new OAuth({ consumer: { key: consumerKey, secret: consumerSecret }, signature_method: "HMAC-SHA1", hash_function: (base_string, key2) => crypto.createHmac("sha1", key2).update(base_string).digest("base64") }); const responseText = await _Instapaper.postForm( oauth, "https://www.instapaper.com/api/1/oauth/access_token", { x_auth_username: username, x_auth_password: password, x_auth_mode: "client_auth" } ); const data = new URLSearchParams(responseText); const key = data.get("oauth_token"); const secret = data.get("oauth_token_secret"); assert(key && secret, "Token exchange failed: key or secret is null."); return { key, secret }; } static async postForm(oauth, url, params = {}, token) { const form = new URLSearchParams(); for (const [key, val] of Object.entries(params)) { form.append(key, String(val)); } const headers = oauth.toHeader( oauth.authorize({ url, method: "POST", data: params }, token) ); const response = await fetch(url, { method: "POST", headers: new Headers({ ...headers }), body: form }); if (!response.ok) { const errorText = await response.text(); throw new Error(`API error: ${response.status} ${errorText}`); } const contentType = response.headers.get("content-type") ?? ""; return contentType.includes("application/json") ? response.json() : response.text(); } request = (endpoint, params = {}) => _Instapaper.postForm( this.oauth, this.baseUrl + endpoint, params, this.token ); verifyCredentials = () => this.request("/1/account/verify_credentials"); bookmarks = { list: (params = {}) => this.request( "/1/bookmarks/list", params ), updateReadProgress: (params) => this.request( "/1/bookmarks/update_read_progress", params ), add: (params) => this.request("/1/bookmarks/add", params), delete: (bookmark_id) => this.request("/1/bookmarks/delete", { bookmark_id }), star: (bookmark_id) => this.request("/1/bookmarks/star", { bookmark_id }), unstar: (bookmark_id) => this.request("/1/bookmarks/unstar", { bookmark_id }), archive: (bookmark_id) => this.request("/1/bookmarks/archive", { bookmark_id }), unarchive: (bookmark_id) => this.request("/1/bookmarks/unarchive", { bookmark_id }), move: (bookmark_id, folder_id) => this.request("/1/bookmarks/move", { bookmark_id, folder_id }), getText: (bookmark_id) => this.request("/1/bookmarks/get_text", { bookmark_id }) }; folders = { list: () => this.request("/1/folders/list"), add: (title) => this.request("/1/folders/add", { title }), delete: (folder_id) => this.request("/1/folders/delete", { folder_id }), setOrder: (order) => this.request("/1/folders/set_order", { order }) }; highlights = { list: (bookmark_id) => this.request( `/1.1/bookmarks/${bookmark_id}/highlights` ), add: (params) => this.request( `/1.1/bookmarks/${params.bookmark_id}/highlight`, { text: params.text, position: params.position } ), delete: (highlight_id) => this.request(`/1.1/highlights/${highlight_id}/delete`) }; }; export { Instapaper };