@buildable/events
Version:
Custom Events for Buildable
197 lines (196 loc) • 8.66 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const axios_1 = __importDefault(require("axios"));
const utils_1 = require("../utils");
const errorsMap = {
'401': 'You are not authorized to make this request.',
emit: 'There was an error trying to emit this event',
default: 'An error has occurred'
};
const baseURL = process.env.BLD_EVENTS_BASE_URL || 'https://events.buildable.dev';
const emitPath = "/emit";
const SEPERATOR = "---";
function createClient(secret) {
if (!secret) {
throw new Error('A valid Buildable secret is required');
}
let listeners = {};
const getListenerId = ({ eventName, txKey }) => {
return eventName + SEPERATOR + txKey;
};
const runTransactions = async ({ eventName, txKey, since = Date.now(), sleepTime = 3000, platform, label }) => {
var _a, _b, _c, _d, _e, _f;
try {
const listener = listeners[getListenerId({ eventName, txKey })];
if (!listener) {
return; //deregistered
}
const { handler } = listener;
let events = [];
let page = 1;
let hasMorePages = true;
while (hasMorePages) {
try {
const { data: { rows, totalPages } } = await (0, axios_1.default)({
method: "post",
url: baseURL + "/query",
headers: {
"X-BUILDABLE-SECRET": secret
},
data: {
eventName,
txKey,
platform,
label,
since,
txState: "does-not-exist",
page,
pageSize: 10
}
});
if (totalPages > page) {
page++;
}
else {
hasMorePages = false;
}
events = rows;
}
catch (e) {
hasMorePages = false;
console.error("Error fetching events for ", { eventName, txKey }, { data: (_a = e === null || e === void 0 ? void 0 : e.response) === null || _a === void 0 ? void 0 : _a.data, status: (_b = e === null || e === void 0 ? void 0 : e.response) === null || _b === void 0 ? void 0 : _b.status });
}
for (const event of events) {
const { headers, query, payload, key, eventName } = event;
try {
await (0, axios_1.default)({
method: "post",
url: baseURL + "/init",
headers: {
"X-BUILDABLE-SECRET": secret
},
data: {
key,
txKey,
}
});
}
catch (e) {
console.error(`Error initializing transaction for event: ${eventName}, with key: ${key} and txKey: ${txKey}`, { data: (_c = e === null || e === void 0 ? void 0 : e.response) === null || _c === void 0 ? void 0 : _c.data, status: (_d = e === null || e === void 0 ? void 0 : e.response) === null || _d === void 0 ? void 0 : _d.status });
continue;
}
let output;
let error;
try {
output = await handler({
headers,
query,
payload,
event
});
}
catch (e) {
error = e;
}
if (error) {
await (0, axios_1.default)({
method: "post",
url: baseURL + "/transact",
headers: {
"X-BUILDABLE-SECRET": secret
},
data: {
key,
txKey,
output: (0, utils_1.stringify)(error),
state: "failed"
}
});
}
else {
await (0, axios_1.default)({
method: "post",
url: baseURL + "/transact",
headers: {
"X-BUILDABLE-SECRET": secret
},
data: {
key,
txKey,
output: (0, utils_1.stringify)(output),
state: "finished"
}
});
}
}
}
}
catch (e) {
console.error("Error occurred in query interval", (e === null || e === void 0 ? void 0 : e.response) ? { data: (_e = e === null || e === void 0 ? void 0 : e.response) === null || _e === void 0 ? void 0 : _e.data, status: (_f = e === null || e === void 0 ? void 0 : e.response) === null || _f === void 0 ? void 0 : _f.status } : e);
}
await (0, utils_1.sleep)(sleepTime);
const listener = listeners[getListenerId({ eventName, txKey })];
if (listener && listener.interval) {
listener.interval.then(() => runTransactions({ eventName, txKey, since, sleepTime, platform, label })); // doesn't affect stack size
}
};
return {
emit: async (event, payload = {}) => {
var _a, _b, _c;
if (!event) {
throw Error('Need to provide an `event name`');
}
try {
const data = { event, payload };
const options = {
headers: { 'X-Buildable-Secret': secret }
};
const res = await axios_1.default.post(baseURL + emitPath, data, options);
// todo: check actual response data
return !!(res === null || res === void 0 ? void 0 : res.data);
}
catch (ex) {
const resCode = (_b = (_a = ex === null || ex === void 0 ? void 0 : ex.response) === null || _a === void 0 ? void 0 : _a.status) !== null && _b !== void 0 ? _b : 'emit';
const msg = (_c = errorsMap[resCode]) !== null && _c !== void 0 ? _c : errorsMap.default;
throw Error(msg);
}
},
on: (eventName, handler, options = {}) => {
const txKey = options.txKey || `js-sdk.${eventName}`;
const id = getListenerId({ eventName, txKey });
if (listeners[id]) {
throw new Error(`Listener already exists with eventName: ${eventName}, txKey: ${txKey}`);
}
listeners[id] = { eventName, handler, txKey, options, id };
listeners[id].interval = runTransactions({ eventName, txKey, since: options.since, platform: options.platform, label: options.label });
return { eventName, handler, txKey, options, id };
},
deregister: ({ eventName, txKey }) => {
const removeKeys = Object.keys(listeners).filter(id => {
const [_eventName, _txKey] = id.split(SEPERATOR);
if (eventName && txKey) {
return _eventName === eventName && _txKey === txKey;
}
if (eventName) {
return _eventName === eventName;
}
if (txKey) {
return _txKey === txKey;
}
return false;
});
for (const key of removeKeys) {
if (listeners[key]) {
delete listeners[key];
}
}
},
deregisterAll: () => {
listeners = {};
}
};
}
module.exports = { createClient, baseURL };