@buildable/messages
Advanced tools
+25
| MIT License | ||
| ----------- | ||
| Copyright (c) 2022 Buildable Technologies Inc (https://www.buildable.dev/) | ||
| Permission is hereby granted, free of charge, to any person | ||
| obtaining a copy of this software and associated documentation | ||
| files (the "Software"), to deal in the Software without | ||
| restriction, including without limitation the rights to use, | ||
| copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
| copies of the Software, and to permit persons to whom the | ||
| Software is furnished to do so, subject to the following | ||
| conditions: | ||
| The above copyright notice and this permission notice shall be | ||
| included in all copies or substantial portions of the Software. | ||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES | ||
| OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | ||
| HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | ||
| WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR | ||
| OTHER DEALINGS IN THE SOFTWARE. |
+22
-52
@@ -15,3 +15,3 @@ "use strict"; | ||
| const emitPath = "/emit"; | ||
| const SEPERATOR = process.env.BLD_LISTENER_SEPARATOR || "---"; | ||
| const SEPERATOR = "---"; | ||
| function createClient(secret) { | ||
@@ -22,14 +22,8 @@ if (!secret) { | ||
| let listeners = {}; | ||
| let fullEventNameCache = {}; | ||
| const getFullEventName = ({ eventName, platform, label }) => { | ||
| return fullEventNameCache[eventName + platform + label]; | ||
| const getListenerId = ({ eventName, txKey }) => { | ||
| return eventName + SEPERATOR + txKey; | ||
| }; | ||
| const getListenerId = ({ eventName, txKey, platform, label }) => { | ||
| const fullEventName = getFullEventName({ eventName, platform, label }); | ||
| return fullEventName + SEPERATOR + txKey; | ||
| }; | ||
| const runTransactions = async ({ eventName, txKey, since = Date.now(), sleepTime = 3000, platform, label }) => { | ||
| var _a, _b, _c, _d, _e, _f; | ||
| const runTransactions = async ({ eventName, txKey, since = Date.now(), sleepTime = 3000 }) => { | ||
| try { | ||
| const listener = listeners[getListenerId({ eventName, txKey, platform, label })]; | ||
| const listener = listeners[getListenerId({ eventName, txKey })]; | ||
| if (!listener) { | ||
@@ -53,4 +47,2 @@ return; //deregistered | ||
| txKey, | ||
| platform, | ||
| label, | ||
| since, | ||
@@ -72,6 +64,6 @@ txState: "does-not-exist", | ||
| 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 }); | ||
| console.error("Error fetching events for ", { eventName, txKey }, e === null || e === void 0 ? void 0 : e.response); | ||
| } | ||
| for (const event of events) { | ||
| const { headers, query, payload, key, eventName } = event; | ||
| const { headers, query, payload, key } = event; | ||
| try { | ||
@@ -91,3 +83,3 @@ await (0, axios_1.default)({ | ||
| 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 }); | ||
| console.error(`Error initializing transaction for event: ${event.eventName}`, e === null || e === void 0 ? void 0 : e.response); | ||
| continue; | ||
@@ -118,3 +110,3 @@ } | ||
| txKey, | ||
| output: error, | ||
| output: (0, utils_1.stringify)(error), | ||
| state: "failed" | ||
@@ -134,3 +126,3 @@ } | ||
| txKey, | ||
| output: output || "{}", | ||
| output: (0, utils_1.stringify)(output), | ||
| state: "finished" | ||
@@ -144,8 +136,8 @@ } | ||
| 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); | ||
| console.error("Error occurred in query interval", e); | ||
| } | ||
| await (0, utils_1.sleep)(sleepTime); | ||
| const listener = listeners[getListenerId({ eventName, txKey, platform, label })]; | ||
| 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 | ||
| listener.interval.then(() => runTransactions({ eventName, txKey, since })); // doesn't affect stack size | ||
| } | ||
@@ -174,42 +166,20 @@ }; | ||
| }, | ||
| on: async (eventName, handler, options = {}) => { | ||
| let fullEventName = getFullEventName({ eventName, platform: options.platform, label: options.label }); | ||
| if (!fullEventName) { | ||
| const { data } = await (0, axios_1.default)({ | ||
| method: "post", | ||
| url: baseURL + "/get-full-event-name", | ||
| headers: { | ||
| "X-BUILDABLE-SECRET": secret | ||
| }, | ||
| data: { | ||
| eventName, | ||
| platform: options.platform, | ||
| label: options.platform | ||
| } | ||
| }); | ||
| if (!data || !data.fullEventName) { | ||
| throw new Error("Could not grab required fullEventName from the server"); | ||
| } | ||
| const [, , ...splitEventName] = data.fullEventName.split("."); | ||
| fullEventName = splitEventName.join("."); | ||
| fullEventNameCache[eventName + options.platform + options.label] = fullEventName; | ||
| } | ||
| const txKey = options.txKey || `js-sdk.${fullEventName}`; | ||
| const id = getListenerId({ eventName, txKey, platform: options.platform, label: options.label }); | ||
| 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 for ${fullEventName} with txKey: ${txKey}`); | ||
| 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 }); | ||
| listeners[id].interval = runTransactions({ eventName, txKey, since: options.since }); | ||
| return { eventName, handler, txKey, options, id }; | ||
| }, | ||
| deregister: async ({ eventName, txKey, platform, label }) => { | ||
| deregister: ({ eventName, txKey }) => { | ||
| const removeKeys = Object.keys(listeners).filter(id => { | ||
| const [_fullEventName, _txKey] = id.split(SEPERATOR); | ||
| const fullEventName = getFullEventName({ eventName, platform, label }); | ||
| const [_eventName, _txKey] = id.split(SEPERATOR); | ||
| if (eventName && txKey) { | ||
| return _fullEventName === fullEventName && _txKey === txKey; | ||
| return _eventName === eventName && _txKey === txKey; | ||
| } | ||
| if (eventName) { | ||
| return _fullEventName === fullEventName; | ||
| return _eventName === eventName; | ||
| } | ||
@@ -216,0 +186,0 @@ if (txKey) { |
+9
-4
| { | ||
| "name": "@buildable/messages", | ||
| "version": "1.0.0", | ||
| "description": "Custom Events for Buildable", | ||
| "version": "1.0.1", | ||
| "description": "A fully managed messaging service that lets you easily exchange event data across any app or resource.", | ||
| "main": "dist/src/index.js", | ||
@@ -13,5 +13,10 @@ "types": "dist/src/index.d.ts", | ||
| "buildable", | ||
| "low code" | ||
| "events", | ||
| "messages", | ||
| "message-broker", | ||
| "event-broker", | ||
| "event-pipeline", | ||
| "transactions" | ||
| ], | ||
| "author": "@Buildable Team", | ||
| "author": "@buildable", | ||
| "license": "MIT", | ||
@@ -18,0 +23,0 @@ "dependencies": { |
+61
-8
@@ -5,3 +5,3 @@ # `@buildable/messages` | ||
| [Buildable](https://www.buildable.dev/messages) is the easiest way to collect, transform, send and action your backend system messages. Buildable simplifies the process of collecting message data from your disparate systems and connecting new tools to action those messages, allowing you to spend more of your engineering time on things that matter. | ||
| [Buildable](https://www.buildable.dev/messages) is the easiest way to collect, transform, send and action your backend system events. Buildable simplifies the process of communicating between services or cloud apps, via Messages. | ||
@@ -33,2 +33,6 @@ **This library allows you to quickly and easily emit and listen on messages via Node.js.** | ||
| A message contains: | ||
| 1. `event` - The name of the event | ||
| 2. `payload` - The data of the event | ||
| Once a message is emitted, it will be visible immediately in the Messages Stream on your Buildable account. | ||
@@ -43,4 +47,4 @@ | ||
| client.emit("my-message", { | ||
| salutation: "Hello world ⚡️" | ||
| client.emit("user.created", { | ||
| name: "John Doe" | ||
| }); | ||
@@ -55,5 +59,5 @@ ``` | ||
| --data-raw '{ | ||
| "event": "my-message", | ||
| "event": "user.created", | ||
| "payload": { | ||
| "salutation": "Hello world ⚡️" | ||
| "name": "John Doe" | ||
| } | ||
@@ -65,2 +69,5 @@ }' | ||
| ### What is a transaction? | ||
| A transaction is an action that can be triggered when a message is received. A message can have multiple transactions. Each transaction has a unique transaction key (`txKey`) per message. | ||
| There are two cases for transacting on messages: | ||
@@ -78,4 +85,4 @@ | ||
| // Listen on `my-message` | ||
| client.on("my-message", async ({ event, payload }) => { | ||
| // Transact on `user.created` | ||
| client.on("user.created", async ({ event, payload }) => { | ||
| console.log("Receieved message with payload: ", payload); | ||
@@ -87,3 +94,3 @@ }); | ||
| All [Connections](https://hub.buildable.dev/fundamentals/emitting-messages#emit-using-connections) act as a source of events, leveraging the power of WebHooks. Once you’ve created a Connection in Buildable and subscribed to at least 1 message type, messages will continually enter the Messages Stream. In most cases, once you create a Connection once, you can forget about it! | ||
| All [Connections](https://hub.buildable.dev/fundamentals/emitting-messages#emit-using-connections) act as a source of events, leveraging the power of WebHooks. Once you’ve created a Connection in Buildable and subscribed to at least 1 event, messages will continually enter the Messages Stream. In most cases, once you create a Connection once, you can forget about it! | ||
@@ -106,2 +113,48 @@ When listening on messages from cloud apps, simply add two additional options to the listener: | ||
| ### Multiple transactions on a message | ||
| In order to trigger multiple transactions on the same message, you must specify a custom transaction key (`txKey`). For example, if two services need to listen on the same message and trigger different custom logic, each service must pass a unique txKey to the listener. | ||
| ```javascript | ||
| const { createClient } = require('@buildable/messages'); | ||
| const client = createClient(process.env.BUILDABLE_SECRET_KEY); | ||
| // Transaction #1 on `user.created` from service A | ||
| client.on("user.created", async ({ event, payload }) => { | ||
| // Set the notification.sent transaction output | ||
| return await sendNotification(payload); | ||
| }, { | ||
| txKey: "notification.sent" | ||
| }); | ||
| // Transaction #2 on `user.created` from service B | ||
| client.on("user.created", async ({ event, payload }) => { | ||
| // Set the salesforce.customer.created transaction output | ||
| return await createCustomerOnSalesForce(payload); | ||
| }, { | ||
| txKey: "salesforce.customer.created" | ||
| }); | ||
| ``` | ||
| *By default, the `txKey` is set to `sdk.{{EVENT_NAME}}` | ||
| ### Transacting on older messages | ||
| In order to transact on messages that have already been emitted, simply pass in the additional configuration argument `since`. For example, to transact on messages from 10 days ago: | ||
| ```javascript | ||
| client.on("user.created", async ({ event, payload }) => { | ||
| // Set the notification.sent transaction output | ||
| return await sendNotification(payload); | ||
| }, { | ||
| txKey: "notification.sent", | ||
| since: Date.now() - (10 * 24 * 60 * 60 * 1000) // Since 10 days ago | ||
| }); | ||
| ``` | ||
| ## API | ||
| Alternatively, you can use the `Messages API`. Learn more about it at [hub.buildable.dev](https://hub.buildable.dev/using-the-api) | ||
| ## Need More Help? | ||
@@ -108,0 +161,0 @@ |
| { | ||
| "semi": true, | ||
| "trailingComma": "all", | ||
| "singleQuote": true, | ||
| "printWidth": 80, | ||
| "useTabs": true | ||
| } |
| export declare const getFullEventName: ({ secret, eventName, platform, label, baseURL }: { | ||
| secret: string; | ||
| eventName: string; | ||
| platform?: string | undefined; | ||
| label?: string | undefined; | ||
| baseURL: string; | ||
| }) => Promise<any>; |
| "use strict"; | ||
| var __importDefault = (this && this.__importDefault) || function (mod) { | ||
| return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
| }; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.getFullEventName = void 0; | ||
| const axios_1 = __importDefault(require("axios")); | ||
| const getFullEventName = async ({ secret, eventName, platform, label, baseURL }) => { | ||
| let fullEventName; | ||
| try { | ||
| const { data } = await (0, axios_1.default)({ | ||
| method: "post", | ||
| url: baseURL + "/get-full-event-name", | ||
| headers: { | ||
| "X-BUILDABLE-SECRET": secret | ||
| }, | ||
| data: { | ||
| eventName, | ||
| platform: platform, | ||
| label: label | ||
| } | ||
| }); | ||
| fullEventName = data.fullEventName; | ||
| } | ||
| catch (e) { | ||
| console.error((e === null || e === void 0 ? void 0 : e.response) ? { data: e.response.data, status: e.response.status } : e); | ||
| throw new Error("Error retreiving fullEventName"); | ||
| } | ||
| if (fullEventName) { | ||
| throw new Error("Could not grab required fullEventName from the server"); | ||
| } | ||
| const [, , ...splitEventName] = fullEventName.split("."); | ||
| return splitEventName.join("."); | ||
| }; | ||
| exports.getFullEventName = getFullEventName; |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 2 instances in 1 package
166
46.9%3
-25%16422
-5.4%8
-20%204
-26.35%1
Infinity%