UNPKG

@otters/monzo

Version:
399 lines (393 loc) 11 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { ID_PREFIXES: () => ID_PREFIXES, MonzoAPI: () => MonzoAPI, MonzoOAuthAPI: () => MonzoOAuthAPI, assertId: () => assertId, castId: () => castId, validateId: () => validateId }); module.exports = __toCommonJS(src_exports); // src/monzo.ts var import_http = require("alistair/http"); var import_pathcat = require("pathcat"); var import_qs = require("qs"); var MonzoAPI = class { credentials; app; api; config; constructor(credentialsOrBearer, app, config) { this.credentials = typeof credentialsOrBearer === "object" ? { token_type: "Bearer", ...credentialsOrBearer } : { token_type: "Bearer", access_token: credentialsOrBearer }; this.app = app; this.config = { base: "https://api.monzo.com", ...config }; this.api = (0, import_http.createHTTPClient)({ base: this.config.base, lifecycle: { before: async (request) => { request.headers.set( "Authorization", `${this.credentials.token_type} ${this.credentials.access_token}` ); return request; } } }); } /** * Calls the logout endpoint. This will immediately invalidate the access token. * Once invalidated, the user must go through the authentication process again. You will not be able to refresh the access token. */ async logout() { await this.api.post("/ping/logout"); } /** * Refreshes the access token. This will invalidate the current access token and return a new one. * You'll have to reinstantiate the API client with the new token. * * You must pass the full user credentials and app credentials to the constructor, otherwise this method will throw. * * @returns The new credentials to use for requests. * * @example * ```ts * const app: AppCredentials = { * client_id: 'oauth2client_00001abc...', * client_secret: '...', * redirect_uri: '...', * } * * const current = new MonzoAPI( * { * access_token: '...', * refresh_token: '...', * }, * app, * ); * const creds = await current.refresh(); * const refreshed = new MonzoAPI(creds, app); * ``` */ async refresh() { if (typeof this.credentials === "string" || !("refresh_token" in this.credentials) || !this.app) { throw new Error( "No app or user credentials provided. You must provide the full constructor arguments to use .refresh()" ); } return this.api.post("/oauth2/token", { headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: (0, import_qs.stringify)({ grant_type: "refresh_token", client_id: this.app.client_id, client_secret: this.app.client_secret, refresh_token: this.credentials.refresh_token }) }); } /** * Gets information about the authenticated user. * @returns Information about the authenticated user. */ async whoami() { return this.api.get("/ping/whoami"); } async getAccounts(account_type) { const url = (0, import_pathcat.pathcat)("/accounts", { account_type }); const { accounts } = await this.api.get(url); return accounts; } async getBalance(account_id) { return this.api.get((0, import_pathcat.pathcat)("/balance", { account_id })); } async getPots(current_account_id) { const url = (0, import_pathcat.pathcat)("/pots", { current_account_id }); const { pots } = await this.api.get(url); return pots; } async depositIntoPot(pot, { amount, dedupe_id, source_account_id }) { const url = (0, import_pathcat.pathcat)("/pots/:pot_id/deposit", { pot_id: pot }); return this.api.put(url, { headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: (0, import_qs.stringify)({ dedupe_id, source_account_id, amount: amount.toString() }) }); } async withdrawFromPot(pot, { destination_account_id, amount, dedupe_id }) { const url = (0, import_pathcat.pathcat)("/pots/:pot_id/withdraw", { pot_id: pot }); return this.api.put(url, { headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: (0, import_qs.stringify)({ dedupe_id, destination_account_id, amount: amount.toString() }) }); } async getTransaction(transaction_id, expand) { const url = (0, import_pathcat.pathcat)("/transactions/:transaction_id", { transaction_id, "expand[]": expand }); const { transaction } = await this.api.get(url); return transaction; } async getTransactions(account_id, pagination) { const url = (0, import_pathcat.pathcat)("/transactions", { account_id, ...pagination }); const { transactions } = await this.api.get(url); return transactions; } async annotateTransaction(transaction_id, metadata) { const url = (0, import_pathcat.pathcat)("/transactions/:transaction_id", { transaction_id }); const { transaction } = await this.api.patch( url, { headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: (0, import_qs.stringify)(metadata) } ); return transaction; } async createFeedItem(account_id, type, params) { const { url, ...rest } = params; await this.api.post("/feed", { headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: (0, import_qs.stringify)({ params: rest, url, account_id, type }) }); } async uploadAttachment(file_name, file_type, content_length) { return this.api.post("/attachment/upload", { body: (0, import_qs.stringify)({ file_name, file_type, content_length }), headers: { "Content-Type": "application/x-www-form-urlencoded" } }); } async registerAttachment(external_id, file_url, file_type) { const { attachment } = await this.api.post("/attachment/register", { body: (0, import_qs.stringify)({ external_id, file_url, file_type }), headers: { "Content-Type": "application/x-www-form-urlencoded" } }); return attachment; } async deregisterAttachment(attachment_id) { await this.api.post("/attachment/deregister", { body: (0, import_qs.stringify)({ id: attachment_id }), headers: { "Content-Type": "application/x-www-form-urlencoded" } }); } async createReceipt(transaction_id, receipt) { await this.api.put("/transaction-receipts", { body: { transaction_id, ...receipt } }); } async retrieveReceipt(external_id) { const url = (0, import_pathcat.pathcat)("/transaction-receipts", { external_id }); const { receipt } = await this.api.get(url); return receipt; } async deleteReceipt(external_id) { const url = (0, import_pathcat.pathcat)("/transaction-receipts", { external_id }); await this.api.delete(url); } async registerWebhook(account_id, webhookUrl) { const { webhook } = await this.api.post("/webhooks", { body: (0, import_qs.stringify)({ account_id, url: webhookUrl }), headers: { "Content-Type": "application/x-www-form-urlencoded" } }); return webhook; } async listWebhooks(account_id) { const url = (0, import_pathcat.pathcat)("/webhooks", { account_id }); const { webhooks } = await this.api.get(url); return webhooks; } async deleteWebhook(id2) { const url = (0, import_pathcat.pathcat)("/webhooks/:id", { id: id2 }); await this.api.delete(url); } }; // src/oauth.ts var import_http2 = require("alistair/http"); var import_id = require("alistair/id"); var import_pathcat2 = require("pathcat"); // src/types.ts var ID_PREFIXES = [ "acc", "pot", "user", "oauth2client", "tx", "grp", "merch", "business", "entryset", "obextpayment", "potdep", "anonuser", "mcauthmsg", "mclifecycle", "mccard", "tab", "participant", "attach", "sub", "potwdr", "copdecision", "series", "p2p", "billsplit", "payreq", "inbndp2p", "trip", "receipt", "webhook" ]; function validateId(maybeId, prefix) { if (prefix) { return maybeId.startsWith(`${prefix}_`); } return ID_PREFIXES.some((prefix2) => maybeId.startsWith(`${prefix2}_`)); } function assertId(maybeId, prefix) { const result = prefix ? validateId(maybeId, prefix) : validateId(maybeId); if (!result) { throw new Error(`Invalid id: ${maybeId}`); } } function castId(maybeId, prefix) { if (!validateId(maybeId, prefix)) { throw new Error("Cannot cast a non-id string to an id."); } return maybeId; } // src/oauth.ts var MonzoOAuthAPI = class { credentials; api; config; constructor(credentials, config) { this.credentials = credentials; this.config = { base: "https://api.monzo.com", ...config }; this.api = (0, import_http2.createHTTPClient)({ base: this.config.base }); } getOAuthURL(state) { const s = state ?? (0, import_id.id)(16, "abcdef0123456789"); const url = (0, import_pathcat2.pathcat)("https://auth.monzo.com", { client_id: this.credentials.client_id, redirect_uri: this.credentials.redirect_uri, response_type: "code", state: s }); return state ? url : { state: s, url }; } async exchangeAuthorizationCode(code) { const creds = await this.api.post("/oauth2/token", { headers: { "Content-Type": "application/x-www-form-urlencoded" }, body: new URLSearchParams({ grant_type: "authorization_code", client_id: this.credentials.client_id, client_secret: this.credentials.client_secret, redirect_uri: this.credentials.redirect_uri, code }) }); return new MonzoAPI(creds, this.credentials, this.config); } }; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { ID_PREFIXES, MonzoAPI, MonzoOAuthAPI, assertId, castId, validateId });