@segment/analytics-node
Version:
https://www.npmjs.com/package/@segment/analytics-node
215 lines • 8.85 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Analytics = void 0;
const analytics_core_1 = require("@segment/analytics-core");
const settings_1 = require("./settings");
const version_1 = require("../generated/version");
const segmentio_1 = require("../plugins/segmentio");
const event_factory_1 = require("./event-factory");
const dispatch_emit_1 = require("./dispatch-emit");
const emitter_1 = require("./emitter");
const context_1 = require("./context");
const event_queue_1 = require("./event-queue");
const http_client_1 = require("../lib/http-client");
class Analytics extends emitter_1.NodeEmitter {
_eventFactory;
_isClosed = false;
_pendingEvents = 0;
_closeAndFlushDefaultTimeout;
_publisher;
_isFlushing = false;
_queue;
ready;
constructor(settings) {
super();
(0, settings_1.validateSettings)(settings);
this._eventFactory = new event_factory_1.NodeEventFactory();
this._queue = new event_queue_1.NodeEventQueue();
const flushInterval = settings.flushInterval ?? 10000;
this._closeAndFlushDefaultTimeout = flushInterval * 1.25; // add arbitrary multiplier in case an event is in a plugin.
const { plugin, publisher } = (0, segmentio_1.createConfiguredNodePlugin)({
writeKey: settings.writeKey,
host: settings.host,
path: settings.path,
maxRetries: settings.maxRetries ?? 3,
flushAt: settings.flushAt ?? settings.maxEventsInBatch ?? 15,
httpRequestTimeout: settings.httpRequestTimeout,
disable: settings.disable,
flushInterval,
httpClient: typeof settings.httpClient === 'function'
? new http_client_1.FetchHTTPClient(settings.httpClient)
: settings.httpClient ?? new http_client_1.FetchHTTPClient(),
oauthSettings: settings.oauthSettings,
}, this);
this._publisher = publisher;
this.ready = this.register(plugin).then(() => undefined);
this.emit('initialize', settings);
(0, analytics_core_1.bindAll)(this);
}
get VERSION() {
return version_1.version;
}
/**
* Call this method to stop collecting new events and flush all existing events.
* This method also waits for any event method-specific callbacks to be triggered,
* and any of their subsequent promises to be resolved/rejected.
*/
closeAndFlush({ timeout = this._closeAndFlushDefaultTimeout, } = {}) {
return this.flush({ timeout, close: true });
}
/**
* Call this method to flush all existing events..
* This method also waits for any event method-specific callbacks to be triggered,
* and any of their subsequent promises to be resolved/rejected.
*/
async flush({ timeout, close = false, } = {}) {
if (this._isFlushing) {
// if we're already flushing, then we don't need to do anything
console.warn('Overlapping flush calls detected. Please wait for the previous flush to finish before calling .flush again');
return;
}
else {
this._isFlushing = true;
}
if (close) {
this._isClosed = true;
}
this._publisher.flush(this._pendingEvents);
const promise = new Promise((resolve) => {
if (!this._pendingEvents) {
resolve();
}
else {
this.once('drained', () => {
resolve();
});
}
}).finally(() => {
this._isFlushing = false;
});
return timeout ? (0, analytics_core_1.pTimeout)(promise, timeout).catch(() => undefined) : promise;
}
_dispatch(segmentEvent, callback) {
if (this._isClosed) {
this.emit('call_after_close', segmentEvent);
return undefined;
}
this._pendingEvents++;
(0, dispatch_emit_1.dispatchAndEmit)(segmentEvent, this._queue, this, callback)
.catch((ctx) => ctx)
.finally(() => {
this._pendingEvents--;
if (!this._pendingEvents) {
this.emit('drained');
}
});
}
/**
* Combines two unassociated user identities.
* @link https://segment.com/docs/connections/sources/catalog/libraries/server/node/#alias
*/
alias({ userId, previousId, context, timestamp, integrations, messageId, }, callback) {
const segmentEvent = this._eventFactory.alias(userId, previousId, {
context,
integrations,
timestamp,
messageId,
});
this._dispatch(segmentEvent, callback);
}
/**
* Associates an identified user with a collective.
* @link https://segment.com/docs/connections/sources/catalog/libraries/server/node/#group
*/
group({ timestamp, groupId, userId, anonymousId, traits = {}, context, integrations, messageId, }, callback) {
const segmentEvent = this._eventFactory.group(groupId, traits, {
context,
anonymousId,
userId,
timestamp,
integrations,
messageId,
});
this._dispatch(segmentEvent, callback);
}
/**
* Includes a unique userId and (maybe anonymousId) and any optional traits you know about them.
* @link https://segment.com/docs/connections/sources/catalog/libraries/server/node/#identify
*/
identify({ userId, anonymousId, traits = {}, context, timestamp, integrations, messageId, }, callback) {
const segmentEvent = this._eventFactory.identify(userId, traits, {
context,
anonymousId,
userId,
timestamp,
integrations,
messageId,
});
this._dispatch(segmentEvent, callback);
}
/**
* The page method lets you record page views on your website, along with optional extra information about the page being viewed.
* @link https://segment.com/docs/connections/sources/catalog/libraries/server/node/#page
*/
page({ userId, anonymousId, category, name, properties, context, timestamp, integrations, messageId, }, callback) {
const segmentEvent = this._eventFactory.page(category ?? null, name ?? null, properties, { context, anonymousId, userId, timestamp, integrations, messageId });
this._dispatch(segmentEvent, callback);
}
/**
* Records screen views on your app, along with optional extra information
* about the screen viewed by the user.
*
* TODO: This is not documented on the segment docs ATM (for node).
*/
screen({ userId, anonymousId, category, name, properties, context, timestamp, integrations, messageId, }, callback) {
const segmentEvent = this._eventFactory.screen(category ?? null, name ?? null, properties, { context, anonymousId, userId, timestamp, integrations, messageId });
this._dispatch(segmentEvent, callback);
}
/**
* Records actions your users perform.
* @link https://segment.com/docs/connections/sources/catalog/libraries/server/node/#track
*/
track({ userId, anonymousId, event, properties, context, timestamp, integrations, messageId, }, callback) {
const segmentEvent = this._eventFactory.track(event, properties, {
context,
userId,
anonymousId,
timestamp,
integrations,
messageId,
});
this._dispatch(segmentEvent, callback);
}
/**
* Registers one or more plugins to augment Analytics functionality.
* @param plugins
*/
register(...plugins) {
return this._queue.criticalTasks.run(async () => {
const ctx = context_1.Context.system();
const registrations = plugins.map((xt) => this._queue.register(ctx, xt, this));
await Promise.all(registrations);
this.emit('register', plugins.map((el) => el.name));
});
}
/**
* Deregisters one or more plugins based on their names.
* @param pluginNames - The names of one or more plugins to deregister.
*/
async deregister(...pluginNames) {
const ctx = context_1.Context.system();
const deregistrations = pluginNames.map((pl) => {
const plugin = this._queue.plugins.find((p) => p.name === pl);
if (plugin) {
return this._queue.deregister(ctx, plugin, this);
}
else {
ctx.log('warn', `plugin ${pl} not found`);
}
});
await Promise.all(deregistrations);
this.emit('deregister', pluginNames);
}
}
exports.Analytics = Analytics;
//# sourceMappingURL=analytics-node.js.map