Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

coveo.analytics

Package Overview
Dependencies
Maintainers
16
Versions
259
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

coveo.analytics - npm Package Compare versions

Comparing version 2.25.3 to 2.26.1

dist/definitions/plugins/link.d.ts

4

dist/definitions/client/analytics.d.ts

@@ -52,2 +52,3 @@ import { AnyEventResponse, ClickEventRequest, ClickEventResponse, CustomEventRequest, CustomEventResponse, EventType, HealthResponse, SearchEventRequest, SearchEventResponse, ViewEventRequest, ViewEventResponse, VisitResponse, VariableArgumentsPayload, PreparedClickEventRequest, PreparedCustomEventRequest, PreparedViewEventRequest, PreparedSearchEventRequest } from '../events';

getCurrentVisitorId?(): Promise<string>;
setAcceptedLinkReferrers?(hosts: string[]): void;
}

@@ -69,2 +70,3 @@ export interface BufferedRequest {

private options;
private acceptedLinkReferrers;
constructor(opts: Partial<ClientOptions>);

@@ -81,2 +83,3 @@ private initRuntime;

set currentVisitorId(visitorId: string);
private extractClientIdFromLink;
resolveParameters(eventType: EventType | string, ...payload: VariableArgumentsPayload): Promise<VariableArgumentsPayload>;

@@ -103,2 +106,3 @@ resolvePayloadForParameters(eventType: EventType | string, parameters: any): Promise<any>;

addEventTypeMapping(eventType: string, eventConfig: EventTypeConfig): void;
setAcceptedLinkReferrers(hosts: string[]): void;
private parseVariableArgumentsPayload;

@@ -105,0 +109,0 @@ private isKeyAllowedEmpty;

8

dist/definitions/coveoua/plugins.d.ts

@@ -1,6 +0,2 @@

import { PluginClass, PluginOptions, BasePlugin } from '../plugins/BasePlugin';
export declare type UAPluginOptions = any[];
export declare type Plugin = BasePlugin & {
[propName: string]: unknown;
};
import { PluginClass, PluginOptions } from '../plugins/BasePlugin';
export declare class Plugins {

@@ -13,3 +9,3 @@ static readonly DefaultPlugins: string[];

clearRequired(): void;
execute(name: string, fn: string, ...pluginOptions: UAPluginOptions): any;
execute(name: string, fn: string, ...args: any[]): any;
}

@@ -24,3 +24,3 @@ import { AnyEventResponse, SendEventArguments } from '../events';

require(name: string, options: Omit<PluginOptions, 'client'>): void;
callPlugin(pluginName: string, fn: string, ...args: any): void;
callPlugin(pluginName: string, fn: string, ...args: any): any;
reset(): void;

@@ -27,0 +27,0 @@ version(): string;

@@ -6,3 +6,3 @@ import { AnalyticsClient } from '../client/analytics';

};
export declare type PluginClass = typeof BasePlugin & PluginWithId;
export declare type PluginClass = typeof Plugin & PluginWithId;
export declare const BasePluginEventTypes: {

@@ -16,5 +16,9 @@ pageview: string;

};
export declare abstract class BasePlugin {
export declare abstract class Plugin {
protected client: AnalyticsClient;
protected uuidGenerator: typeof uuidv4;
constructor({ client, uuidGenerator }: PluginOptions);
abstract getApi(name: string): any;
}
export declare abstract class BasePlugin extends Plugin {
protected action?: string;

@@ -32,2 +36,3 @@ protected actionData: {

protected abstract clearPluginData(): void;
getApi(name: string): Function | null;
setAction(action: string, options?: any): void;

@@ -41,3 +46,3 @@ clearData(): void;

};
updateLocationInformation(eventType: string, payload: any): void;
protected updateLocationInformation(eventType: string, payload: any): void;
getDefaultContextInformation(eventType: string): {

@@ -44,0 +49,0 @@ title: string;

@@ -50,2 +50,3 @@ import { BasePlugin, PluginClass, PluginOptions } from './BasePlugin';

constructor({ client, uuidGenerator }: PluginOptions);
getApi(name: string): Function | null;
protected addHooks(): void;

@@ -52,0 +53,0 @@ addProduct(product: Product): void;

@@ -22,2 +22,3 @@ import { BasePlugin, PluginClass, PluginOptions } from './BasePlugin';

constructor({ client, uuidGenerator }: PluginOptions);
getApi(name: string): Function | null;
protected addHooks(): void;

@@ -24,0 +25,0 @@ setTicket(ticket: Ticket): void;

@@ -1,6 +0,2 @@

import { PluginClass, PluginOptions, BasePlugin } from '../plugins/BasePlugin';
export declare type UAPluginOptions = any[];
export declare type Plugin = BasePlugin & {
[propName: string]: unknown;
};
import { PluginClass, PluginOptions } from '../plugins/BasePlugin';
export declare class Plugins {

@@ -13,3 +9,3 @@ static readonly DefaultPlugins: string[];

clearRequired(): void;
execute(name: string, fn: string, ...pluginOptions: UAPluginOptions): any;
execute(name: string, fn: string, ...args: any[]): any;
}

@@ -24,3 +24,3 @@ import { AnyEventResponse, SendEventArguments } from '../events';

require(name: string, options: Omit<PluginOptions, 'client'>): void;
callPlugin(pluginName: string, fn: string, ...args: any): void;
callPlugin(pluginName: string, fn: string, ...args: any): any;
reset(): void;

@@ -27,0 +27,0 @@ version(): string;

@@ -50,2 +50,3 @@ import { BasePlugin, PluginClass, PluginOptions } from './BasePlugin';

constructor({ client, uuidGenerator }: PluginOptions);
getApi(name: string): Function | null;
protected addHooks(): void;

@@ -52,0 +53,0 @@ addProduct(product: Product): void;

@@ -1,1 +0,1 @@

export declare const libVersion = "2.25.3";
export declare const libVersion = "2.26.1";
{
"name": "coveo.analytics",
"version": "2.25.3",
"version": "2.26.1",
"description": "📈 Coveo analytics client (node and browser compatible) ",

@@ -5,0 +5,0 @@ "main": "dist/library.js",

@@ -133,2 +133,29 @@ # ![coveo.analytics](./assets/coveo.analytics.js.png)

## Linking clientIds across different domains using a URL parameter
To help track a visitor across different domains, the library offers functionality to initialize a clientId from a URL query parameter. The query parameter is named `cvo_cid` with value `<clientid>.<timestamp>`. The clientId is encoded without dashes and the timestamp is encoded in seconds since epoch, both to save space in the url. Both are separated by a period. A sample parameter could be `cvo_cid=c0b48880743e484f8044d7c37910c55b.1676298678`. This query parameter will be picked up by the target page if the following conditions hold:
- The target page has a equal or greater version of coveo.analytics.js loaded.
- The current URL contains a `cvo_cid` query parameter
- The parameter contains a valid uuid.
- The parameter contains a valid timestamp, and that timestamp is no more than 120 seconds in the past.
- The receiving page has specified a list of valid referrers and the current referrer host matches that list, using wildcards, including ports, specified using `coveoua('link:acceptFrom', [<referrers>])`.
Given that you want to ensure the clientId remains consistent when you navigate from a source page on http://foo.com/index.html to a target page http://bar.com/index.html, the following steps are needed.
1. Ensure coveo.analytics.js is loaded on the source page.
2. Modify the source page such that whenever a link to the target page is clicked, its `href` is replaced by `coveoua('link:decorate', 'http://bar.com/index.html')`. For example, by creating an onClick event listener on the element or on the page. It's important that the decorated link is generated at the moment the link is clicked, as it will be valid only for a short time after generation.
```html
<script>
async function decorate(element) {
element.href = await coveoua('link:decorate', element.href);
}
</script>
<a onclick="decorate(this)" href="http://bar.com/index.html">Navigate</a>>
```
3. Ensure coveo.analytics.js is loaded on the target page.
4. Ensure that the target page allows reception of links from the source page by adding `coveoua('link:acceptFrom', ['foo.com']);` immediately after script load.
# Developer information

@@ -216,2 +243,6 @@

## Conformance
Chrome, Firefox, Safari, Edge. IE11 support on a reasonable-effort basis.
## Contributing

@@ -218,0 +249,0 @@

@@ -10,2 +10,4 @@ import {EventType, ViewEventRequest, DefaultEventResponse} from '../events';

import {Cookie} from '../cookieutils';
import {v4 as uuidv4} from 'uuid';
import {CoveoLinkParam} from '../plugins/link';

@@ -487,1 +489,121 @@ const aVisitorId = '123';

});
describe('clientId from link', () => {
// note: referrer is set as http://somewhere.over/thereferrer in setup.js
let client: CoveoAnalyticsClient;
const forcedUUID: string = 'c0b48880-743e-484f-8044-d7c37910c55b';
function navigateTo(url: string) {
// @ts-ignore
delete window.location;
// @ts-ignore
window.location = new URL(url);
}
beforeEach(() => {
client = new CoveoAnalyticsClient({});
// need to clear existing clientIds
client.clear();
jest.spyOn(doNotTrack, 'doNotTrack').mockImplementation(() => false);
});
it('will extract a clientId from a query param if the referrer matches all and it is not expired', async () => {
client.setAcceptedLinkReferrers(['*']);
const linkString = new CoveoLinkParam(forcedUUID, Date.now());
navigateTo('http://my.receivingdomain.com/?cvo_cid=' + linkString.toString());
expect(await client.getCurrentVisitorId()).toBe(forcedUUID);
});
it('will extract a clientId from a query param if the referrer matches the current referrer exactly and it is not expired', async () => {
client.setAcceptedLinkReferrers(['somewhere.over']);
const linkString = new CoveoLinkParam(forcedUUID, Date.now());
navigateTo('http://my.receivingdomain.com/?cvo_cid=' + linkString.toString());
expect(await client.getCurrentVisitorId()).toBe(forcedUUID);
});
it('will extract a clientId from a query param if the referrer matches the current referrer with wildcard and it is not expired', async () => {
client.setAcceptedLinkReferrers(['*.over']);
const linkString = new CoveoLinkParam(forcedUUID, Date.now());
navigateTo('http://my.receivingdomain.com/?cvo_cid=' + linkString.toString());
expect(await client.getCurrentVisitorId()).toBe(forcedUUID);
});
it('will extract a clientId from a query param if one of the referrer matches the current referrer and it is not expired', async () => {
client.setAcceptedLinkReferrers(['*.mydomain.com', '*.over']);
const linkString = new CoveoLinkParam(forcedUUID, Date.now());
navigateTo('http://my.receivingdomain.com/?cvo_cid=' + linkString.toString());
expect(await client.getCurrentVisitorId()).toBe(forcedUUID);
});
it('will not extract a clientId from a query param if the referrer matches and it is expired', async () => {
client.setAcceptedLinkReferrers(['*']);
const linkString = new CoveoLinkParam(forcedUUID, Date.now() - 180000);
navigateTo('http://my.receivingdomain.com/?cvo_cid=' + linkString.toString());
expect(await client.getCurrentVisitorId()).not.toBe(null);
expect(await client.getCurrentVisitorId()).toBe(aVisitorId);
});
it('will not extract a clientId from a query param if there is no accept list specified', async () => {
const linkString = new CoveoLinkParam(forcedUUID, Date.now());
navigateTo('http://my.receivingdomain.com/?cvo_cid=' + linkString.toString());
expect(await client.getCurrentVisitorId()).not.toBe(null);
expect(await client.getCurrentVisitorId()).toBe(aVisitorId);
});
it('will not extract a clientId from a query param if there is an empty accept list', async () => {
client.setAcceptedLinkReferrers([]);
const linkString = new CoveoLinkParam(forcedUUID, Date.now());
navigateTo('http://my.receivingdomain.com/?cvo_cid=' + linkString.toString());
expect(await client.getCurrentVisitorId()).not.toBe(null);
expect(await client.getCurrentVisitorId()).toBe(aVisitorId);
});
it('will not extract a clientId from a query param if the referrer list does not match', async () => {
client.setAcceptedLinkReferrers(['*.mydomain.com']);
const linkString = new CoveoLinkParam(forcedUUID, Date.now());
navigateTo('http://my.receivingdomain.com/?cvo_cid=' + linkString.toString());
expect(await client.getCurrentVisitorId()).not.toBe(null);
expect(await client.getCurrentVisitorId()).toBe(aVisitorId);
});
it('will not extract a clientId from a query param if the referrer list does not match the exact port', async () => {
client.setAcceptedLinkReferrers(['*.over:9000']);
const linkString = new CoveoLinkParam(forcedUUID, Date.now());
navigateTo('http://my.receivingdomain.com/?cvo_cid=' + linkString.toString());
expect(await client.getCurrentVisitorId()).not.toBe(null);
expect(await client.getCurrentVisitorId()).toBe(aVisitorId);
});
it('will not extract a clientId from a query param if the multi referrer list does not match', async () => {
client.setAcceptedLinkReferrers(['*.mydomain.com', 'www.example.com']);
const linkString = new CoveoLinkParam(forcedUUID, Date.now());
navigateTo('http://my.receivingdomain.com/?cvo_cid=' + linkString.toString());
expect(await client.getCurrentVisitorId()).not.toBe(null);
expect(await client.getCurrentVisitorId()).toBe(aVisitorId);
});
it('will not extract a clientId from a query param if it is not a UUID', async () => {
client.setAcceptedLinkReferrers(['*']);
navigateTo('http://my.receivingdomain.com/?cvo_cid=notauuid.' + Math.floor(Date.now() / 1000));
expect(await client.getCurrentVisitorId()).not.toBe(null);
expect(await client.getCurrentVisitorId()).toBe(aVisitorId);
});
it('will not extract a clientId from a query param if DNT is enabled', async () => {
client.setAcceptedLinkReferrers(['*']);
jest.spyOn(doNotTrack, 'doNotTrack').mockImplementation(() => true);
const linkString = new CoveoLinkParam(forcedUUID, Date.now());
navigateTo('http://my.receivingdomain.com/?cvo_cid=' + linkString.toString());
expect(await client.getCurrentVisitorId()).not.toBe(null);
expect(await client.getCurrentVisitorId()).toBe(aVisitorId);
});
it('will throw when specifying invalid hosts list', async () => {
//@ts-ignore
expect(() => client.setAcceptedLinkReferrers('*')).toThrow('Parameter should be an array of domain strings');
//@ts-ignore
expect(() => client.setAcceptedLinkReferrers({})).toThrow('Parameter should be an array of domain strings');
//@ts-ignore
expect(() => client.setAcceptedLinkReferrers([{}])).toThrow('Parameter should be an array of domain strings');
});
});

@@ -27,2 +27,3 @@ import {

import {libVersion} from '../version';
import {CoveoLinkParam} from '../plugins/link';
import {

@@ -109,2 +110,3 @@ convertKeysToMeasurementProtocol,

getCurrentVisitorId?(): Promise<string>; // TODO: v3 make required
setAcceptedLinkReferrers?(hosts: string[]): void;
}

@@ -151,2 +153,3 @@

private options: ClientOptions;
private acceptedLinkReferrers: string[] = [];

@@ -202,3 +205,7 @@ constructor(opts: Partial<ClientOptions>) {

try {
return (await this.storage.getItem('visitorId')) || uuidv4();
return (
this.extractClientIdFromLink(window.location.href) ||
(await this.storage.getItem('visitorId')) ||
uuidv4()
);
} catch (err) {

@@ -265,2 +272,22 @@ console.log(

private extractClientIdFromLink(urlString: string): string | null {
if (doNotTrack()) {
return null;
}
try {
const linkParam: string | null = new URL(urlString).searchParams.get(CoveoLinkParam.cvo_cid);
if (linkParam == null) {
return null;
}
const linker: CoveoLinkParam | null = CoveoLinkParam.fromString(linkParam);
if (!linker || !hasDocument() || !linker.validate(document.referrer, this.acceptedLinkReferrers)) {
return null;
}
return linker.clientId;
} catch (error) {
// Ignore any parsing errors
}
return null;
}
async resolveParameters(eventType: EventType | string, ...payload: VariableArgumentsPayload) {

@@ -461,2 +488,7 @@ const {

setAcceptedLinkReferrers(hosts: string[]): void {
if (Array.isArray(hosts) && hosts.every((host) => typeof host == 'string')) this.acceptedLinkReferrers = hosts;
else throw Error('Parameter should be an array of domain strings');
}
private parseVariableArgumentsPayload(fieldsOrder: string[], payload: VariableArgumentsPayload) {

@@ -463,0 +495,0 @@ const parsedArguments: {[name: string]: any} = {};

@@ -1,13 +0,12 @@

import {PluginClass, PluginOptions, BasePlugin} from '../plugins/BasePlugin';
import {PluginClass, PluginOptions, BasePlugin, Plugin} from '../plugins/BasePlugin';
import {EC} from '../plugins/ec';
import {Link} from '../plugins/link';
import {SVC} from '../plugins/svc';
export type UAPluginOptions = any[];
export type Plugin = BasePlugin & {[propName: string]: unknown};
export class Plugins {
public static readonly DefaultPlugins: string[] = [EC.Id, SVC.Id];
public static readonly DefaultPlugins: string[] = [EC.Id, SVC.Id, Link.Id];
private registeredPluginsMap: Record<string, PluginClass> = {
[EC.Id]: EC,
[SVC.Id]: SVC,
[Link.Id]: Link,
};

@@ -34,3 +33,3 @@ private requiredPlugins: Record<string, BasePlugin> = {};

execute(name: string, fn: string, ...pluginOptions: UAPluginOptions) {
execute(name: string, fn: string, ...args: any[]): any {
const plugin = this.requiredPlugins[name] as Plugin;

@@ -40,3 +39,3 @@ if (!plugin) {

}
const actionFunction = plugin[fn];
const actionFunction = plugin.getApi(fn);
if (!actionFunction) {

@@ -48,4 +47,4 @@ throw new Error(`The function "${fn}" does not exist on the plugin "${name}".`);

}
return actionFunction.apply(plugin, pluginOptions);
return actionFunction.apply(plugin, args);
}
}

@@ -22,6 +22,15 @@ import coveoua from './simpleanalytics';

}
public getApi(name: string): Function | null {
switch (name) {
case 'testMethod':
return this.testMethod;
default:
return null;
}
}
testMethod(...args: any[]) {
TestPluginWithSpy.spy(args);
}
someProperty: string = 'foo';
}

@@ -126,6 +135,7 @@

it('uses EC and SVC plugins by default', () => {
it('uses EC, SVC and Link plugins by default', () => {
coveoua('init', 'SOME TOKEN');
expect(() => coveoua('callPlugin', 'ec', 'nosuchfunction')).toThrow(/does not exist/);
expect(() => coveoua('callPlugin', 'svc', 'nosuchfunction')).toThrow(/does not exist/);
expect(() => coveoua('callPlugin', 'link', 'nosuchfunction')).toThrow(/does not exist/);
});

@@ -137,2 +147,3 @@

expect(() => coveoua('callPlugin', 'svc', 'nosuchfunction')).toThrow(/is not required/);
expect(() => coveoua('callPlugin', 'link', 'nosuchfunction')).toThrow(/is not required/);
});

@@ -143,2 +154,3 @@

expect(() => coveoua('callPlugin', 'ec', 'nosuchfunction')).toThrow(/is not required/);
expect(() => coveoua('callPlugin', 'link', 'nosuchfunction')).toThrow(/is not required/);
expect(() => coveoua('callPlugin', 'svc', 'nosuchfunction')).toThrow(/does not exist/);

@@ -158,3 +170,3 @@ });

it(`throw if the initForProxy receive an endpoint that's is not a string`, () => {
it(`throw if the initForProxy receive an endpoint that is not a string`, () => {
expect(() => coveoua('initForProxy', {})).toThrow(

@@ -412,9 +424,2 @@ `You must pass a string as the endpoint parameter when you call 'initForProxy'`

});
it('throws when a namespaced action is called and that this action is not a function on the plugin', () => {
coveoua('provide', 'test', TestPluginWithSpy);
coveoua('init', 'SOME TOKEN', {plugins: ['test']});
expect(() => coveoua('callPlugin', 'test', 'someProperty')).toThrow(/is not a function/);
});
});

@@ -421,0 +426,0 @@

@@ -132,4 +132,4 @@ import {AnyEventResponse, EventType, SendEventArguments, VariableArgumentsPayload} from '../events';

callPlugin(pluginName: string, fn: string, ...args: any): void {
this.plugins.execute(pluginName, fn, ...args);
callPlugin(pluginName: string, fn: string, ...args: any): any {
return this.plugins.execute(pluginName, fn, ...args);
}

@@ -136,0 +136,0 @@

@@ -10,4 +10,3 @@ import {AnalyticsClient} from '../client/analytics';

export type PluginClass = typeof BasePlugin & PluginWithId;
export type PluginClass = typeof Plugin & PluginWithId;
export const BasePluginEventTypes = {

@@ -20,5 +19,13 @@ pageview: 'pageview',

export abstract class BasePlugin {
export abstract class Plugin {
protected client: AnalyticsClient;
protected uuidGenerator: typeof uuidv4;
constructor({client, uuidGenerator = uuidv4}: PluginOptions) {
this.client = client;
this.uuidGenerator = uuidGenerator;
}
public abstract getApi(name: string): any;
}
export abstract class BasePlugin extends Plugin {
protected action?: string;

@@ -33,4 +40,3 @@ protected actionData: {[name: string]: string} = {};

constructor({client, uuidGenerator = uuidv4}: PluginOptions) {
this.client = client;
this.uuidGenerator = uuidGenerator;
super({client, uuidGenerator});
this.pageViewId = uuidGenerator();

@@ -43,6 +49,14 @@ this.nextPageViewId = this.pageViewId;

}
protected abstract addHooks(): void;
protected abstract clearPluginData(): void;
public getApi(name: string): Function | null {
switch (name) {
case 'setAction':
return this.setAction;
default:
return null;
}
}
public setAction(action: string, options?: any) {

@@ -66,3 +80,3 @@ this.action = action;

public updateLocationInformation(eventType: string, payload: any) {
protected updateLocationInformation(eventType: string, payload: any) {
this.updateLocationForNextPageView(eventType, payload);

@@ -69,0 +83,0 @@ }

@@ -74,2 +74,15 @@ import {EventType} from '../events';

public getApi(name: string): Function | null {
const superCall: Function | null = super.getApi(name);
if (superCall !== null) return superCall;
switch (name) {
case 'addProduct':
return this.addProduct;
case 'addImpression':
return this.addImpression;
default:
return null;
}
}
protected addHooks(): void {

@@ -76,0 +89,0 @@ this.addHooksForPageView();

@@ -37,2 +37,13 @@ import {EventType} from '../events';

public getApi(name: string): Function | null {
const superCall: Function | null = super.getApi(name);
if (superCall !== null) return superCall;
switch (name) {
case 'setTicket':
return this.setTicket;
default:
return null;
}
}
protected addHooks(): void {

@@ -39,0 +50,0 @@ this.addHooksForEvent();

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc