Auto-commit 2026-05-02 09:37

This commit is contained in:
2026-05-02 09:37:34 -04:00
parent b7600fa937
commit 35d004cde3
3809 changed files with 2315945 additions and 106 deletions

21
node_modules/@segment/analytics-node/LICENSE generated vendored Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright © 2021 Segment
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.

150
node_modules/@segment/analytics-node/README.md generated vendored Normal file
View File

@@ -0,0 +1,150 @@
# @segment/analytics-node
https://www.npmjs.com/package/@segment/analytics-node
### OFFICIAL DOCUMENTATION (FULL)
- https://segment.com/docs/connections/sources/catalog/libraries/server/node
### LEGACY NODE SDK MIGRATION GUIDE:
- https://segment.com/docs/connections/sources/catalog/libraries/server/node/migration
## Runtime Support
- Node.js >= 14
- AWS Lambda
- Cloudflare Workers
- Vercel Edge Functions
- Web Workers (experimental)
## Quick Start
### Install library
```bash
# npm
npm install @segment/analytics-node
# yarn
yarn add @segment/analytics-node
# pnpm
pnpm install @segment/analytics-node
```
### Usage
Assuming some express-like web framework.
```ts
import { Analytics } from '@segment/analytics-node'
// or, if you use require:
const { Analytics } = require('@segment/analytics-node')
// instantiation
const analytics = new Analytics({ writeKey: '<MY_WRITE_KEY>' })
app.post('/login', (req, res) => {
analytics.identify({
userId: req.body.userId,
previousId: req.body.previousId
})
res.sendStatus(200)
})
app.post('/cart', (req, res) => {
analytics.track({
userId: req.body.userId,
event: 'Add to cart',
properties: { productId: '123456' }
})
res.sendStatus(201)
});
```
## Settings & Configuration
See the documentation: https://segment.com/docs/connections/sources/catalog/libraries/server/node/#configuration
You can also see the complete list of settings in the [AnalyticsSettings interface](src/app/settings.ts).
## Plugin Architecture
- See segment's [documentation for plugin architecture](https://segment.com/docs/connections/sources/catalog/libraries/website/javascript/#plugin-architecture).
## Usage in non-node runtimes
### Usage in AWS Lambda
- [AWS lambda execution environment](https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtime-environment.html) is challenging for typically non-response-blocking async activites like tracking or logging, since the runtime terminates / freezes after a response is emitted.
Here is an example of using analytics.js within a handler:
```ts
const { Analytics } = require('@segment/analytics-node');
// since analytics has the potential to be stateful if there are any plugins added,
// to be on the safe side, we should instantiate a new instance of analytics on every request (the cost of instantiation is low).
const analytics = () => new Analytics({
flushAt: 1,
writeKey: '<MY_WRITE_KEY>',
})
.on('error', console.error);
module.exports.handler = async (event) => {
...
// we need to await before returning, otherwise the lambda will exit before sending the request.
await new Promise((resolve) =>
analytics().track({ ... }, resolve)
)
...
return {
statusCode: 200,
};
....
};
```
### Usage in Vercel Edge Functions
```ts
import { Analytics } from '@segment/analytics-node';
import { NextRequest, NextResponse } from 'next/server';
export const analytics = new Analytics({
writeKey: '<MY_WRITE_KEY>',
flushAt: 1,
})
.on('error', console.error)
export const config = {
runtime: 'edge',
};
export default async (req: NextRequest) => {
await new Promise((resolve) =>
analytics.track({ ... }, resolve)
);
return NextResponse.json({ ... })
};
```
### Usage in Cloudflare Workers
```ts
import { Analytics, Context } from '@segment/analytics-node';
export default {
async fetch(
request: Request,
env: Env,
ctx: ExecutionContext
): Promise<Response> {
const analytics = new Analytics({
flushAt: 1,
writeKey: '<MY_WRITE_KEY>',
}).on('error', console.error);
await new Promise((resolve, reject) =>
analytics.track({ ... }, resolve)
);
...
return new Response(...)
},
};
```

View File

