UNPKG

investec-card-api

Version:

A simple package for interacting with Investec's programmable banking card API

362 lines (359 loc) 12.3 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; 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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { InvestecCardApi: () => InvestecCardApi }); module.exports = __toCommonJS(index_exports); // src/investec-card-api.ts var import_node_fetch = __toESM(require("node-fetch"), 1); var createEndpoint = (host, path) => new URL(path, host).toString(); var InvestecCardApi = class { /** The API host URL. */ host; /** The OAuth client ID. */ clientId; /** The OAuth client secret. */ clientSecret; /** The Investec API key. */ apiKey; /** The current OAuth token. */ token; /** The token expiry date. */ expiresIn; /** * Constructs a new InvestecCardApi instance. * @param clientId - OAuth client ID * @param clientSecret - OAuth client secret * @param apiKey - Investec API key * @param host - API host URL (default: 'https://openapi.investec.com') */ constructor(clientId, clientSecret, apiKey, host = "https://openapi.investec.com") { this.host = host; this.apiKey = apiKey; this.clientId = clientId; this.clientSecret = clientSecret; this.expiresIn = /* @__PURE__ */ new Date(); } /** * Gets a valid OAuth token, refreshing if necessary. * @returns The OAuth token string. * @throws Error if token cannot be retrieved. */ async getToken() { const now = /* @__PURE__ */ new Date(); if (this.token) { if (now.getTime() < this.expiresIn.getTime()) { return this.token; } } const result = await this.getAccessToken(); now.setSeconds(now.getSeconds() + result.expires_in); this.expiresIn = now; return result.access_token; } /** * Requests a new OAuth access token from Investec. * @returns The AuthResponse object. * @throws Error if authentication fails or the cards scope is missing. */ async getAccessToken() { const endpoint = createEndpoint(this.host, `/identity/v2/oauth2/token`); const response = await (0, import_node_fetch.default)(endpoint, { method: "POST", headers: { Authorization: "Basic " + Buffer.from(this.clientId + ":" + this.clientSecret).toString("base64"), "x-api-key": this.apiKey, "content-type": "application/x-www-form-urlencoded" }, body: "grant_type=client_credentials" }); if (response.status !== 200) { throw new Error(response.statusText); } const result = await response.json(); if (!result.scope.includes("cards")) { throw new Error("You require the cards scope to use this tool"); } this.token = result.access_token; return result; } /** * Uploads environment variables to a programmable card. * @param cardKey - The card key * @param env - The environment variables object * @returns The EnvResponse object * @throws Error if parameters are missing or the request fails. */ async uploadEnv(cardKey, env) { if (!cardKey || !env) { throw new Error("Missing required parameters"); } const endpoint = createEndpoint( this.host, `/za/v1/cards/${encodeURIComponent(cardKey.toString())}/environmentvariables` ); const token = this.token || await this.getToken(); return fetchPost(endpoint, token, env); } /** * Uploads code to a programmable card. * @param cardKey - The card key * @param code - The code object * @returns The CodeResponse object * @throws Error if parameters are missing or the request fails. */ async uploadCode(cardKey, code) { if (!cardKey || !code) { throw new Error("Missing required parameters"); } const endpoint = createEndpoint( this.host, `/za/v1/cards/${encodeURIComponent(cardKey.toString())}/code` ); const token = this.token || await this.getToken(); return fetchPost(endpoint, token, code); } /** * Publishes code to a programmable card. * @param cardKey - The card key * @param codeId - The code ID * @param code - The code string * @returns The CodeResponse object * @throws Error if parameters are missing or the request fails. */ async uploadPublishedCode(cardKey, codeId, code) { if (!cardKey || !codeId || !code) { throw new Error("Missing required parameters"); } const raw = { code, codeId }; const endpoint = createEndpoint( this.host, `/za/v1/cards/${encodeURIComponent(cardKey.toString())}/publish` ); const token = this.token || await this.getToken(); return fetchPost(endpoint, token, raw); } /** * Retrieves all programmable cards for the authenticated user. * @returns The CardResponse object * @throws Error if the request fails. */ async getCards() { const endpoint = createEndpoint(this.host, `/za/v1/cards`); const token = this.token || await this.getToken(); return fetchGet(endpoint, token); } /** * Retrieves environment variables for a programmable card. * @param cardKey - The card key * @returns The EnvResponse object * @throws Error if parameters are missing or the request fails. */ async getEnv(cardKey) { if (!cardKey) { throw new Error("Missing required parameters"); } const endpoint = createEndpoint( this.host, `/za/v1/cards/${encodeURIComponent(cardKey.toString())}/environmentvariables` ); const token = this.token || await this.getToken(); return fetchGet(endpoint, token); } /** * Retrieves code for a programmable card. * @param cardKey - The card key * @returns The CodeResponse object * @throws Error if parameters are missing or the request fails. */ async getCode(cardKey) { if (!cardKey) { throw new Error("Missing required parameters"); } const endpoint = createEndpoint( this.host, `/za/v1/cards/${encodeURIComponent(cardKey.toString())}/code` ); const token = this.token || await this.getToken(); return fetchGet(endpoint, token); } /** * Retrieves published code for a programmable card. * @param cardKey - The card key * @returns The CodeResponse object * @throws Error if parameters are missing or the request fails. */ async getPublishedCode(cardKey) { if (!cardKey) { throw new Error("Missing required parameters"); } const endpoint = createEndpoint( this.host, `/za/v1/cards/${encodeURIComponent(cardKey.toString())}/publishedcode` ); const token = this.token || await this.getToken(); return fetchGet(endpoint, token); } /** * Enables or disables programmable features on a card. * @param cardKey - The card key * @param enabled - Whether to enable the feature * @returns The CodeToggle object * @throws Error if parameters are missing or the request fails. */ async toggleCode(cardKey, enabled) { if (!cardKey || enabled === void 0) { throw new Error("Missing required parameters"); } const endpoint = createEndpoint( this.host, `/za/v1/cards/${encodeURIComponent(cardKey.toString())}/toggle-programmable-feature` ); const token = this.token || await this.getToken(); return fetchPost(endpoint, token, { Enabled: enabled }); } /** * Retrieves code execution results for a programmable card. * @param cardKey - The card key * @returns The ExecutionResult object * @throws Error if parameters are missing or the request fails. */ async getExecutions(cardKey) { if (!cardKey) { throw new Error("Missing required parameters"); } const endpoint = createEndpoint( this.host, `/za/v1/cards/${encodeURIComponent(cardKey.toString())}/code/executions` ); const token = this.token || await this.getToken(); return fetchGet(endpoint, token); } /** * Executes code in a simulated transaction context. * @param code - The code string * @param transaction - The transaction object * @param cardKey - The card key * @returns The ExecuteResult object * @throws Error if parameters are missing or the request fails. */ async executeCode(code, transaction, cardKey) { if (!code || !cardKey) { throw new Error("Missing required parameters"); } const raw = { simulationcode: code, centsAmount: transaction.centsAmount, currencyCode: transaction.currencyCode, merchantCode: transaction.merchant.category.code, merchantName: transaction.merchant.name, merchantCity: transaction.merchant.city, countryCode: transaction.merchant.country.code }; const endpoint = createEndpoint( this.host, `/za/v1/cards/${encodeURIComponent(cardKey.toString())}/code/execute` ); const token = this.token || await this.getToken(); return fetchPost(endpoint, token, raw); } /** * Retrieves supported currencies for programmable cards. * @returns The ReferenceResponse object * @throws Error if the request fails. */ async getCurrencies() { const endpoint = createEndpoint(this.host, `/za/v1/cards/currencies`); const token = this.token || await this.getToken(); return fetchGet(endpoint, token); } /** * Retrieves supported countries for programmable cards. * @returns The ReferenceResponse object * @throws Error if the request fails. */ async getCountries() { const endpoint = createEndpoint(this.host, `/za/v1/cards/countries`); const token = this.token || await this.getToken(); return fetchGet(endpoint, token); } /** * Retrieves supported merchants for programmable cards. * @returns The ReferenceResponse object * @throws Error if the request fails. */ async getMerchants() { const endpoint = createEndpoint(this.host, `/za/v1/cards/merchants`); const token = this.token || await this.getToken(); return fetchGet(endpoint, token); } }; async function fetchGet(endpoint, token) { const response = await (0, import_node_fetch.default)(endpoint, { method: "GET", signal: AbortSignal.timeout(3e4), headers: { Authorization: "Bearer " + token, "content-type": "application/json" } }); if (response.status !== 200) { if (response.status === 404) { throw new Error("Card not found"); } throw new Error(response.statusText); } return await response.json(); } async function fetchPost(endpoint, token, body) { const response = await (0, import_node_fetch.default)(endpoint, { method: "POST", signal: AbortSignal.timeout(3e4), headers: { Authorization: "Bearer " + token, "content-type": "application/json" }, body: JSON.stringify(body) }); if (response.status !== 200) { if (response.status === 404) { throw new Error("Card not found"); } throw new Error(response.statusText); } return await response.json(); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { InvestecCardApi });