investec-card-api
Version:
A simple package for interacting with Investec's programmable banking card API
362 lines (359 loc) • 12.3 kB
JavaScript
;
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
});