@@ -0,0 +1,205 @@
"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 {
constructor(settings) {
super();
this._isClosed = false;
this._pendingEvents = 0;
this._isFlushing = false;
(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(),
}, 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 }, callback) {
const segmentEvent = this._eventFactory.alias(userId, previousId, {
context,
integrations,
timestamp,
});
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, }, callback) {
const segmentEvent = this._eventFactory.group(groupId, traits, {
context,
anonymousId,
userId,
timestamp,
integrations,
});
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, }, callback) {
const segmentEvent = this._eventFactory.identify(userId, traits, {
context,
anonymousId,
userId,
timestamp,
integrations,
});
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, }, callback) {
const segmentEvent = this._eventFactory.page(category ?? null, name ?? null, properties, { context, anonymousId, userId, timestamp, integrations });
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, }, callback) {
const segmentEvent = this._eventFactory.screen(category ?? null, name ?? null, properties, { context, anonymousId, userId, timestamp, integrations });
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, }, callback) {
const segmentEvent = this._eventFactory.track(event, properties, {
context,
userId,
anonymousId,
timestamp,
integrations,
});
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

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,13 @@
"use strict";
// create a derived class since we may want to add node specific things to Context later
Object.defineProperty(exports, "__esModule", { value: true });
exports.Context = void 0;
const analytics_core_1 = require("@segment/analytics-core");
// While this is not a type, it is a definition
class Context extends analytics_core_1.CoreContext {
static system() {
return new this({ type: 'track', event: 'system' });
}
}
exports.Context = Context;
//# sourceMappingURL=context.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/app/context.ts"],"names":[],"mappings":";AAAA,wFAAwF;;;AAExF,4DAAqD;AAGrD,+CAA+C;AAC/C,MAAa,OAAQ,SAAQ,4BAAyB;IACpD,MAAM,CAAU,MAAM;QACpB,OAAO,IAAI,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;IACrD,CAAC;CACF;AAJD,0BAIC"}

View File

@@ -0,0 +1,37 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.dispatchAndEmit = void 0;
const analytics_core_1 = require("@segment/analytics-core");
const context_1 = require("./context");
const normalizeDispatchCb = (cb) => (ctx) => {
const failedDelivery = ctx.failedDelivery();
return failedDelivery ? cb(failedDelivery.reason, ctx) : cb(undefined, ctx);
};
/* Dispatch function, but swallow promise rejections and use event emitter instead */
const dispatchAndEmit = async (event, queue, emitter, callback) => {
try {
const context = new context_1.Context(event);
const ctx = await (0, analytics_core_1.dispatch)(context, queue, emitter, {
...(callback ? { callback: normalizeDispatchCb(callback) } : {}),
});
const failedDelivery = ctx.failedDelivery();
if (failedDelivery) {
emitter.emit('error', {
code: 'delivery_failure',
reason: failedDelivery.reason,
ctx: ctx,
});
}
else {
emitter.emit(event.type, ctx);
}
}
catch (err) {
emitter.emit('error', {
code: 'unknown',
reason: err,
});
}
};
exports.dispatchAndEmit = dispatchAndEmit;
//# sourceMappingURL=dispatch-emit.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"dispatch-emit.js","sourceRoot":"","sources":["../../../src/app/dispatch-emit.ts"],"names":[],"mappings":";;;AAAA,4DAAkD;AAElD,uCAAmC;AAMnC,MAAM,mBAAmB,GAAG,CAAC,EAAY,EAAE,EAAE,CAAC,CAAC,GAAY,EAAE,EAAE;IAC7D,MAAM,cAAc,GAAG,GAAG,CAAC,cAAc,EAAE,CAAA;IAC3C,OAAO,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;AAC7E,CAAC,CAAA;AAED,qFAAqF;AAC9E,MAAM,eAAe,GAAG,KAAK,EAClC,KAAmB,EACnB,KAAqB,EACrB,OAAoB,EACpB,QAAmB,EACJ,EAAE;IACjB,IAAI;QACF,MAAM,OAAO,GAAG,IAAI,iBAAO,CAAC,KAAK,CAAC,CAAA;QAClC,MAAM,GAAG,GAAG,MAAM,IAAA,yBAAQ,EAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;YAClD,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,mBAAmB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACjE,CAAC,CAAA;QACF,MAAM,cAAc,GAAG,GAAG,CAAC,cAAc,EAAE,CAAA;QAC3C,IAAI,cAAc,EAAE;YAClB,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE;gBACpB,IAAI,EAAE,kBAAkB;gBACxB,MAAM,EAAE,cAAc,CAAC,MAAM;gBAC7B,GAAG,EAAE,GAAG;aACT,CAAC,CAAA;SACH;aAAM;YACL,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;SAC9B;KACF;IAAC,OAAO,GAAG,EAAE;QACZ,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE;YACpB,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,GAAG;SACZ,CAAC,CAAA;KACH;AACH,CAAC,CAAA;AA3BY,QAAA,eAAe,mBA2B3B"}

View File

@@ -0,0 +1,8 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NodeEmitter = void 0;
const analytics_generic_utils_1 = require("@segment/analytics-generic-utils");
class NodeEmitter extends analytics_generic_utils_1.Emitter {
}
exports.NodeEmitter = NodeEmitter;
//# sourceMappingURL=emitter.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"emitter.js","sourceRoot":"","sources":["../../../src/app/emitter.ts"],"names":[],"mappings":";;;AACA,8EAA0D;AAsB1D,MAAa,WAAY,SAAQ,iCAA0B;CAAG;AAA9D,kCAA8D"}

View File

@@ -0,0 +1,12 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NodeEventFactory = void 0;
const analytics_core_1 = require("@segment/analytics-core");
const get_message_id_1 = require("../lib/get-message-id");
class NodeEventFactory extends analytics_core_1.EventFactory {
constructor() {
super({ createMessageId: get_message_id_1.createMessageId });
}
}
exports.NodeEventFactory = NodeEventFactory;
//# sourceMappingURL=event-factory.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"event-factory.js","sourceRoot":"","sources":["../../../src/app/event-factory.ts"],"names":[],"mappings":";;;AAAA,4DAAsD;AACtD,0DAAuD;AAcvD,MAAa,gBAAiB,SAAQ,6BAAY;IAChD;QACE,KAAK,CAAC,EAAE,eAAe,EAAf,gCAAe,EAAE,CAAC,CAAA;IAC5B,CAAC;CACF;AAJD,4CAIC"}

View File

@@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.NodeEventQueue = void 0;
const analytics_core_1 = require("@segment/analytics-core");
class NodePriorityQueue extends analytics_core_1.PriorityQueue {
constructor() {
super(1, []);
}
// do not use an internal "seen" map
getAttempts(ctx) {
return ctx.attempts ?? 0;
}
updateAttempts(ctx) {
ctx.attempts = this.getAttempts(ctx) + 1;
return this.getAttempts(ctx);
}
}
class NodeEventQueue extends analytics_core_1.CoreEventQueue {
constructor() {
super(new NodePriorityQueue());
}
}
exports.NodeEventQueue = NodeEventQueue;
//# sourceMappingURL=event-queue.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"event-queue.js","sourceRoot":"","sources":["../../../src/app/event-queue.ts"],"names":[],"mappings":";;;AAAA,4DAAuE;AAIvE,MAAM,iBAAkB,SAAQ,8BAAsB;IACpD;QACE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACd,CAAC;IACD,oCAAoC;IACpC,WAAW,CAAC,GAAY;QACtB,OAAO,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAA;IAC1B,CAAC;IACD,cAAc,CAAC,GAAY;QACzB,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACxC,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IAC9B,CAAC;CACF;AAED,MAAa,cAAe,SAAQ,+BAA+B;IACjE;QACE,KAAK,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAA;IAChC,CAAC;CACF;AAJD,wCAIC"}

View File

@@ -0,0 +1,11 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.validateSettings = void 0;
const analytics_core_1 = require("@segment/analytics-core");
const validateSettings = (settings) => {
if (!settings.writeKey) {
throw new analytics_core_1.ValidationError('writeKey', 'writeKey is missing.');
}
};
exports.validateSettings = validateSettings;
//# sourceMappingURL=settings.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/app/settings.ts"],"names":[],"mappings":";;;AAAA,4DAAyD;AAiDlD,MAAM,gBAAgB,GAAG,CAAC,QAA2B,EAAE,EAAE;IAC9D,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE;QACtB,MAAM,IAAI,gCAAe,CAAC,UAAU,EAAE,sBAAsB,CAAC,CAAA;KAC9D;AACH,CAAC,CAAA;AAJY,QAAA,gBAAgB,oBAI5B"}

View File

@@ -0,0 +1,7 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
tslib_1.__exportStar(require("./params"), exports);
tslib_1.__exportStar(require("./segment-event"), exports);
tslib_1.__exportStar(require("./plugin"), exports);
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/app/types/index.ts"],"names":[],"mappings":";;;AAAA,mDAAwB;AACxB,0DAA+B;AAC/B,mDAAwB"}

View File

@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=params.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"params.js","sourceRoot":"","sources":["../../../../src/app/types/params.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=plugin.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../../src/app/types/plugin.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,3 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
//# sourceMappingURL=segment-event.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"segment-event.js","sourceRoot":"","sources":["../../../../src/app/types/segment-event.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.version = void 0;
// This file is generated.
exports.version = '1.3.0';
//# sourceMappingURL=version.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/generated/version.ts"],"names":[],"mappings":";;;AAAA,0BAA0B;AACb,QAAA,OAAO,GAAG,OAAO,CAAA"}

13
node_modules/@segment/analytics-node/dist/cjs/index.js generated vendored Normal file
View File

@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FetchHTTPClient = exports.Context = exports.Analytics = void 0;
var analytics_node_1 = require("./app/analytics-node");
Object.defineProperty(exports, "Analytics", { enumerable: true, get: function () { return analytics_node_1.Analytics; } });
var context_1 = require("./app/context");
Object.defineProperty(exports, "Context", { enumerable: true, get: function () { return context_1.Context; } });
var http_client_1 = require("./lib/http-client");
Object.defineProperty(exports, "FetchHTTPClient", { enumerable: true, get: function () { return http_client_1.FetchHTTPClient; } });
// export Analytics as both a named export and a default export (for backwards-compat. reasons)
const analytics_node_2 = require("./app/analytics-node");
exports.default = analytics_node_2.Analytics;
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,uDAAgD;AAAvC,2GAAA,SAAS,OAAA;AAClB,yCAAuC;AAA9B,kGAAA,OAAO,OAAA;AAChB,iDAO0B;AALxB,8GAAA,eAAe,OAAA;AAmBjB,+FAA+F;AAC/F,yDAAgD;AAChD,kBAAe,0BAAS,CAAA"}

View File

@@ -0,0 +1,78 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.abortSignalAfterTimeout = exports.AbortSignal = void 0;
/**
* use non-native event emitter for the benefit of non-node runtimes like CF workers.
*/
const analytics_generic_utils_1 = require("@segment/analytics-generic-utils");
const env_1 = require("./env");
/**
* adapted from: https://www.npmjs.com/package/node-abort-controller
*/
class AbortSignal {
constructor() {
this.onabort = null;
this.aborted = false;
this.eventEmitter = new analytics_generic_utils_1.Emitter();
}
toString() {
return '[object AbortSignal]';
}
get [Symbol.toStringTag]() {
return 'AbortSignal';
}
removeEventListener(...args) {
this.eventEmitter.off(...args);
}
addEventListener(...args) {
this.eventEmitter.on(...args);
}
dispatchEvent(type) {
const event = { type, target: this };
const handlerName = `on${type}`;
if (typeof this[handlerName] === 'function') {
;
this[handlerName](event);
}
this.eventEmitter.emit(type, event);
}
}
exports.AbortSignal = AbortSignal;
/**
* This polyfill is only neccessary to support versions of node < 14.17.
* Can be removed once node 14 support is dropped.
*/
class AbortController {
constructor() {
this.signal = new AbortSignal();
}
abort() {
if (this.signal.aborted)
return;
this.signal.aborted = true;
this.signal.dispatchEvent('abort');
}
toString() {
return '[object AbortController]';
}
get [Symbol.toStringTag]() {
return 'AbortController';
}
}
/**
* @param timeoutMs - Set a request timeout, after which the request is cancelled.
*/
const abortSignalAfterTimeout = (timeoutMs) => {
if ((0, env_1.detectRuntime)() === 'cloudflare-worker') {
return []; // TODO: this is broken in cloudflare workers, otherwise results in "A hanging Promise was canceled..." error.
}
const ac = new (globalThis.AbortController || AbortController)();
const timeoutId = setTimeout(() => {
ac.abort();
}, timeoutMs);
// Allow Node.js processes to exit early if only the timeout is running
timeoutId?.unref?.();
return [ac.signal, timeoutId];
};
exports.abortSignalAfterTimeout = abortSignalAfterTimeout;
//# sourceMappingURL=abort.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"abort.js","sourceRoot":"","sources":["../../../src/lib/abort.ts"],"names":[],"mappings":";;;AAAA;;GAEG;AACH,8EAA0D;AAC1D,+BAAqC;AAErC;;GAEG;AACH,MAAa,WAAW;IAAxB;QACE,YAAO,GAAsC,IAAI,CAAA;QACjD,YAAO,GAAG,KAAK,CAAA;QACf,iBAAY,GAAG,IAAI,iCAAO,EAAE,CAAA;IAyB9B,CAAC;IAvBC,QAAQ;QACN,OAAO,sBAAsB,CAAA;IAC/B,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QACtB,OAAO,aAAa,CAAA;IACtB,CAAC;IACD,mBAAmB,CAAC,GAAG,IAAgC;QACrD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAA;IAChC,CAAC;IACD,gBAAgB,CAAC,GAAG,IAA+B;QACjD,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAA;IAC/B,CAAC;IACD,aAAa,CAAC,IAAY;QACxB,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;QAEpC,MAAM,WAAW,GAAG,KAAK,IAAI,EAAE,CAAA;QAE/B,IAAI,OAAQ,IAAY,CAAC,WAAW,CAAC,KAAK,UAAU,EAAE;YACpD,CAAC;YAAC,IAAY,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAA;SACnC;QAED,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACrC,CAAC;CACF;AA5BD,kCA4BC;AAED;;;GAGG;AACH,MAAM,eAAe;IAArB;QACE,WAAM,GAAG,IAAI,WAAW,EAAE,CAAA;IAa5B,CAAC;IAZC,KAAK;QACH,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAM;QAE/B,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA;QAC1B,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;IACpC,CAAC;IACD,QAAQ;QACN,OAAO,0BAA0B,CAAA;IACnC,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QACtB,OAAO,iBAAiB,CAAA;IAC1B,CAAC;CACF;AAED;;GAEG;AACI,MAAM,uBAAuB,GAAG,CAAC,SAAiB,EAAE,EAAE;IAC3D,IAAI,IAAA,mBAAa,GAAE,KAAK,mBAAmB,EAAE;QAC3C,OAAO,EAAE,CAAA,CAAC,8GAA8G;KACzH;IACD,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,eAAe,IAAI,eAAe,CAAC,EAAE,CAAA;IAEhE,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;QAChC,EAAE,CAAC,KAAK,EAAE,CAAA;IACZ,CAAC,EAAE,SAAS,CAAC,CAAA;IAEb,uEAAuE;IACvE,SAAS,EAAE,KAAK,EAAE,EAAE,CAAA;IAEpB,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,CAAU,CAAA;AACxC,CAAC,CAAA;AAdY,QAAA,uBAAuB,2BAcnC"}

View File

@@ -0,0 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.b64encode = void 0;
// eslint-disable-next-line import/no-nodejs-modules
const buffer_1 = require("buffer");
/**
* Base64 encoder that works in browser, worker, node runtimes.
*/
const b64encode = (str) => {
return buffer_1.Buffer.from(str).toString('base64');
};
exports.b64encode = b64encode;
//# sourceMappingURL=base-64-encode.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"base-64-encode.js","sourceRoot":"","sources":["../../../src/lib/base-64-encode.ts"],"names":[],"mappings":";;;AAAA,oDAAoD;AACpD,mCAA+B;AAC/B;;GAEG;AACI,MAAM,SAAS,GAAG,CAAC,GAAW,EAAU,EAAE;IAC/C,OAAO,eAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;AAC5C,CAAC,CAAA;AAFY,QAAA,SAAS,aAErB"}

View File

@@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.tryCreateFormattedUrl = void 0;
const stripTrailingSlash = (str) => str.replace(/\/$/, '');
/**
*
* @param host e.g. "http://foo.com"
* @param path e.g. "/bar"
* @returns "e.g." "http://foo.com/bar"
*/
const tryCreateFormattedUrl = (host, path) => {
return stripTrailingSlash(new URL(path || '', host).href);
};
exports.tryCreateFormattedUrl = tryCreateFormattedUrl;
//# sourceMappingURL=create-url.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"create-url.js","sourceRoot":"","sources":["../../../src/lib/create-url.ts"],"names":[],"mappings":";;;AAAA,MAAM,kBAAkB,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;AAElE;;;;;GAKG;AACI,MAAM,qBAAqB,GAAG,CAAC,IAAY,EAAE,IAAa,EAAE,EAAE;IACnE,OAAO,kBAAkB,CAAC,IAAI,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAA;AAC3D,CAAC,CAAA;AAFY,QAAA,qBAAqB,yBAEjC"}

View File

@@ -0,0 +1,33 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.detectRuntime = void 0;
const detectRuntime = () => {
if (typeof process === 'object' &&
process &&
typeof process.env === 'object' &&
process.env &&
typeof process.version === 'string') {
return 'node';
}
if (typeof window === 'object') {
return 'browser';
}
// @ts-ignore
if (typeof WebSocketPair !== 'undefined') {
return 'cloudflare-worker';
}
// @ts-ignore
if (typeof EdgeRuntime === 'string') {
return 'vercel-edge';
}
if (
// @ts-ignore
typeof WorkerGlobalScope !== 'undefined' &&
// @ts-ignore
typeof importScripts === 'function') {
return 'web-worker';
}
return 'unknown';
};
exports.detectRuntime = detectRuntime;
//# sourceMappingURL=env.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../../src/lib/env.ts"],"names":[],"mappings":";;;AASO,MAAM,aAAa,GAAG,GAAe,EAAE;IAC5C,IACE,OAAO,OAAO,KAAK,QAAQ;QAC3B,OAAO;QACP,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ;QAC/B,OAAO,CAAC,GAAG;QACX,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,EACnC;QACA,OAAO,MAAM,CAAA;KACd;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QAC9B,OAAO,SAAS,CAAA;KACjB;IAED,aAAa;IACb,IAAI,OAAO,aAAa,KAAK,WAAW,EAAE;QACxC,OAAO,mBAAmB,CAAA;KAC3B;IAED,aAAa;IACb,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE;QACnC,OAAO,aAAa,CAAA;KACrB;IAED;IACE,aAAa;IACb,OAAO,iBAAiB,KAAK,WAAW;QACxC,aAAa;QACb,OAAO,aAAa,KAAK,UAAU,EACnC;QACA,OAAO,YAAY,CAAA;KACpB;IAED,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA;AAnCY,QAAA,aAAa,iBAmCzB"}

View File

@@ -0,0 +1,41 @@
"use strict";
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 (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.fetch = void 0;
const fetch = async (...args) => {
if (globalThis.fetch) {
return globalThis.fetch(...args);
}
// This guard causes is important, as it causes dead-code elimination to be enabled inside this block.
// @ts-ignore
else if (typeof EdgeRuntime !== 'string') {
return (await Promise.resolve().then(() => __importStar(require('node-fetch')))).default(...args);
}
else {
throw new Error('Invariant: an edge runtime that does not support fetch should not exist');
}
};
exports.fetch = fetch;
//# sourceMappingURL=fetch.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../../src/lib/fetch.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;AAEO,MAAM,KAAK,GAAgB,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE;IAClD,IAAI,UAAU,CAAC,KAAK,EAAE;QACpB,OAAO,UAAU,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAA;KACjC;IACD,sGAAsG;IACtG,aAAa;SACR,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE;QACxC,OAAO,CAAC,wDAAa,YAAY,GAAC,CAAC,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAA;KACrD;SAAM;QACL,MAAM,IAAI,KAAK,CACb,yEAAyE,CAC1E,CAAA;KACF;AACH,CAAC,CAAA;AAbY,QAAA,KAAK,SAajB"}

View File

@@ -0,0 +1,14 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createMessageId = void 0;
const uuid_1 = require("./uuid");
/**
* get a unique messageId with a very low chance of collisions
* using @lukeed/uuid/secure uses the node crypto module, which is the fastest
* @example "node-next-1668208232027-743be593-7789-4b74-8078-cbcc8894c586"
*/
const createMessageId = () => {
return `node-next-${Date.now()}-${(0, uuid_1.uuid)()}`;
};
exports.createMessageId = createMessageId;
//# sourceMappingURL=get-message-id.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"get-message-id.js","sourceRoot":"","sources":["../../../src/lib/get-message-id.ts"],"names":[],"mappings":";;;AAAA,iCAA6B;AAE7B;;;;GAIG;AACI,MAAM,eAAe,GAAG,GAAW,EAAE;IAC1C,OAAO,aAAa,IAAI,CAAC,GAAG,EAAE,IAAI,IAAA,WAAI,GAAE,EAAE,CAAA;AAC5C,CAAC,CAAA;AAFY,QAAA,eAAe,mBAE3B"}

View File

@@ -0,0 +1,26 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FetchHTTPClient = void 0;
const abort_1 = require("./abort");
const fetch_1 = require("./fetch");
/**
* Default HTTP client implementation using fetch
*/
class FetchHTTPClient {
constructor(fetchFn) {
this._fetch = fetchFn ?? fetch_1.fetch;
}
async makeRequest(options) {
const [signal, timeoutId] = (0, abort_1.abortSignalAfterTimeout)(options.httpRequestTimeout);
const requestInit = {
url: options.url,
method: options.method,
headers: options.headers,
body: JSON.stringify(options.data),
signal: signal,
};
return this._fetch(options.url, requestInit).finally(() => clearTimeout(timeoutId));
}
}
exports.FetchHTTPClient = FetchHTTPClient;
//# sourceMappingURL=http-client.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../../src/lib/http-client.ts"],"names":[],"mappings":";;;AAAA,mCAAiD;AACjD,mCAA+C;AAoE/C;;GAEG;AACH,MAAa,eAAe;IAE1B,YAAY,OAAqB;QAC/B,IAAI,CAAC,MAAM,GAAG,OAAO,IAAI,aAAY,CAAA;IACvC,CAAC;IACD,KAAK,CAAC,WAAW,CAAC,OAA0B;QAC1C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,IAAA,+BAAuB,EACjD,OAAO,CAAC,kBAAkB,CAC3B,CAAA;QAED,MAAM,WAAW,GAAG;YAClB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;YAClC,MAAM,EAAE,MAAM;SACf,CAAA;QAED,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CACxD,YAAY,CAAC,SAAS,CAAC,CACxB,CAAA;IACH,CAAC;CACF;AAtBD,0CAsBC"}

View File

@@ -0,0 +1,6 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.uuid = void 0;
var uuid_1 = require("@lukeed/uuid");
Object.defineProperty(exports, "uuid", { enumerable: true, get: function () { return uuid_1.v4; } });
//# sourceMappingURL=uuid.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"uuid.js","sourceRoot":"","sources":["../../../src/lib/uuid.ts"],"names":[],"mappings":";;;AAAA,qCAAyC;AAAhC,4FAAA,EAAE,OAAQ"}

View File

@@ -0,0 +1,55 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ContextBatch = void 0;
const uuid_1 = require("../../lib/uuid");
const MAX_EVENT_SIZE_IN_KB = 32;
const MAX_BATCH_SIZE_IN_KB = 480; // (500 KB is the limit, leaving some padding)
class ContextBatch {
constructor(maxEventCount) {
this.id = (0, uuid_1.uuid)();
this.items = [];
this.sizeInBytes = 0;
this.maxEventCount = Math.max(1, maxEventCount);
}
tryAdd(item) {
if (this.length === this.maxEventCount)
return {
success: false,
message: `Event limit of ${this.maxEventCount} has been exceeded.`,
};
const eventSize = this.calculateSize(item.context);
if (eventSize > MAX_EVENT_SIZE_IN_KB * 1024) {
return {
success: false,
message: `Event exceeds maximum event size of ${MAX_EVENT_SIZE_IN_KB} KB`,
};
}
if (this.sizeInBytes + eventSize > MAX_BATCH_SIZE_IN_KB * 1024) {
return {
success: false,
message: `Event has caused batch size to exceed ${MAX_BATCH_SIZE_IN_KB} KB`,
};
}
this.items.push(item);
this.sizeInBytes += eventSize;
return { success: true };
}
get length() {
return this.items.length;
}
calculateSize(ctx) {
return encodeURI(JSON.stringify(ctx.event)).split(/%..|i/).length;
}
getEvents() {
const events = this.items.map(({ context }) => context.event);
return events;
}
getContexts() {
return this.items.map((item) => item.context);
}
resolveEvents() {
this.items.forEach(({ resolver, context }) => resolver(context));
}
}
exports.ContextBatch = ContextBatch;
//# sourceMappingURL=context-batch.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"context-batch.js","sourceRoot":"","sources":["../../../../src/plugins/segmentio/context-batch.ts"],"names":[],"mappings":";;;AAAA,yCAAqC;AAIrC,MAAM,oBAAoB,GAAG,EAAE,CAAA;AAC/B,MAAM,oBAAoB,GAAG,GAAG,CAAA,CAAC,+CAA+C;AAOhF,MAAa,YAAY;IAMvB,YAAY,aAAqB;QAL1B,OAAE,GAAG,IAAA,WAAI,GAAE,CAAA;QACV,UAAK,GAAkB,EAAE,CAAA;QACzB,gBAAW,GAAG,CAAC,CAAA;QAIrB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,CAAC,CAAA;IACjD,CAAC;IACM,MAAM,CACX,IAAiB;QAEjB,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,aAAa;YACpC,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,kBAAkB,IAAI,CAAC,aAAa,qBAAqB;aACnE,CAAA;QAEH,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAClD,IAAI,SAAS,GAAG,oBAAoB,GAAG,IAAI,EAAE;YAC3C,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,uCAAuC,oBAAoB,KAAK;aAC1E,CAAA;SACF;QAED,IAAI,IAAI,CAAC,WAAW,GAAG,SAAS,GAAG,oBAAoB,GAAG,IAAI,EAAE;YAC9D,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,yCAAyC,oBAAoB,KAAK;aAC5E,CAAA;SACF;QAED,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACrB,IAAI,CAAC,WAAW,IAAI,SAAS,CAAA;QAC7B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IAC1B,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAA;IAC1B,CAAC;IAEO,aAAa,CAAC,GAAY;QAChC,OAAO,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAA;IACnE,CAAC;IAED,SAAS;QACP,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC7D,OAAO,MAAM,CAAA;IACf,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC/C,CAAC;IAED,aAAa;QACX,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;IAClE,CAAC;CACF;AA1DD,oCA0DC"}

View File

@@ -0,0 +1,45 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.createConfiguredNodePlugin = exports.createNodePlugin = void 0;
const publisher_1 = require("./publisher");
const version_1 = require("../../generated/version");
const env_1 = require("../../lib/env");
function normalizeEvent(ctx) {
ctx.updateEvent('context.library.name', '@segment/analytics-node');
ctx.updateEvent('context.library.version', version_1.version);
const runtime = (0, env_1.detectRuntime)();
if (runtime === 'node') {
// eslint-disable-next-line no-restricted-globals
ctx.updateEvent('_metadata.nodeVersion', process.version);
}
ctx.updateEvent('_metadata.jsRuntime', runtime);
}
function createNodePlugin(publisher) {
function action(ctx) {
normalizeEvent(ctx);
return publisher.enqueue(ctx);
}
return {
name: 'Segment.io',
type: 'destination',
version: '1.0.0',
isLoaded: () => true,
load: () => Promise.resolve(),
alias: action,
group: action,
identify: action,
page: action,
screen: action,
track: action,
};
}
exports.createNodePlugin = createNodePlugin;
const createConfiguredNodePlugin = (props, emitter) => {
const publisher = new publisher_1.Publisher(props, emitter);
return {
publisher: publisher,
plugin: createNodePlugin(publisher),
};
};
exports.createConfiguredNodePlugin = createConfiguredNodePlugin;
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/plugins/segmentio/index.ts"],"names":[],"mappings":";;;AAAA,2CAAuD;AACvD,qDAAiD;AACjD,uCAA6C;AAK7C,SAAS,cAAc,CAAC,GAAY;IAClC,GAAG,CAAC,WAAW,CAAC,sBAAsB,EAAE,yBAAyB,CAAC,CAAA;IAClE,GAAG,CAAC,WAAW,CAAC,yBAAyB,EAAE,iBAAO,CAAC,CAAA;IACnD,MAAM,OAAO,GAAG,IAAA,mBAAa,GAAE,CAAA;IAC/B,IAAI,OAAO,KAAK,MAAM,EAAE;QACtB,iDAAiD;QACjD,GAAG,CAAC,WAAW,CAAC,uBAAuB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;KAC1D;IACD,GAAG,CAAC,WAAW,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAA;AACjD,CAAC;AAmBD,SAAgB,gBAAgB,CAAC,SAAoB;IACnD,SAAS,MAAM,CAAC,GAAY;QAC1B,cAAc,CAAC,GAAG,CAAC,CAAA;QACnB,OAAO,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAC/B,CAAC;IAED,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,OAAO;QAChB,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI;QACpB,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;QAC7B,KAAK,EAAE,MAAM;QACb,KAAK,EAAE,MAAM;QACb,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,MAAM;QACZ,MAAM,EAAE,MAAM;QACd,KAAK,EAAE,MAAM;KACd,CAAA;AACH,CAAC;AAnBD,4CAmBC;AAEM,MAAM,0BAA0B,GAAG,CACxC,KAA+B,EAC/B,OAAoB,EACpB,EAAE;IACF,MAAM,SAAS,GAAG,IAAI,qBAAS,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IAC/C,OAAO;QACL,SAAS,EAAE,SAAS;QACpB,MAAM,EAAE,gBAAgB,CAAC,SAAS,CAAC;KACpC,CAAA;AACH,CAAC,CAAA;AATY,QAAA,0BAA0B,8BAStC"}

View File

@@ -0,0 +1,191 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.Publisher = void 0;
const analytics_core_1 = require("@segment/analytics-core");
const create_url_1 = require("../../lib/create-url");
const analytics_generic_utils_1 = require("@segment/analytics-generic-utils");
const context_batch_1 = require("./context-batch");
const base_64_encode_1 = require("../../lib/base-64-encode");
function sleep(timeoutInMs) {
return new Promise((resolve) => setTimeout(resolve, timeoutInMs));
}
function noop() { }
/**
* The Publisher is responsible for batching events and sending them to the Segment API.
*/
class Publisher {
constructor({ host, path, maxRetries, flushAt, flushInterval, writeKey, httpRequestTimeout, httpClient, disable, }, emitter) {
this._emitter = emitter;
this._maxRetries = maxRetries;
this._flushAt = Math.max(flushAt, 1);
this._flushInterval = flushInterval;
this._auth = (0, base_64_encode_1.b64encode)(`${writeKey}:`);
this._url = (0, create_url_1.tryCreateFormattedUrl)(host ?? 'https://api.segment.io', path ?? '/v1/batch');
this._httpRequestTimeout = httpRequestTimeout ?? 10000;
this._disable = Boolean(disable);
this._httpClient = httpClient;
}
createBatch() {
this.pendingFlushTimeout && clearTimeout(this.pendingFlushTimeout);
const batch = new context_batch_1.ContextBatch(this._flushAt);
this._batch = batch;
this.pendingFlushTimeout = setTimeout(() => {
if (batch === this._batch) {
this._batch = undefined;
}
this.pendingFlushTimeout = undefined;
if (batch.length) {
this.send(batch).catch(noop);
}
}, this._flushInterval);
return batch;
}
clearBatch() {
this.pendingFlushTimeout && clearTimeout(this.pendingFlushTimeout);
this._batch = undefined;
}
flush(pendingItemsCount) {
if (!pendingItemsCount) {
// if number of pending items is 0, there is nothing to flush
return;
}
this._flushPendingItemsCount = pendingItemsCount;
// if batch is empty, there's nothing to flush, and when things come in, enqueue will handle them.
if (!this._batch)
return;
// the number of globally pending items will always be larger or the same as batch size.
// Any mismatch is because some globally pending items are in plugins.
const isExpectingNoMoreItems = this._batch.length === pendingItemsCount;
if (isExpectingNoMoreItems) {
this.send(this._batch).catch(noop);
this.clearBatch();
}
}
/**
* Enqueues the context for future delivery.
* @param ctx - Context containing a Segment event.
* @returns a promise that resolves with the context after the event has been delivered.
*/
enqueue(ctx) {
const batch = this._batch ?? this.createBatch();
const { promise: ctxPromise, resolve } = (0, analytics_generic_utils_1.createDeferred)();
const pendingItem = {
context: ctx,
resolver: resolve,
};
/*
The following logic ensures that a batch is never orphaned,
and is always sent before a new batch is created.
Add an event to the existing batch.
Success: Check if batch is full or no more items are expected to come in (i.e. closing). If so, send batch.
Failure: Assume event is too big to fit in current batch - send existing batch.
Add an event to the new batch.
Success: Check if batch is full and send if it is.
Failure: Event exceeds maximum size (it will never fit), fail the event.
*/
const addStatus = batch.tryAdd(pendingItem);
if (addStatus.success) {
const isExpectingNoMoreItems = batch.length === this._flushPendingItemsCount;
const isFull = batch.length === this._flushAt;
if (isFull || isExpectingNoMoreItems) {
this.send(batch).catch(noop);
this.clearBatch();
}
return ctxPromise;
}
// If the new item causes the maximimum event size to be exceeded, send the current batch and create a new one.
if (batch.length) {
this.send(batch).catch(noop);
this.clearBatch();
}
const fallbackBatch = this.createBatch();
const fbAddStatus = fallbackBatch.tryAdd(pendingItem);
if (fbAddStatus.success) {
const isExpectingNoMoreItems = fallbackBatch.length === this._flushPendingItemsCount;
if (isExpectingNoMoreItems) {
this.send(fallbackBatch).catch(noop);
this.clearBatch();
}
return ctxPromise;
}
else {
// this should only occur if max event size is exceeded
ctx.setFailedDelivery({
reason: new Error(fbAddStatus.message),
});
return Promise.resolve(ctx);
}
}
async send(batch) {
if (this._flushPendingItemsCount) {
this._flushPendingItemsCount -= batch.length;
}
const events = batch.getEvents();
const maxAttempts = this._maxRetries + 1;
let currentAttempt = 0;
while (currentAttempt < maxAttempts) {
currentAttempt++;
let failureReason;
try {
if (this._disable) {
return batch.resolveEvents();
}
const request = {
url: this._url,
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Basic ${this._auth}`,
'User-Agent': 'analytics-node-next/latest',
},
data: { batch: events, sentAt: new Date() },
httpRequestTimeout: this._httpRequestTimeout,
};
this._emitter.emit('http_request', {
body: request.data,
method: request.method,
url: request.url,
headers: request.headers,
});
const response = await this._httpClient.makeRequest(request);
if (response.status >= 200 && response.status < 300) {
// Successfully sent events, so exit!
batch.resolveEvents();
return;
}
else if (response.status === 400) {
// https://segment.com/docs/connections/sources/catalog/libraries/server/http-api/#max-request-size
// Request either malformed or size exceeded - don't retry.
resolveFailedBatch(batch, new Error(`[${response.status}] ${response.statusText}`));
return;
}
else {
// Treat other errors as transient and retry.
failureReason = new Error(`[${response.status}] ${response.statusText}`);
}
}
catch (err) {
// Network errors get thrown, retry them.
failureReason = err;
}
// Final attempt failed, update context and resolve events.
if (currentAttempt === maxAttempts) {
resolveFailedBatch(batch, failureReason);
return;
}
// Retry after attempt-based backoff.
await sleep((0, analytics_core_1.backoff)({
attempt: currentAttempt,
minTimeout: 25,
maxTimeout: 1000,
}));
}
}
}
exports.Publisher = Publisher;
function resolveFailedBatch(batch, reason) {
batch.getContexts().forEach((ctx) => ctx.setFailedDelivery({ reason }));
batch.resolveEvents();
}
//# sourceMappingURL=publisher.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,201 @@
import { bindAll, pTimeout } from '@segment/analytics-core';
import { validateSettings } from './settings';
import { version } from '../generated/version';
import { createConfiguredNodePlugin } from '../plugins/segmentio';
import { NodeEventFactory } from './event-factory';
import { dispatchAndEmit } from './dispatch-emit';
import { NodeEmitter } from './emitter';
import { Context } from './context';
import { NodeEventQueue } from './event-queue';
import { FetchHTTPClient } from '../lib/http-client';
export class Analytics extends NodeEmitter {
constructor(settings) {
super();
this._isClosed = false;
this._pendingEvents = 0;
this._isFlushing = false;
validateSettings(settings);
this._eventFactory = new NodeEventFactory();
this._queue = new 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 } = 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 FetchHTTPClient(settings.httpClient)
: settings.httpClient ?? new FetchHTTPClient(),
}, this);
this._publisher = publisher;
this.ready = this.register(plugin).then(() => undefined);
this.emit('initialize', settings);
bindAll(this);
}
get VERSION() {
return 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 ? pTimeout(promise, timeout).catch(() => undefined) : promise;
}
_dispatch(segmentEvent, callback) {
if (this._isClosed) {
this.emit('call_after_close', segmentEvent);
return undefined;
}
this._pendingEvents++;
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 }, callback) {
const segmentEvent = this._eventFactory.alias(userId, previousId, {
context,
integrations,
timestamp,
});
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, }, callback) {
const segmentEvent = this._eventFactory.group(groupId, traits, {
context,
anonymousId,
userId,
timestamp,
integrations,
});
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, }, callback) {
const segmentEvent = this._eventFactory.identify(userId, traits, {
context,
anonymousId,
userId,
timestamp,
integrations,
});
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, }, callback) {
const segmentEvent = this._eventFactory.page(category ?? null, name ?? null, properties, { context, anonymousId, userId, timestamp, integrations });
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, }, callback) {
const segmentEvent = this._eventFactory.screen(category ?? null, name ?? null, properties, { context, anonymousId, userId, timestamp, integrations });
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, }, callback) {
const segmentEvent = this._eventFactory.track(event, properties, {
context,
userId,
anonymousId,
timestamp,
integrations,
});
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.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.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);
}
}
//# sourceMappingURL=analytics-node.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,9 @@
// create a derived class since we may want to add node specific things to Context later
import { CoreContext } from '@segment/analytics-core';
// While this is not a type, it is a definition
export class Context extends CoreContext {
static system() {
return new this({ type: 'track', event: 'system' });
}
}
//# sourceMappingURL=context.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"context.js","sourceRoot":"","sources":["../../../src/app/context.ts"],"names":[],"mappings":"AAAA,wFAAwF;AAExF,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAA;AAGrD,+CAA+C;AAC/C,MAAM,OAAO,OAAQ,SAAQ,WAAyB;IACpD,MAAM,CAAU,MAAM;QACpB,OAAO,IAAI,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAA;IACrD,CAAC;CACF"}

View File

@@ -0,0 +1,33 @@
import { dispatch } from '@segment/analytics-core';
import { Context } from './context';
const normalizeDispatchCb = (cb) => (ctx) => {
const failedDelivery = ctx.failedDelivery();
return failedDelivery ? cb(failedDelivery.reason, ctx) : cb(undefined, ctx);
};
/* Dispatch function, but swallow promise rejections and use event emitter instead */
export const dispatchAndEmit = async (event, queue, emitter, callback) => {
try {
const context = new Context(event);
const ctx = await dispatch(context, queue, emitter, {
...(callback ? { callback: normalizeDispatchCb(callback) } : {}),
});
const failedDelivery = ctx.failedDelivery();
if (failedDelivery) {
emitter.emit('error', {
code: 'delivery_failure',
reason: failedDelivery.reason,
ctx: ctx,
});
}
else {
emitter.emit(event.type, ctx);
}
}
catch (err) {
emitter.emit('error', {
code: 'unknown',
reason: err,
});
}
};
//# sourceMappingURL=dispatch-emit.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"dispatch-emit.js","sourceRoot":"","sources":["../../../src/app/dispatch-emit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAA;AAElD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAMnC,MAAM,mBAAmB,GAAG,CAAC,EAAY,EAAE,EAAE,CAAC,CAAC,GAAY,EAAE,EAAE;IAC7D,MAAM,cAAc,GAAG,GAAG,CAAC,cAAc,EAAE,CAAA;IAC3C,OAAO,cAAc,CAAC,CAAC,CAAC,EAAE,CAAC,cAAc,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;AAC7E,CAAC,CAAA;AAED,qFAAqF;AACrF,MAAM,CAAC,MAAM,eAAe,GAAG,KAAK,EAClC,KAAmB,EACnB,KAAqB,EACrB,OAAoB,EACpB,QAAmB,EACJ,EAAE;IACjB,IAAI;QACF,MAAM,OAAO,GAAG,IAAI,OAAO,CAAC,KAAK,CAAC,CAAA;QAClC,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE;YAClD,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,mBAAmB,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACjE,CAAC,CAAA;QACF,MAAM,cAAc,GAAG,GAAG,CAAC,cAAc,EAAE,CAAA;QAC3C,IAAI,cAAc,EAAE;YAClB,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE;gBACpB,IAAI,EAAE,kBAAkB;gBACxB,MAAM,EAAE,cAAc,CAAC,MAAM;gBAC7B,GAAG,EAAE,GAAG;aACT,CAAC,CAAA;SACH;aAAM;YACL,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;SAC9B;KACF;IAAC,OAAO,GAAG,EAAE;QACZ,OAAO,CAAC,IAAI,CAAC,OAAO,EAAE;YACpB,IAAI,EAAE,SAAS;YACf,MAAM,EAAE,GAAG;SACZ,CAAC,CAAA;KACH;AACH,CAAC,CAAA"}

View File

@@ -0,0 +1,4 @@
import { Emitter } from '@segment/analytics-generic-utils';
export class NodeEmitter extends Emitter {
}
//# sourceMappingURL=emitter.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"emitter.js","sourceRoot":"","sources":["../../../src/app/emitter.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAA;AAsB1D,MAAM,OAAO,WAAY,SAAQ,OAA0B;CAAG"}

View File

@@ -0,0 +1,8 @@
import { EventFactory } from '@segment/analytics-core';
import { createMessageId } from '../lib/get-message-id';
export class NodeEventFactory extends EventFactory {
constructor() {
super({ createMessageId });
}
}
//# sourceMappingURL=event-factory.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"event-factory.js","sourceRoot":"","sources":["../../../src/app/event-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACtD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAcvD,MAAM,OAAO,gBAAiB,SAAQ,YAAY;IAChD;QACE,KAAK,CAAC,EAAE,eAAe,EAAE,CAAC,CAAA;IAC5B,CAAC;CACF"}

View File

@@ -0,0 +1,20 @@
import { CoreEventQueue, PriorityQueue } from '@segment/analytics-core';
class NodePriorityQueue extends PriorityQueue {
constructor() {
super(1, []);
}
// do not use an internal "seen" map
getAttempts(ctx) {
return ctx.attempts ?? 0;
}
updateAttempts(ctx) {
ctx.attempts = this.getAttempts(ctx) + 1;
return this.getAttempts(ctx);
}
}
export class NodeEventQueue extends CoreEventQueue {
constructor() {
super(new NodePriorityQueue());
}
}
//# sourceMappingURL=event-queue.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"event-queue.js","sourceRoot":"","sources":["../../../src/app/event-queue.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAA;AAIvE,MAAM,iBAAkB,SAAQ,aAAsB;IACpD;QACE,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IACd,CAAC;IACD,oCAAoC;IACpC,WAAW,CAAC,GAAY;QACtB,OAAO,GAAG,CAAC,QAAQ,IAAI,CAAC,CAAA;IAC1B,CAAC;IACD,cAAc,CAAC,GAAY;QACzB,GAAG,CAAC,QAAQ,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACxC,OAAO,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAA;IAC9B,CAAC;CACF;AAED,MAAM,OAAO,cAAe,SAAQ,cAA+B;IACjE;QACE,KAAK,CAAC,IAAI,iBAAiB,EAAE,CAAC,CAAA;IAChC,CAAC;CACF"}

View File

@@ -0,0 +1,7 @@
import { ValidationError } from '@segment/analytics-core';
export const validateSettings = (settings) => {
if (!settings.writeKey) {
throw new ValidationError('writeKey', 'writeKey is missing.');
}
};
//# sourceMappingURL=settings.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"settings.js","sourceRoot":"","sources":["../../../src/app/settings.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAA;AAiDzD,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,QAA2B,EAAE,EAAE;IAC9D,IAAI,CAAC,QAAQ,CAAC,QAAQ,EAAE;QACtB,MAAM,IAAI,eAAe,CAAC,UAAU,EAAE,sBAAsB,CAAC,CAAA;KAC9D;AACH,CAAC,CAAA"}

View File

@@ -0,0 +1,4 @@
export * from './params';
export * from './segment-event';
export * from './plugin';
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/app/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,UAAU,CAAA;AACxB,cAAc,iBAAiB,CAAA;AAC/B,cAAc,UAAU,CAAA"}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=params.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"params.js","sourceRoot":"","sources":["../../../../src/app/types/params.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=plugin.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../../../../src/app/types/plugin.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,2 @@
export {};
//# sourceMappingURL=segment-event.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"segment-event.js","sourceRoot":"","sources":["../../../../src/app/types/segment-event.ts"],"names":[],"mappings":""}

View File

@@ -0,0 +1,3 @@
// This file is generated.
export const version = '1.3.0';
//# sourceMappingURL=version.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"version.js","sourceRoot":"","sources":["../../../src/generated/version.ts"],"names":[],"mappings":"AAAA,0BAA0B;AAC1B,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAA"}

View File

@@ -0,0 +1,7 @@
export { Analytics } from './app/analytics-node';
export { Context } from './app/context';
export { FetchHTTPClient, } from './lib/http-client';
// export Analytics as both a named export and a default export (for backwards-compat. reasons)
import { Analytics } from './app/analytics-node';
export default Analytics;
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAChD,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAA;AACvC,OAAO,EAEL,eAAe,GAKhB,MAAM,mBAAmB,CAAA;AAc1B,+FAA+F;AAC/F,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAChD,eAAe,SAAS,CAAA"}

View File

@@ -0,0 +1,73 @@
/**
* use non-native event emitter for the benefit of non-node runtimes like CF workers.
*/
import { Emitter } from '@segment/analytics-generic-utils';
import { detectRuntime } from './env';
/**
* adapted from: https://www.npmjs.com/package/node-abort-controller
*/
export class AbortSignal {
constructor() {
this.onabort = null;
this.aborted = false;
this.eventEmitter = new Emitter();
}
toString() {
return '[object AbortSignal]';
}
get [Symbol.toStringTag]() {
return 'AbortSignal';
}
removeEventListener(...args) {
this.eventEmitter.off(...args);
}
addEventListener(...args) {
this.eventEmitter.on(...args);
}
dispatchEvent(type) {
const event = { type, target: this };
const handlerName = `on${type}`;
if (typeof this[handlerName] === 'function') {
;
this[handlerName](event);
}
this.eventEmitter.emit(type, event);
}
}
/**
* This polyfill is only neccessary to support versions of node < 14.17.
* Can be removed once node 14 support is dropped.
*/
class AbortController {
constructor() {
this.signal = new AbortSignal();
}
abort() {
if (this.signal.aborted)
return;
this.signal.aborted = true;
this.signal.dispatchEvent('abort');
}
toString() {
return '[object AbortController]';
}
get [Symbol.toStringTag]() {
return 'AbortController';
}
}
/**
* @param timeoutMs - Set a request timeout, after which the request is cancelled.
*/
export const abortSignalAfterTimeout = (timeoutMs) => {
if (detectRuntime() === 'cloudflare-worker') {
return []; // TODO: this is broken in cloudflare workers, otherwise results in "A hanging Promise was canceled..." error.
}
const ac = new (globalThis.AbortController || AbortController)();
const timeoutId = setTimeout(() => {
ac.abort();
}, timeoutMs);
// Allow Node.js processes to exit early if only the timeout is running
timeoutId?.unref?.();
return [ac.signal, timeoutId];
};
//# sourceMappingURL=abort.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"abort.js","sourceRoot":"","sources":["../../../src/lib/abort.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,OAAO,EAAE,MAAM,kCAAkC,CAAA;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,OAAO,CAAA;AAErC;;GAEG;AACH,MAAM,OAAO,WAAW;IAAxB;QACE,YAAO,GAAsC,IAAI,CAAA;QACjD,YAAO,GAAG,KAAK,CAAA;QACf,iBAAY,GAAG,IAAI,OAAO,EAAE,CAAA;IAyB9B,CAAC;IAvBC,QAAQ;QACN,OAAO,sBAAsB,CAAA;IAC/B,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QACtB,OAAO,aAAa,CAAA;IACtB,CAAC;IACD,mBAAmB,CAAC,GAAG,IAAgC;QACrD,IAAI,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,CAAA;IAChC,CAAC;IACD,gBAAgB,CAAC,GAAG,IAA+B;QACjD,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAA;IAC/B,CAAC;IACD,aAAa,CAAC,IAAY;QACxB,MAAM,KAAK,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAA;QAEpC,MAAM,WAAW,GAAG,KAAK,IAAI,EAAE,CAAA;QAE/B,IAAI,OAAQ,IAAY,CAAC,WAAW,CAAC,KAAK,UAAU,EAAE;YACpD,CAAC;YAAC,IAAY,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAA;SACnC;QAED,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACrC,CAAC;CACF;AAED;;;GAGG;AACH,MAAM,eAAe;IAArB;QACE,WAAM,GAAG,IAAI,WAAW,EAAE,CAAA;IAa5B,CAAC;IAZC,KAAK;QACH,IAAI,IAAI,CAAC,MAAM,CAAC,OAAO;YAAE,OAAM;QAE/B,IAAI,CAAC,MAAM,CAAC,OAAO,GAAG,IAAI,CAAA;QAC1B,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,OAAO,CAAC,CAAA;IACpC,CAAC;IACD,QAAQ;QACN,OAAO,0BAA0B,CAAA;IACnC,CAAC;IACD,IAAI,CAAC,MAAM,CAAC,WAAW,CAAC;QACtB,OAAO,iBAAiB,CAAA;IAC1B,CAAC;CACF;AAED;;GAEG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,SAAiB,EAAE,EAAE;IAC3D,IAAI,aAAa,EAAE,KAAK,mBAAmB,EAAE;QAC3C,OAAO,EAAE,CAAA,CAAC,8GAA8G;KACzH;IACD,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,eAAe,IAAI,eAAe,CAAC,EAAE,CAAA;IAEhE,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,EAAE;QAChC,EAAE,CAAC,KAAK,EAAE,CAAA;IACZ,CAAC,EAAE,SAAS,CAAC,CAAA;IAEb,uEAAuE;IACvE,SAAS,EAAE,KAAK,EAAE,EAAE,CAAA;IAEpB,OAAO,CAAC,EAAE,CAAC,MAAM,EAAE,SAAS,CAAU,CAAA;AACxC,CAAC,CAAA"}

View File

@@ -0,0 +1,9 @@
// eslint-disable-next-line import/no-nodejs-modules
import { Buffer } from 'buffer';
/**
* Base64 encoder that works in browser, worker, node runtimes.
*/
export const b64encode = (str) => {
return Buffer.from(str).toString('base64');
};
//# sourceMappingURL=base-64-encode.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"base-64-encode.js","sourceRoot":"","sources":["../../../src/lib/base-64-encode.ts"],"names":[],"mappings":"AAAA,oDAAoD;AACpD,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAC/B;;GAEG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,GAAW,EAAU,EAAE;IAC/C,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAA;AAC5C,CAAC,CAAA"}

View File

@@ -0,0 +1,11 @@
const stripTrailingSlash = (str) => str.replace(/\/$/, '');
/**
*
* @param host e.g. "http://foo.com"
* @param path e.g. "/bar"
* @returns "e.g." "http://foo.com/bar"
*/
export const tryCreateFormattedUrl = (host, path) => {
return stripTrailingSlash(new URL(path || '', host).href);
};
//# sourceMappingURL=create-url.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"create-url.js","sourceRoot":"","sources":["../../../src/lib/create-url.ts"],"names":[],"mappings":"AAAA,MAAM,kBAAkB,GAAG,CAAC,GAAW,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAA;AAElE;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,IAAY,EAAE,IAAa,EAAE,EAAE;IACnE,OAAO,kBAAkB,CAAC,IAAI,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAA;AAC3D,CAAC,CAAA"}

View File

@@ -0,0 +1,29 @@
export const detectRuntime = () => {
if (typeof process === 'object' &&
process &&
typeof process.env === 'object' &&
process.env &&
typeof process.version === 'string') {
return 'node';
}
if (typeof window === 'object') {
return 'browser';
}
// @ts-ignore
if (typeof WebSocketPair !== 'undefined') {
return 'cloudflare-worker';
}
// @ts-ignore
if (typeof EdgeRuntime === 'string') {
return 'vercel-edge';
}
if (
// @ts-ignore
typeof WorkerGlobalScope !== 'undefined' &&
// @ts-ignore
typeof importScripts === 'function') {
return 'web-worker';
}
return 'unknown';
};
//# sourceMappingURL=env.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../../src/lib/env.ts"],"names":[],"mappings":"AASA,MAAM,CAAC,MAAM,aAAa,GAAG,GAAe,EAAE;IAC5C,IACE,OAAO,OAAO,KAAK,QAAQ;QAC3B,OAAO;QACP,OAAO,OAAO,CAAC,GAAG,KAAK,QAAQ;QAC/B,OAAO,CAAC,GAAG;QACX,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,EACnC;QACA,OAAO,MAAM,CAAA;KACd;IAED,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE;QAC9B,OAAO,SAAS,CAAA;KACjB;IAED,aAAa;IACb,IAAI,OAAO,aAAa,KAAK,WAAW,EAAE;QACxC,OAAO,mBAAmB,CAAA;KAC3B;IAED,aAAa;IACb,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE;QACnC,OAAO,aAAa,CAAA;KACrB;IAED;IACE,aAAa;IACb,OAAO,iBAAiB,KAAK,WAAW;QACxC,aAAa;QACb,OAAO,aAAa,KAAK,UAAU,EACnC;QACA,OAAO,YAAY,CAAA;KACpB;IAED,OAAO,SAAS,CAAA;AAClB,CAAC,CAAA"}

View File

@@ -0,0 +1,14 @@
export const fetch = async (...args) => {
if (globalThis.fetch) {
return globalThis.fetch(...args);
}
// This guard causes is important, as it causes dead-code elimination to be enabled inside this block.
// @ts-ignore
else if (typeof EdgeRuntime !== 'string') {
return (await import('node-fetch')).default(...args);
}
else {
throw new Error('Invariant: an edge runtime that does not support fetch should not exist');
}
};
//# sourceMappingURL=fetch.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"fetch.js","sourceRoot":"","sources":["../../../src/lib/fetch.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,KAAK,GAAgB,KAAK,EAAE,GAAG,IAAI,EAAE,EAAE;IAClD,IAAI,UAAU,CAAC,KAAK,EAAE;QACpB,OAAO,UAAU,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,CAAA;KACjC;IACD,sGAAsG;IACtG,aAAa;SACR,IAAI,OAAO,WAAW,KAAK,QAAQ,EAAE;QACxC,OAAO,CAAC,MAAM,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAA;KACrD;SAAM;QACL,MAAM,IAAI,KAAK,CACb,yEAAyE,CAC1E,CAAA;KACF;AACH,CAAC,CAAA"}

View File

@@ -0,0 +1,10 @@
import { uuid } from './uuid';
/**
* get a unique messageId with a very low chance of collisions
* using @lukeed/uuid/secure uses the node crypto module, which is the fastest
* @example "node-next-1668208232027-743be593-7789-4b74-8078-cbcc8894c586"
*/
export const createMessageId = () => {
return `node-next-${Date.now()}-${uuid()}`;
};
//# sourceMappingURL=get-message-id.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"get-message-id.js","sourceRoot":"","sources":["../../../src/lib/get-message-id.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AAE7B;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,GAAW,EAAE;IAC1C,OAAO,aAAa,IAAI,CAAC,GAAG,EAAE,IAAI,IAAI,EAAE,EAAE,CAAA;AAC5C,CAAC,CAAA"}

View File

@@ -0,0 +1,22 @@
import { abortSignalAfterTimeout } from './abort';
import { fetch as defaultFetch } from './fetch';
/**
* Default HTTP client implementation using fetch
*/
export class FetchHTTPClient {
constructor(fetchFn) {
this._fetch = fetchFn ?? defaultFetch;
}
async makeRequest(options) {
const [signal, timeoutId] = abortSignalAfterTimeout(options.httpRequestTimeout);
const requestInit = {
url: options.url,
method: options.method,
headers: options.headers,
body: JSON.stringify(options.data),
signal: signal,
};
return this._fetch(options.url, requestInit).finally(() => clearTimeout(timeoutId));
}
}
//# sourceMappingURL=http-client.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"http-client.js","sourceRoot":"","sources":["../../../src/lib/http-client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAA;AACjD,OAAO,EAAE,KAAK,IAAI,YAAY,EAAE,MAAM,SAAS,CAAA;AAoE/C;;GAEG;AACH,MAAM,OAAO,eAAe;IAE1B,YAAY,OAAqB;QAC/B,IAAI,CAAC,MAAM,GAAG,OAAO,IAAI,YAAY,CAAA;IACvC,CAAC;IACD,KAAK,CAAC,WAAW,CAAC,OAA0B;QAC1C,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,uBAAuB,CACjD,OAAO,CAAC,kBAAkB,CAC3B,CAAA;QAED,MAAM,WAAW,GAAG;YAClB,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,MAAM,EAAE,OAAO,CAAC,MAAM;YACtB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC;YAClC,MAAM,EAAE,MAAM;SACf,CAAA;QAED,OAAO,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,WAAW,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CACxD,YAAY,CAAC,SAAS,CAAC,CACxB,CAAA;IACH,CAAC;CACF"}

View File

@@ -0,0 +1,2 @@
export { v4 as uuid } from '@lukeed/uuid';
//# sourceMappingURL=uuid.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"uuid.js","sourceRoot":"","sources":["../../../src/lib/uuid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,EAAE,IAAI,IAAI,EAAE,MAAM,cAAc,CAAA"}

View File

@@ -0,0 +1,51 @@
import { uuid } from '../../lib/uuid';
const MAX_EVENT_SIZE_IN_KB = 32;
const MAX_BATCH_SIZE_IN_KB = 480; // (500 KB is the limit, leaving some padding)
export class ContextBatch {
constructor(maxEventCount) {
this.id = uuid();
this.items = [];
this.sizeInBytes = 0;
this.maxEventCount = Math.max(1, maxEventCount);
}
tryAdd(item) {
if (this.length === this.maxEventCount)
return {
success: false,
message: `Event limit of ${this.maxEventCount} has been exceeded.`,
};
const eventSize = this.calculateSize(item.context);
if (eventSize > MAX_EVENT_SIZE_IN_KB * 1024) {
return {
success: false,
message: `Event exceeds maximum event size of ${MAX_EVENT_SIZE_IN_KB} KB`,
};
}
if (this.sizeInBytes + eventSize > MAX_BATCH_SIZE_IN_KB * 1024) {
return {
success: false,
message: `Event has caused batch size to exceed ${MAX_BATCH_SIZE_IN_KB} KB`,
};
}
this.items.push(item);
this.sizeInBytes += eventSize;
return { success: true };
}
get length() {
return this.items.length;
}
calculateSize(ctx) {
return encodeURI(JSON.stringify(ctx.event)).split(/%..|i/).length;
}
getEvents() {
const events = this.items.map(({ context }) => context.event);
return events;
}
getContexts() {
return this.items.map((item) => item.context);
}
resolveEvents() {
this.items.forEach(({ resolver, context }) => resolver(context));
}
}
//# sourceMappingURL=context-batch.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"context-batch.js","sourceRoot":"","sources":["../../../../src/plugins/segmentio/context-batch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAA;AAIrC,MAAM,oBAAoB,GAAG,EAAE,CAAA;AAC/B,MAAM,oBAAoB,GAAG,GAAG,CAAA,CAAC,+CAA+C;AAOhF,MAAM,OAAO,YAAY;IAMvB,YAAY,aAAqB;QAL1B,OAAE,GAAG,IAAI,EAAE,CAAA;QACV,UAAK,GAAkB,EAAE,CAAA;QACzB,gBAAW,GAAG,CAAC,CAAA;QAIrB,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,CAAC,CAAA;IACjD,CAAC;IACM,MAAM,CACX,IAAiB;QAEjB,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,aAAa;YACpC,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,kBAAkB,IAAI,CAAC,aAAa,qBAAqB;aACnE,CAAA;QAEH,MAAM,SAAS,GAAG,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;QAClD,IAAI,SAAS,GAAG,oBAAoB,GAAG,IAAI,EAAE;YAC3C,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,uCAAuC,oBAAoB,KAAK;aAC1E,CAAA;SACF;QAED,IAAI,IAAI,CAAC,WAAW,GAAG,SAAS,GAAG,oBAAoB,GAAG,IAAI,EAAE;YAC9D,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,OAAO,EAAE,yCAAyC,oBAAoB,KAAK;aAC5E,CAAA;SACF;QAED,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACrB,IAAI,CAAC,WAAW,IAAI,SAAS,CAAA;QAC7B,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAA;IAC1B,CAAC;IAED,IAAI,MAAM;QACR,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAA;IAC1B,CAAC;IAEO,aAAa,CAAC,GAAY;QAChC,OAAO,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,CAAA;IACnE,CAAC;IAED,SAAS;QACP,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAC7D,OAAO,MAAM,CAAA;IACf,CAAC;IAED,WAAW;QACT,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC/C,CAAC;IAED,aAAa;QACX,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;IAClE,CAAC;CACF"}

View File

@@ -0,0 +1,40 @@
import { Publisher } from './publisher';
import { version } from '../../generated/version';
import { detectRuntime } from '../../lib/env';
function normalizeEvent(ctx) {
ctx.updateEvent('context.library.name', '@segment/analytics-node');
ctx.updateEvent('context.library.version', version);
const runtime = detectRuntime();
if (runtime === 'node') {
// eslint-disable-next-line no-restricted-globals
ctx.updateEvent('_metadata.nodeVersion', process.version);
}
ctx.updateEvent('_metadata.jsRuntime', runtime);
}
export function createNodePlugin(publisher) {
function action(ctx) {
normalizeEvent(ctx);
return publisher.enqueue(ctx);
}
return {
name: 'Segment.io',
type: 'destination',
version: '1.0.0',
isLoaded: () => true,
load: () => Promise.resolve(),
alias: action,
group: action,
identify: action,
page: action,
screen: action,
track: action,
};
}
export const createConfiguredNodePlugin = (props, emitter) => {
const publisher = new Publisher(props, emitter);
return {
publisher: publisher,
plugin: createNodePlugin(publisher),
};
};
//# sourceMappingURL=index.js.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/plugins/segmentio/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAkB,MAAM,aAAa,CAAA;AACvD,OAAO,EAAE,OAAO,EAAE,MAAM,yBAAyB,CAAA;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAK7C,SAAS,cAAc,CAAC,GAAY;IAClC,GAAG,CAAC,WAAW,CAAC,sBAAsB,EAAE,yBAAyB,CAAC,CAAA;IAClE,GAAG,CAAC,WAAW,CAAC,yBAAyB,EAAE,OAAO,CAAC,CAAA;IACnD,MAAM,OAAO,GAAG,aAAa,EAAE,CAAA;IAC/B,IAAI,OAAO,KAAK,MAAM,EAAE;QACtB,iDAAiD;QACjD,GAAG,CAAC,WAAW,CAAC,uBAAuB,EAAE,OAAO,CAAC,OAAO,CAAC,CAAA;KAC1D;IACD,GAAG,CAAC,WAAW,CAAC,qBAAqB,EAAE,OAAO,CAAC,CAAA;AACjD,CAAC;AAmBD,MAAM,UAAU,gBAAgB,CAAC,SAAoB;IACnD,SAAS,MAAM,CAAC,GAAY;QAC1B,cAAc,CAAC,GAAG,CAAC,CAAA;QACnB,OAAO,SAAS,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IAC/B,CAAC;IAED,OAAO;QACL,IAAI,EAAE,YAAY;QAClB,IAAI,EAAE,aAAa;QACnB,OAAO,EAAE,OAAO;QAChB,QAAQ,EAAE,GAAG,EAAE,CAAC,IAAI;QACpB,IAAI,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE;QAC7B,KAAK,EAAE,MAAM;QACb,KAAK,EAAE,MAAM;QACb,QAAQ,EAAE,MAAM;QAChB,IAAI,EAAE,MAAM;QACZ,MAAM,EAAE,MAAM;QACd,KAAK,EAAE,MAAM;KACd,CAAA;AACH,CAAC;AAED,MAAM,CAAC,MAAM,0BAA0B,GAAG,CACxC,KAA+B,EAC/B,OAAoB,EACpB,EAAE;IACF,MAAM,SAAS,GAAG,IAAI,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,CAAA;IAC/C,OAAO;QACL,SAAS,EAAE,SAAS;QACpB,MAAM,EAAE,gBAAgB,CAAC,SAAS,CAAC;KACpC,CAAA;AACH,CAAC,CAAA"}

View File

@@ -0,0 +1,187 @@
import { backoff } from '@segment/analytics-core';
import { tryCreateFormattedUrl } from '../../lib/create-url';
import { createDeferred } from '@segment/analytics-generic-utils';
import { ContextBatch } from './context-batch';
import { b64encode } from '../../lib/base-64-encode';
function sleep(timeoutInMs) {
return new Promise((resolve) => setTimeout(resolve, timeoutInMs));
}
function noop() { }
/**
* The Publisher is responsible for batching events and sending them to the Segment API.
*/
export class Publisher {
constructor({ host, path, maxRetries, flushAt, flushInterval, writeKey, httpRequestTimeout, httpClient, disable, }, emitter) {
this._emitter = emitter;
this._maxRetries = maxRetries;
this._flushAt = Math.max(flushAt, 1);
this._flushInterval = flushInterval;
this._auth = b64encode(`${writeKey}:`);
this._url = tryCreateFormattedUrl(host ?? 'https://api.segment.io', path ?? '/v1/batch');
this._httpRequestTimeout = httpRequestTimeout ?? 10000;
this._disable = Boolean(disable);
this._httpClient = httpClient;
}
createBatch() {
this.pendingFlushTimeout && clearTimeout(this.pendingFlushTimeout);
const batch = new ContextBatch(this._flushAt);
this._batch = batch;
this.pendingFlushTimeout = setTimeout(() => {
if (batch === this._batch) {
this._batch = undefined;
}
this.pendingFlushTimeout = undefined;
if (batch.length) {
this.send(batch).catch(noop);
}
}, this._flushInterval);
return batch;
}
clearBatch() {
this.pendingFlushTimeout && clearTimeout(this.pendingFlushTimeout);
this._batch = undefined;
}
flush(pendingItemsCount) {
if (!pendingItemsCount) {
// if number of pending items is 0, there is nothing to flush
return;
}
this._flushPendingItemsCount = pendingItemsCount;
// if batch is empty, there's nothing to flush, and when things come in, enqueue will handle them.
if (!this._batch)
return;
// the number of globally pending items will always be larger or the same as batch size.
// Any mismatch is because some globally pending items are in plugins.
const isExpectingNoMoreItems = this._batch.length === pendingItemsCount;
if (isExpectingNoMoreItems) {
this.send(this._batch).catch(noop);
this.clearBatch();
}
}
/**
* Enqueues the context for future delivery.
* @param ctx - Context containing a Segment event.
* @returns a promise that resolves with the context after the event has been delivered.
*/
enqueue(ctx) {
const batch = this._batch ?? this.createBatch();
const { promise: ctxPromise, resolve } = createDeferred();
const pendingItem = {
context: ctx,
resolver: resolve,
};
/*
The following logic ensures that a batch is never orphaned,
and is always sent before a new batch is created.
Add an event to the existing batch.
Success: Check if batch is full or no more items are expected to come in (i.e. closing). If so, send batch.
Failure: Assume event is too big to fit in current batch - send existing batch.
Add an event to the new batch.
Success: Check if batch is full and send if it is.
Failure: Event exceeds maximum size (it will never fit), fail the event.
*/
const addStatus = batch.tryAdd(pendingItem);
if (addStatus.success) {
const isExpectingNoMoreItems = batch.length === this._flushPendingItemsCount;
const isFull = batch.length === this._flushAt;
if (isFull || isExpectingNoMoreItems) {
this.send(batch).catch(noop);
this.clearBatch();
}
return ctxPromise;
}
// If the new item causes the maximimum event size to be exceeded, send the current batch and create a new one.
if (batch.length) {
this.send(batch).catch(noop);
this.clearBatch();
}
const fallbackBatch = this.createBatch();
const fbAddStatus = fallbackBatch.tryAdd(pendingItem);
if (fbAddStatus.success) {
const isExpectingNoMoreItems = fallbackBatch.length === this._flushPendingItemsCount;
if (isExpectingNoMoreItems) {
this.send(fallbackBatch).catch(noop);
this.clearBatch();
}
return ctxPromise;
}
else {
// this should only occur if max event size is exceeded
ctx.setFailedDelivery({
reason: new Error(fbAddStatus.message),
});
return Promise.resolve(ctx);
}
}
async send(batch) {
if (this._flushPendingItemsCount) {
this._flushPendingItemsCount -= batch.length;
}
const events = batch.getEvents();
const maxAttempts = this._maxRetries + 1;
let currentAttempt = 0;
while (currentAttempt < maxAttempts) {
currentAttempt++;
let failureReason;
try {
if (this._disable) {
return batch.resolveEvents();
}
const request = {
url: this._url,
method: 'POST',
headers: {
'Content-Type': 'application/json',
Authorization: `Basic ${this._auth}`,
'User-Agent': 'analytics-node-next/latest',
},
data: { batch: events, sentAt: new Date() },
httpRequestTimeout: this._httpRequestTimeout,
};
this._emitter.emit('http_request', {
body: request.data,
method: request.method,
url: request.url,
headers: request.headers,
});
const response = await this._httpClient.makeRequest(request);
if (response.status >= 200 && response.status < 300) {
// Successfully sent events, so exit!
batch.resolveEvents();
return;
}
else if (response.status === 400) {
// https://segment.com/docs/connections/sources/catalog/libraries/server/http-api/#max-request-size
// Request either malformed or size exceeded - don't retry.
resolveFailedBatch(batch, new Error(`[${response.status}] ${response.statusText}`));
return;
}
else {
// Treat other errors as transient and retry.
failureReason = new Error(`[${response.status}] ${response.statusText}`);
}
}
catch (err) {
// Network errors get thrown, retry them.
failureReason = err;
}
// Final attempt failed, update context and resolve events.
if (currentAttempt === maxAttempts) {
resolveFailedBatch(batch, failureReason);
return;
}
// Retry after attempt-based backoff.
await sleep(backoff({
attempt: currentAttempt,
minTimeout: 25,
maxTimeout: 1000,
}));
}
}
}
function resolveFailedBatch(batch, reason) {
batch.getContexts().forEach((ctx) => ctx.setFailedDelivery({ reason }));
batch.resolveEvents();
}
//# sourceMappingURL=publisher.js.map

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,73 @@
import { CoreAnalytics } from '@segment/analytics-core';
import { AnalyticsSettings } from './settings';
import { Callback } from './dispatch-emit';
import { NodeEmitter } from './emitter';
import { AliasParams, GroupParams, IdentifyParams, PageParams, TrackParams, Plugin, FlushParams, CloseAndFlushParams } from './types';
export declare class Analytics extends NodeEmitter implements CoreAnalytics {
private readonly _eventFactory;
private _isClosed;
private _pendingEvents;
private readonly _closeAndFlushDefaultTimeout;
private readonly _publisher;
private _isFlushing;
private readonly _queue;
ready: Promise<void>;
constructor(settings: AnalyticsSettings);
get VERSION(): string;
/**
* 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, }?: CloseAndFlushParams): Promise<void>;
/**
* 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.
*/
flush({ timeout, close, }?: FlushParams): Promise<void>;
private _dispatch;
/**
* Combines two unassociated user identities.
* @link https://segment.com/docs/connections/sources/catalog/libraries/server/node/#alias
*/
alias({ userId, previousId, context, timestamp, integrations }: AliasParams, callback?: Callback): void;
/**
* 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, }: GroupParams, callback?: Callback): void;
/**
* 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, }: IdentifyParams, callback?: Callback): void;
/**
* 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, }: PageParams, callback?: Callback): void;
/**
* 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, }: PageParams, callback?: Callback): void;
/**
* 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, }: TrackParams, callback?: Callback): void;
/**
* Registers one or more plugins to augment Analytics functionality.
* @param plugins
*/
register(...plugins: Plugin[]): Promise<void>;
/**
* Deregisters one or more plugins based on their names.
* @param pluginNames - The names of one or more plugins to deregister.
*/
deregister(...pluginNames: string[]): Promise<void>;
}
//# sourceMappingURL=analytics-node.d.ts.map

View File

@@ -0,0 +1 @@
{"version":3,"file":"analytics-node.d.ts","sourceRoot":"","sources":["../../../src/app/analytics-node.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAqB,MAAM,yBAAyB,CAAA;AAC1E,OAAO,EAAE,iBAAiB,EAAoB,MAAM,YAAY,CAAA;AAIhE,OAAO,EAAE,QAAQ,EAAmB,MAAM,iBAAiB,CAAA;AAC3D,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAA;AACvC,OAAO,EACL,WAAW,EACX,WAAW,EACX,cAAc,EACd,UAAU,EACV,WAAW,EACX,MAAM,EAEN,WAAW,EACX,mBAAmB,EACpB,MAAM,SAAS,CAAA;AAKhB,qBAAa,SAAU,SAAQ,WAAY,YAAW,aAAa;IACjE,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAkB;IAChD,OAAO,CAAC,SAAS,CAAQ;IACzB,OAAO,CAAC,cAAc,CAAI;IAC1B,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAQ;IACrD,OAAO,CAAC,QAAQ,CAAC,UAAU,CAEb;IAEd,OAAO,CAAC,WAAW,CAAQ;IAE3B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAgB;IAEvC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAA;gBAER,QAAQ,EAAE,iBAAiB;IAoCvC,IAAI,OAAO,WAEV;IAED;;;;OAIG;IACI,aAAa,CAAC,EACnB,OAA2C,GAC5C,GAAE,mBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC;IAI3C;;;;OAIG;IACU,KAAK,CAAC,EACjB,OAAO,EACP,KAAa,GACd,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BnC,OAAO,CAAC,SAAS;IAmBjB;;;OAGG;IACH,KAAK,CACH,EAAE,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,EAAE,WAAW,EACrE,QAAQ,CAAC,EAAE,QAAQ,GAClB,IAAI;IASP;;;OAGG;IACH,KAAK,CACH,EACE,SAAS,EACT,OAAO,EACP,MAAM,EACN,WAAW,EACX,MAAW,EACX,OAAO,EACP,YAAY,GACb,EAAE,WAAW,EACd,QAAQ,CAAC,EAAE,QAAQ,GAClB,IAAI;IAYP;;;OAGG;IACH,QAAQ,CACN,EACE,MAAM,EACN,WAAW,EACX,MAAW,EACX,OAAO,EACP,SAAS,EACT,YAAY,GACb,EAAE,cAAc,EACjB,QAAQ,CAAC,EAAE,QAAQ,GAClB,IAAI;IAWP;;;OAGG;IACH,IAAI,CACF,EACE,MAAM,EACN,WAAW,EACX,QAAQ,EACR,IAAI,EACJ,UAAU,EACV,OAAO,EACP,SAAS,EACT,YAAY,GACb,EAAE,UAAU,EACb,QAAQ,CAAC,EAAE,QAAQ,GAClB,IAAI;IAUP;;;;;OAKG;IACH,MAAM,CACJ,EACE,MAAM,EACN,WAAW,EACX,QAAQ,EACR,IAAI,EACJ,UAAU,EACV,OAAO,EACP,SAAS,EACT,YAAY,GACb,EAAE,UAAU,EACb,QAAQ,CAAC,EAAE,QAAQ,GAClB,IAAI;IAWP;;;OAGG;IACH,KAAK,CACH,EACE,MAAM,EACN,WAAW,EACX,KAAK,EACL,UAAU,EACV,OAAO,EACP,SAAS,EACT,YAAY,GACb,EAAE,WAAW,EACd,QAAQ,CAAC,EAAE,QAAQ,GAClB,IAAI;IAYP;;;OAGG;IACH,QAAQ,CAAC,GAAG,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAe7C;;;OAGG;IACG,UAAU,CAAC,GAAG,WAAW,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;CAe1D"}

Some files were not shown because too many files have changed in this diff Show More