pluggy-sdk
Version:
Official Node.js/TypeScript SDK for the Pluggy API.
178 lines (177 loc) • 6.97 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseApi = void 0;
const got_1 = __importStar(require("got"));
const jwt = __importStar(require("jsonwebtoken"));
const transforms_1 = require("./transforms");
const { version: pluggyNodeVersion, dependencies: { got: gotVersion },
// eslint-disable-next-line @typescript-eslint/no-var-requires
} = require('../package.json');
const _30_SECONDS = 30 * 1000;
class BaseApi {
constructor(params) {
const { clientId, clientSecret } = params;
const { PLUGGY_API_URL } = process.env;
this.baseUrl = PLUGGY_API_URL || 'https://api.pluggy.ai';
if (clientSecret && clientId) {
this.clientId = clientId;
this.clientSecret = clientSecret;
}
else {
throw new Error('Missing authorization for API communication');
}
this.defaultHeaders = {
'User-Agent': `PluggyNode/${pluggyNodeVersion} node.js/${process.version.replace('v', '')} Got/${gotVersion}`,
'Content-Type': 'application/json',
};
}
getServiceInstance() {
if (!this.serviceInstance) {
this.serviceInstance = got_1.default.extend({
headers: this.defaultHeaders,
responseType: 'json',
parseJson: transforms_1.deserializeJSONWithDates,
timeout: _30_SECONDS,
retry: {
limit: 2,
methods: ['GET', 'POST', 'PUT', 'PATCH', 'DELETE'],
statusCodes: [429],
},
});
}
return this.serviceInstance;
}
async getApiKey() {
if (this.apiKey && !this.isJwtExpired(this.apiKey)) {
return this.apiKey;
}
const response = await this.getServiceInstance().post(`${this.baseUrl}/auth`, {
json: {
clientId: this.clientId,
clientSecret: this.clientSecret,
nonExpiring: false,
},
responseType: 'json',
});
this.apiKey = response.body.apiKey;
return this.apiKey;
}
async createGetRequest(endpoint, params) {
const apiKey = await this.getApiKey();
const url = `${this.baseUrl}/${endpoint}${this.mapToQueryString(params)}`;
try {
const { statusCode, body } = await this.getServiceInstance()(url, {
headers: {
...this.defaultHeaders,
'X-API-KEY': apiKey,
},
responseType: 'json',
parseJson: transforms_1.deserializeJSONWithDates,
});
if (statusCode < 200 || statusCode >= 300) {
return Promise.reject(body);
}
return body;
}
catch (error) {
if (error instanceof got_1.HTTPError) {
console.error(`[Pluggy SDK] HTTP request failed: ${error.message || ''}`, error.response.body);
return Promise.reject(error.response.body);
}
return Promise.reject(error);
}
}
createPostRequest(endpoint, params, body) {
return this.createMutationRequest('post', endpoint, params, body);
}
createPutRequest(endpoint, params, body) {
return this.createMutationRequest('put', endpoint, params, body);
}
createPatchRequest(endpoint, params, body) {
return this.createMutationRequest('patch', endpoint, params, body);
}
createDeleteRequest(endpoint, params, body) {
return this.createMutationRequest('delete', endpoint, params, body);
}
async createMutationRequest(method, endpoint, params, body) {
const apiKey = await this.getApiKey();
const url = `${this.baseUrl}/${endpoint}${this.mapToQueryString(params)}`;
if (body) {
Object.keys(body).forEach(key => (body[key] === undefined ? delete body[key] : {}));
}
try {
const { statusCode, body: responseBody } = await this.getServiceInstance()(url, {
method,
headers: {
...this.defaultHeaders,
'X-API-KEY': apiKey,
},
json: body,
});
if (statusCode !== 200) {
return Promise.reject(body);
}
return responseBody;
}
catch (error) {
if (error instanceof got_1.HTTPError) {
console.error(`[Pluggy SDK] HTTP request failed: ${error.message || ''}`, error.response.body);
return Promise.reject(error.response.body);
}
return Promise.reject(error);
}
}
mapToQueryString(params) {
if (!params) {
return '';
}
const query = Object.keys(params)
.filter(key => params[key] !== undefined && params[key] !== null)
.map(key => key + '=' + params[key])
.join('&');
return `?${query}`;
}
isJwtExpired(token) {
const decoded = jwt.decode(token, { complete: true });
// Pluggy auth tokens always carry a JSON payload with `exp`. The
// `string | JwtPayload` union surfaced by @types/jsonwebtoken@9 is
// not reachable for tokens minted by the Pluggy API, so narrow it
// explicitly to keep the previous (pre-v9-types) behaviour.
const payload = decoded.payload;
return payload.exp <= Math.floor(Date.now() / 1000);
}
}
exports.BaseApi = BaseApi;