This commit is contained in:
NoryiE
2025-02-16 14:12:49 +00:00
parent c6a89e5b35
commit e0aeb9b06e
2737 changed files with 5220 additions and 1039045 deletions

View File

@@ -1,21 +0,0 @@
The MIT License (MIT)
Copyright (c) 2015-present Algolia, Inc.
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.

View File

@@ -1,91 +0,0 @@
# Search Insights
[![Build Status](https://circleci.com/gh/algolia/search-insights.js.svg?style=shield)](https://github.com/algolia/search-insights.js)
[![npm version](https://badge.fury.io/js/search-insights.svg)](https://badge.fury.io/js/search-insights)
Search Insights lets you report click, conversion and view metrics using the [Algolia Insights API](https://www.algolia.com/doc/rest-api/insights/#overview).
## Table of Contents
<!-- toc -->
- [Notices](#notices)
- [Cookie usage](#cookie-usage)
- [Payload validation](#payload-validation)
- [Getting started](#getting-started)
- [Browser](#browser)
- [Node.js](#nodejs)
- [Documentation](#documentation)
- [Contributing](#contributing)
- [License](#license)
<!-- tocstop -->
> **NOTE:** You're looking at the documentation of `search-insights` v2. (_Click [here](https://github.com/algolia/search-insights.js/blob/v1/README.md) for v1.x documentation._)
## Notices
### Cookie usage
v2 introduces a breaking change which is `useCookie` being `false` by default. If it's `false`, `search-insights` doesn't generate anonymous userToken. It means no event will be sent until `setUserToken` is explicitly called.
### Payload validation
Since v2.0.4, search-insights no longer validates event payloads.
You can visit https://algolia.com/events/debugger instead.
---
## Getting started
> We have created dedicated integrations for Google Tag Manager and Segment. If you are using either of these platforms,
> it is recommended to use the dedicated integrations to manage sending events to the [Insights API][insights-api].
>
> - [Google Tag Manager](https://www.algolia.com/doc/guides/sending-events/connectors/google-tag-manager/)
> - [Segment](https://www.algolia.com/doc/guides/sending-events/connectors/segment/)
### Browser
For information on how to set up `search-insights.js` in a browser environment, see our documentation on [Installing and Initializing the Insights Client][insights-js-docs].
We also have documentation for using `search-insights.js` with [InstantSearch][instantsearch] and [Autocomplete][autocomplete].
- For information on using `search-insights.js` with [InstantSearch][instantsearch], see our documentation on [Sending click and conversion events with InstantSearch.js][instantsearch-guide].
- For information on using `search-insights.js` with [Autocomplete][autocomplete], see our documentation on [Sending Algolia Insights events with Autocomplete][autocomplete-guide].
> **NOTE:** If you are using [Require.js](https://requirejs.org/), see our [Note for Require.js users](./docs/requirejs.md).
### Node.js
For information on how to set up `search-insights.js` in a Node.js environment, see our guide on [Installing and Initializing the Insights Client for Node.js](./docs/nodejs.md).
[insights-api]: https://www.algolia.com/doc/rest-api/insights/
[insights-js-docs]: https://www.algolia.com/doc/api-client/methods/insights/#install-the-insights-client
[instantsearch]: https://www.algolia.com/doc/guides/building-search-ui/what-is-instantsearch/js/
[instantsearch-guide]: https://www.algolia.com/doc/guides/building-search-ui/events/js/
[autocomplete]: https://www.algolia.com/doc/ui-libraries/autocomplete/introduction/what-is-autocomplete/
[autocomplete-guide]: https://www.algolia.com/doc/ui-libraries/autocomplete/guides/sending-algolia-insights-events/
## Documentation
Documentation for `search-insights.js` can be found in our main [Algolia Docs](https://algolia.com/docs) website.
For API Client reference information, see the [Insights API Client Documentation](https://www.algolia.com/doc/api-client/methods/insights/).
## Contributing
To run the examples and the code, you need to run two separate commands:
- `yarn dev` runs webpack and the Node.js server
- `yarn build:dev` runs Rollup in watch mode
To release, go on `main` (`git checkout main`) and use:
```sh
yarn run release
```
It will create a pull request for the next release. When it's reviewed, approved and merged, then CircleCI will automatically publish it to npm.
## License
Search Insights is [MIT licensed](LICENSE.md).

View File

@@ -1,3 +0,0 @@
import type { InsightsEvent, InsightsEventConversionSubType, InsightsEventType } from "./types";
export declare function addEventType(eventType: InsightsEventType, params: Array<Omit<InsightsEvent, "eventType">>): InsightsEvent[];
export declare function addEventTypeAndSubtype(eventType: InsightsEventType, eventSubtype: InsightsEventConversionSubType, params: Array<Omit<InsightsEvent, "eventSubtype" | "eventType">>): InsightsEvent[];

View File

@@ -1,3 +0,0 @@
import type AlgoliaAnalytics from "./insights";
export declare const DEFAULT_ALGOLIA_AGENTS: string[];
export declare function addAlgoliaAgent(this: AlgoliaAnalytics, algoliaAgent: string): void;

View File

@@ -1,3 +0,0 @@
import type { InsightsClient } from "./types";
import type { RequestFnType } from "./utils/request";
export declare function createInsightsClient(requestFn: RequestFnType): InsightsClient;

View File

@@ -1,3 +0,0 @@
import type AlgoliaAnalytics from "./insights";
import type { InsightsClient } from "./types";
export declare function getFunctionalInterface(instance: AlgoliaAnalytics): InsightsClient;

View File

@@ -1,2 +0,0 @@
import type AlgoliaAnalytics from "./insights";
export declare function getVersion(this: AlgoliaAnalytics, callback: (version: string) => void): void;

View File

@@ -1,2 +0,0 @@
import type AlgoliaAnalytics from "./insights";
export declare function processQueue(this: AlgoliaAnalytics, globalObject: any): void;

View File

@@ -1,4 +0,0 @@
import type AlgoliaAnalytics from "./insights";
import type { InsightsAdditionalEventParams, InsightsEvent } from "./types";
import type { RequestFnType } from "./utils/request";
export declare function makeSendEvents(requestFn: RequestFnType): (this: AlgoliaAnalytics, eventData: InsightsEvent[], additionalParams?: InsightsAdditionalEventParams) => Promise<boolean> | undefined;

View File

@@ -1,9 +0,0 @@
import type AlgoliaAnalytics from "./insights";
export declare const MONTH: number;
export declare const getCookie: (name: string) => string;
export declare function setAnonymousUserToken(this: AlgoliaAnalytics, inMemory?: boolean): void;
export declare function setUserToken(this: AlgoliaAnalytics, userToken: number | string): number | string;
export declare function getUserToken(this: AlgoliaAnalytics, options?: any, callback?: (err: any, userToken?: number | string) => void): number | string | undefined;
export declare function onUserTokenChange(this: AlgoliaAnalytics, callback?: (userToken?: number | string) => void, options?: {
immediate: boolean;
}): void;

View File

@@ -1,28 +0,0 @@
import type AlgoliaAnalytics from "./insights";
import type { WithAdditionalParams } from "./utils";
export interface InsightsSearchClickEvent {
eventName: string;
userToken?: string;
timestamp?: number;
index: string;
queryID: string;
objectIDs: string[];
positions: number[];
}
export declare function clickedObjectIDsAfterSearch(this: AlgoliaAnalytics, ...params: Array<WithAdditionalParams<InsightsSearchClickEvent>>): ReturnType<AlgoliaAnalytics["sendEvents"]>;
export interface InsightsClickObjectIDsEvent {
eventName: string;
userToken?: string;
timestamp?: number;
index: string;
objectIDs: string[];
}
export declare function clickedObjectIDs(this: AlgoliaAnalytics, ...params: Array<WithAdditionalParams<InsightsClickObjectIDsEvent>>): ReturnType<AlgoliaAnalytics["sendEvents"]>;
export interface InsightsClickFiltersEvent {
eventName: string;
userToken?: string;
timestamp?: number;
index: string;
filters: string[];
}
export declare function clickedFilters(this: AlgoliaAnalytics, ...params: Array<WithAdditionalParams<InsightsClickFiltersEvent>>): ReturnType<AlgoliaAnalytics["sendEvents"]>;

View File

@@ -1,36 +0,0 @@
import type AlgoliaAnalytics from "./insights";
import type { InsightsEvent } from "./types";
import type { WithAdditionalParams } from "./utils";
export interface InsightsSearchConversionEvent {
eventName: string;
userToken?: string;
timestamp?: number;
index: string;
queryID: string;
objectIDs: string[];
objectData?: InsightsEvent["objectData"];
currency?: InsightsEvent["currency"];
}
export declare function convertedObjectIDsAfterSearch(this: AlgoliaAnalytics, ...params: Array<WithAdditionalParams<InsightsSearchConversionEvent>>): ReturnType<AlgoliaAnalytics["sendEvents"]>;
export declare function addedToCartObjectIDsAfterSearch(this: AlgoliaAnalytics, ...params: Array<WithAdditionalParams<InsightsSearchConversionEvent>>): ReturnType<AlgoliaAnalytics["sendEvents"]>;
export declare function purchasedObjectIDsAfterSearch(this: AlgoliaAnalytics, ...params: Array<WithAdditionalParams<InsightsSearchConversionEvent>>): ReturnType<AlgoliaAnalytics["sendEvents"]>;
export interface InsightsSearchConversionObjectIDsEvent {
eventName: string;
userToken?: string;
timestamp?: number;
index: string;
objectIDs: string[];
objectData?: InsightsEvent["objectData"];
currency?: InsightsEvent["currency"];
}
export declare function convertedObjectIDs(this: AlgoliaAnalytics, ...params: Array<WithAdditionalParams<InsightsSearchConversionObjectIDsEvent>>): ReturnType<AlgoliaAnalytics["sendEvents"]>;
export declare function addedToCartObjectIDs(this: AlgoliaAnalytics, ...params: Array<WithAdditionalParams<InsightsSearchConversionObjectIDsEvent>>): ReturnType<AlgoliaAnalytics["sendEvents"]>;
export declare function purchasedObjectIDs(this: AlgoliaAnalytics, ...params: Array<WithAdditionalParams<InsightsSearchConversionObjectIDsEvent>>): ReturnType<AlgoliaAnalytics["sendEvents"]>;
export interface InsightsSearchConversionFiltersEvent {
eventName: string;
userToken?: string;
timestamp?: number;
index: string;
filters: string[];
}
export declare function convertedFilters(this: AlgoliaAnalytics, ...params: Array<WithAdditionalParams<InsightsSearchConversionFiltersEvent>>): ReturnType<AlgoliaAnalytics["sendEvents"]>;

View File

@@ -1,8 +0,0 @@
import { getFunctionalInterface } from "./_getFunctionalInterface";
import { processQueue } from "./_processQueue";
import AlgoliaAnalytics from "./insights";
import { getRequesterForBrowser } from "./utils/getRequesterForBrowser";
export { getRequesterForBrowser, AlgoliaAnalytics, getFunctionalInterface, processQueue };
export * from "./types";
declare const _default: import("./types").InsightsClient;
export default _default;

View File

@@ -1,8 +0,0 @@
import { getFunctionalInterface } from "./_getFunctionalInterface";
import { processQueue } from "./_processQueue";
import AlgoliaAnalytics from "./insights";
import { getRequesterForNode } from "./utils/getRequesterForNode";
export { getRequesterForNode, AlgoliaAnalytics, getFunctionalInterface, processQueue };
export * from "./types";
declare const _default: import("./types").InsightsClient;
export default _default;

View File

@@ -1,5 +0,0 @@
import AlgoliaAnalytics from "./insights";
import type { RequestFnType } from "./utils/request";
export declare function createInsightsClient(requestFn: RequestFnType): AlgoliaAnalytics;
declare const _default: AlgoliaAnalytics;
export default _default;

View File

@@ -1,21 +0,0 @@
import type AlgoliaAnalytics from "./insights";
type InsightRegion = "de" | "us";
export interface InitParams {
apiKey?: string;
appId?: string;
userHasOptedOut?: boolean;
anonymousUserToken?: boolean;
useCookie?: boolean;
cookieDuration?: number;
region?: InsightRegion;
userToken?: string;
partial?: boolean;
host?: string;
}
/**
* Binds credentials and settings to class.
*
* @param options - InitParams.
*/
export declare function init(this: AlgoliaAnalytics, options?: InitParams): void;
export {};

View File

@@ -1,63 +0,0 @@
import { addAlgoliaAgent } from "./_algoliaAgent";
import { getVersion } from "./_getVersion";
import { makeSendEvents } from "./_sendEvent";
import { getUserToken, setUserToken, setAnonymousUserToken, onUserTokenChange } from "./_tokenUtils";
import { clickedObjectIDsAfterSearch, clickedObjectIDs, clickedFilters } from "./click";
import { convertedObjectIDsAfterSearch, addedToCartObjectIDsAfterSearch, purchasedObjectIDsAfterSearch, convertedObjectIDs, addedToCartObjectIDs, purchasedObjectIDs, convertedFilters } from "./conversion";
import { init } from "./init";
import type { RequestFnType } from "./utils/request";
import { viewedObjectIDs, viewedFilters } from "./view";
type Queue = {
queue: string[][];
};
type AnalyticsFunction = {
[key: string]: (fnName: string, fnArgs: any[]) => void;
};
export type AlgoliaAnalyticsObject = AnalyticsFunction | Queue;
declare global {
interface Window {
AlgoliaAnalyticsObject?: string;
}
}
/**
* AlgoliaAnalytics class.
*/
declare class AlgoliaAnalytics {
_apiKey?: string;
_appId?: string;
_region?: string;
_host?: string;
_endpointOrigin: string;
_anonymousUserToken: boolean;
_userToken?: number | string;
_userHasOptedOut: boolean;
_useCookie: boolean;
_cookieDuration: number;
_ua: string[];
_onUserTokenChangeCallback?: (userToken?: number | string) => void;
version: string;
init: typeof init;
getVersion: typeof getVersion;
addAlgoliaAgent: typeof addAlgoliaAgent;
setUserToken: typeof setUserToken;
setAnonymousUserToken: typeof setAnonymousUserToken;
getUserToken: typeof getUserToken;
onUserTokenChange: typeof onUserTokenChange;
sendEvents: ReturnType<typeof makeSendEvents>;
clickedObjectIDsAfterSearch: typeof clickedObjectIDsAfterSearch;
clickedObjectIDs: typeof clickedObjectIDs;
clickedFilters: typeof clickedFilters;
convertedObjectIDsAfterSearch: typeof convertedObjectIDsAfterSearch;
purchasedObjectIDsAfterSearch: typeof purchasedObjectIDsAfterSearch;
addedToCartObjectIDsAfterSearch: typeof addedToCartObjectIDsAfterSearch;
convertedObjectIDs: typeof convertedObjectIDs;
addedToCartObjectIDs: typeof addedToCartObjectIDs;
purchasedObjectIDs: typeof purchasedObjectIDs;
convertedFilters: typeof convertedFilters;
viewedObjectIDs: typeof viewedObjectIDs;
viewedFilters: typeof viewedFilters;
constructor({ requestFn }: {
requestFn: RequestFnType;
});
}
export default AlgoliaAnalytics;

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,75 +0,0 @@
import type { addAlgoliaAgent } from "./_algoliaAgent";
import type { getVersion } from "./_getVersion";
import type { makeSendEvents } from "./_sendEvent";
import type { getUserToken, setUserToken, onUserTokenChange } from "./_tokenUtils";
import type { clickedObjectIDsAfterSearch, clickedObjectIDs, clickedFilters } from "./click";
import type { convertedObjectIDsAfterSearch, convertedObjectIDs, convertedFilters, purchasedObjectIDs, purchasedObjectIDsAfterSearch, addedToCartObjectIDsAfterSearch, addedToCartObjectIDs } from "./conversion";
import type { init } from "./init";
import type { viewedObjectIDs, viewedFilters } from "./view";
export type InsightsMethodMap = {
init: Parameters<typeof init>;
getVersion: Parameters<typeof getVersion>;
addAlgoliaAgent: Parameters<typeof addAlgoliaAgent>;
setUserToken: Parameters<typeof setUserToken>;
getUserToken: Parameters<typeof getUserToken>;
onUserTokenChange: Parameters<typeof onUserTokenChange>;
clickedObjectIDsAfterSearch: Parameters<typeof clickedObjectIDsAfterSearch>;
clickedObjectIDs: Parameters<typeof clickedObjectIDs>;
clickedFilters: Parameters<typeof clickedFilters>;
convertedObjectIDsAfterSearch: Parameters<typeof convertedObjectIDsAfterSearch>;
convertedObjectIDs: Parameters<typeof convertedObjectIDs>;
convertedFilters: Parameters<typeof convertedFilters>;
viewedObjectIDs: Parameters<typeof viewedObjectIDs>;
viewedFilters: Parameters<typeof viewedFilters>;
purchasedObjectIDs: Parameters<typeof purchasedObjectIDs>;
purchasedObjectIDsAfterSearch: Parameters<typeof purchasedObjectIDsAfterSearch>;
addedToCartObjectIDs: Parameters<typeof addedToCartObjectIDs>;
addedToCartObjectIDsAfterSearch: Parameters<typeof addedToCartObjectIDsAfterSearch>;
sendEvents: Parameters<ReturnType<typeof makeSendEvents>>;
};
type MethodType<MethodName extends keyof InsightsMethodMap> = (method: MethodName, ...args: InsightsMethodMap[MethodName]) => void;
export type Init = MethodType<"init">;
export type GetVersion = MethodType<"getVersion">;
export type AddAlgoliaAgent = MethodType<"addAlgoliaAgent">;
export type SetUserToken = MethodType<"setUserToken">;
export type GetUserToken = MethodType<"getUserToken">;
export type OnUserTokenChange = MethodType<"onUserTokenChange">;
export type ClickedObjectIDsAfterSearch = MethodType<"clickedObjectIDsAfterSearch">;
export type ClickedObjectIDs = MethodType<"clickedObjectIDs">;
export type ClickedFilters = MethodType<"clickedFilters">;
export type ConvertedObjectIDsAfterSearch = MethodType<"convertedObjectIDsAfterSearch">;
export type ConvertedObjectIDs = MethodType<"convertedObjectIDs">;
export type ConvertedFilters = MethodType<"convertedFilters">;
export type ViewedObjectIDs = MethodType<"viewedObjectIDs">;
export type ViewedFilters = MethodType<"viewedFilters">;
export type SendEvents = MethodType<"sendEvents">;
export type InsightsClient = (<MethodName extends keyof InsightsMethodMap>(method: MethodName, ...args: InsightsMethodMap[MethodName]) => void) & {
version?: string;
};
export type InsightsEventType = "click" | "conversion" | "view";
export type InsightsEventConversionSubType = "addToCart" | "purchase";
export type InsightsEventObjectData = {
queryID?: string;
price?: number | string;
discount?: number | string;
quantity?: number;
};
export type InsightsEvent = {
eventType: InsightsEventType;
eventSubtype?: InsightsEventConversionSubType;
eventName: string;
userToken?: number | string;
timestamp?: number;
index: string;
queryID?: string;
objectIDs?: string[];
positions?: number[];
objectData?: InsightsEventObjectData[];
filters?: string[];
value?: number | string;
currency?: string;
};
export type InsightsAdditionalEventParams = {
headers?: Record<string, string>;
};
export {};

View File

@@ -1,8 +0,0 @@
import type { InsightsAdditionalEventParams } from "../types";
export type WithAdditionalParams<TEventType> = InsightsAdditionalEventParams | TEventType;
export declare function extractAdditionalParams<TEventType extends {
index: string;
}>(params: Array<InsightsAdditionalEventParams | TEventType>): {
events: TEventType[];
additionalParams?: InsightsAdditionalEventParams;
};

View File

@@ -1,4 +0,0 @@
export declare const supportsCookies: () => boolean;
export declare const supportsSendBeacon: () => boolean;
export declare const supportsXMLHttpRequest: () => boolean;
export declare const supportsNodeHttpModule: () => boolean;

View File

@@ -1,2 +0,0 @@
import type { RequestFnType } from "./request";
export declare function getRequesterForBrowser(): RequestFnType;

View File

@@ -1,2 +0,0 @@
import type { RequestFnType } from "./request";
export declare function getRequesterForNode(): RequestFnType;

View File

@@ -1,6 +0,0 @@
export declare const isUndefined: (value: any) => value is undefined;
export declare const isString: (value: any) => value is string;
export declare const isNumber: (value: any) => value is number;
export declare const isFunction: (value: any) => value is Function;
export * from "./extractAdditionalParams";
export * from "./featureDetection";

View File

@@ -1,4 +0,0 @@
export type RequestFnType = (url: string, data: Record<string, unknown>) => Promise<boolean>;
export declare const requestWithXMLHttpRequest: RequestFnType;
export declare const requestWithSendBeacon: RequestFnType;
export declare const requestWithNodeHttpModule: RequestFnType;

View File

@@ -1,7 +0,0 @@
/**
* Create UUID according to
* https://www.ietf.org/rfc/rfc4122.txt.
*
* @returns Generated UUID.
*/
export declare function createUUID(): string;

View File

@@ -1,18 +0,0 @@
import type AlgoliaAnalytics from "./insights";
import type { WithAdditionalParams } from "./utils";
export interface InsightsSearchViewObjectIDsEvent {
eventName: string;
userToken?: string;
timestamp?: number;
index: string;
objectIDs: string[];
}
export declare function viewedObjectIDs(this: AlgoliaAnalytics, ...params: Array<WithAdditionalParams<InsightsSearchViewObjectIDsEvent>>): ReturnType<AlgoliaAnalytics["sendEvents"]>;
export interface InsightsSearchViewFiltersEvent {
eventName: string;
userToken?: string;
timestamp?: number;
index: string;
filters: string[];
}
export declare function viewedFilters(this: AlgoliaAnalytics, ...params: Array<WithAdditionalParams<InsightsSearchViewFiltersEvent>>): ReturnType<AlgoliaAnalytics["sendEvents"]>;

View File

@@ -1,4 +0,0 @@
// shim for node modules in React Native
// see https://github.com/facebook/react-native/issues/5079
type empty = {};
export default empty;

View File

@@ -1,3 +0,0 @@
// shim for node modules in React Native
// see https://github.com/facebook/react-native/issues/5079
module.exports = {};

View File

@@ -1,3 +0,0 @@
export * from "./dist/entry-browser-cjs";
import aa from "./dist/entry-browser-cjs";
export default aa;

View File

@@ -1,8 +0,0 @@
const aa = require("./dist/search-insights-browser.cjs.min.js");
module.exports = aa.default;
Object.keys(aa).forEach(key => {
if (key !== "default") {
module.exports[key] = aa[key];
}
});

View File

@@ -1,3 +0,0 @@
export * from "./dist/entry-node-cjs";
import aa from "./dist/entry-node-cjs";
export default aa;

View File

@@ -1,8 +0,0 @@
const aa = require("./dist/search-insights-node.cjs.min.js");
module.exports = aa.default;
Object.keys(aa).forEach(key => {
if (key !== "default") {
module.exports[key] = aa[key];
}
});

View File

@@ -1,27 +0,0 @@
import type {
InsightsEvent,
InsightsEventConversionSubType,
InsightsEventType
} from "./types";
export function addEventType(
eventType: InsightsEventType,
params: Array<Omit<InsightsEvent, "eventType">>
): InsightsEvent[] {
return params.map((event) => ({
eventType,
...event
}));
}
export function addEventTypeAndSubtype(
eventType: InsightsEventType,
eventSubtype: InsightsEventConversionSubType,
params: Array<Omit<InsightsEvent, "eventSubtype" | "eventType">>
): InsightsEvent[] {
return params.map((event) => ({
eventType,
eventSubtype,
...event
}));
}

View File

@@ -1,17 +0,0 @@
import { version } from "../package.json";
import type AlgoliaAnalytics from "./insights";
export const DEFAULT_ALGOLIA_AGENTS = [
`insights-js (${version})`,
`insights-js-${__FLAVOR__} (${version})`
];
export function addAlgoliaAgent(
this: AlgoliaAnalytics,
algoliaAgent: string
): void {
if (this._ua.indexOf(algoliaAgent) === -1) {
this._ua.push(algoliaAgent);
}
}

View File

@@ -1,26 +0,0 @@
import { version } from "../package.json";
import { getFunctionalInterface } from "./_getFunctionalInterface";
import AlgoliaAnalytics from "./insights";
import type { InsightsClient } from "./types";
import type { RequestFnType } from "./utils/request";
import { createUUID } from "./utils/uuid";
export function createInsightsClient(requestFn: RequestFnType): InsightsClient {
const aa = getFunctionalInterface(new AlgoliaAnalytics({ requestFn }));
if (typeof window === "object") {
if (!window.AlgoliaAnalyticsObject) {
let pointer: string;
do {
pointer = createUUID();
} while (window[pointer as any] !== undefined);
window.AlgoliaAnalyticsObject = pointer;
(window as any)[window.AlgoliaAnalyticsObject] = aa;
}
}
aa.version = version;
return aa;
}

View File

@@ -1,17 +0,0 @@
import type AlgoliaAnalytics from "./insights";
import type { InsightsClient } from "./types";
import { isFunction } from "./utils";
export function getFunctionalInterface(
instance: AlgoliaAnalytics
): InsightsClient {
return (functionName, ...functionArguments) => {
if (functionName && isFunction((instance as any)[functionName])) {
// @ts-expect-error
instance[functionName](...functionArguments);
} else {
// eslint-disable-next-line no-console
console.warn(`The method \`${functionName}\` doesn't exist.`);
}
};
}

View File

@@ -1,11 +0,0 @@
import type AlgoliaAnalytics from "./insights";
import { isFunction } from "./utils";
export function getVersion(
this: AlgoliaAnalytics,
callback: (version: string) => void
): void {
if (isFunction(callback)) {
callback(this.version);
}
}

View File

@@ -1,42 +0,0 @@
/**
* Processes queue that might have been set before
* the script was actually loaded and reassigns
* class over globalObject variable to execute commands
* instead of putting them to the queue.
*/
import { getFunctionalInterface } from "./_getFunctionalInterface";
import type AlgoliaAnalytics from "./insights";
export function processQueue(this: AlgoliaAnalytics, globalObject: any): void {
// Set pointer which allows renaming of the script
const pointer = globalObject.AlgoliaAnalyticsObject as string;
if (pointer) {
const _aa = getFunctionalInterface(this);
// `aa` is the user facing function, which is defined in the install snippet.
// - before library is initialized `aa` fills a queue
// - after library is initialized `aa` calls `_aa`
const aa = globalObject[pointer];
aa.queue = aa.queue || [];
const queue: IArguments[] = aa.queue;
// Loop queue and execute functions in the queue
queue.forEach((args: IArguments) => {
const [functionName, ...functionArguments] = [].slice.call(args);
_aa(functionName as any, ...(functionArguments as any));
});
/* eslint-disable no-warning-comments */
// FIXME: Reassigning the pointer is a bad idea (cf: https://github.com/algolia/search-insights.js/issues/127)
// to remove this without any breaking change, we redefine the Array.prototype.push method on the queue array.
// for next major version, use a custom method instead of push.
/* eslint-enable */
// @ts-expect-error (otherwise typescript won't let you change the signature)
queue.push = (args: IArguments): number => {
const [functionName, ...functionArguments] = [].slice.call(args);
_aa(functionName as any, ...(functionArguments as any));
};
}
}

View File

@@ -1,83 +0,0 @@
import type AlgoliaAnalytics from "./insights";
import type { InsightsAdditionalEventParams, InsightsEvent } from "./types";
import { isUndefined } from "./utils";
import type { RequestFnType } from "./utils/request";
export function makeSendEvents(requestFn: RequestFnType) {
return function sendEvents(
this: AlgoliaAnalytics,
eventData: InsightsEvent[],
additionalParams?: InsightsAdditionalEventParams
): Promise<boolean> | undefined {
if (this._userHasOptedOut) {
return undefined;
}
const hasCredentials =
(!isUndefined(this._apiKey) && !isUndefined(this._appId)) ||
(additionalParams?.headers?.["X-Algolia-Application-Id"] &&
additionalParams?.headers?.["X-Algolia-API-Key"]);
if (!hasCredentials) {
throw new Error(
"Before calling any methods on the analytics, you first need to call the 'init' function with appId and apiKey parameters or provide custom credentials in additional parameters."
);
}
if (!this._userToken && this._anonymousUserToken) {
this.setAnonymousUserToken(true);
}
const events: InsightsEvent[] = eventData.map((data) => {
const { filters, ...rest } = data;
const payload: InsightsEvent = {
...rest,
userToken: data?.userToken ?? this._userToken
};
if (!isUndefined(filters)) {
payload.filters = filters.map(encodeURIComponent);
}
return payload;
});
return sendRequest(
requestFn,
this._ua,
this._endpointOrigin,
events,
this._appId,
this._apiKey,
additionalParams?.headers
);
};
}
// eslint-disable-next-line max-params
function sendRequest(
requestFn: RequestFnType,
userAgents: string[],
endpointOrigin: string,
events: InsightsEvent[],
appId?: string,
apiKey?: string,
additionalHeaders: InsightsAdditionalEventParams["headers"] = {}
): Promise<boolean> {
const {
"X-Algolia-Application-Id": providedAppId,
"X-Algolia-API-Key": providedApiKey,
...restHeaders
} = additionalHeaders;
// Auth query
const headers: Record<string, string> = {
"X-Algolia-Application-Id": providedAppId ?? appId,
"X-Algolia-API-Key": providedApiKey ?? apiKey,
"X-Algolia-Agent": encodeURIComponent(userAgents.join("; ")),
...restHeaders
};
const queryParameters = Object.keys(headers)
.map((key) => `${key}=${headers[key]}`)
.join("&");
const reportingURL = `${endpointOrigin}/1/events?${queryParameters}`;
return requestFn(reportingURL, { events });
}

View File

@@ -1,95 +0,0 @@
import type AlgoliaAnalytics from "./insights";
import { isFunction, supportsCookies } from "./utils";
import { createUUID } from "./utils/uuid";
const COOKIE_KEY = "_ALGOLIA";
export const MONTH = 30 * 24 * 60 * 60 * 1000;
const setCookie = (
name: string,
value: number | string,
duration: number
): void => {
const d = new Date();
d.setTime(d.getTime() + duration);
const expires = `expires=${d.toUTCString()}`;
document.cookie = `${name}=${value};${expires};path=/`;
};
export const getCookie = (name: string): string => {
const prefix = `${name}=`;
const ca = document.cookie.split(";");
for (let i = 0; i < ca.length; i++) {
let c = ca[i];
while (c.charAt(0) === " ") {
c = c.substring(1);
}
if (c.indexOf(prefix) === 0) {
return c.substring(prefix.length, c.length);
}
}
return "";
};
export function setAnonymousUserToken(
this: AlgoliaAnalytics,
inMemory = false
): void {
if (inMemory) {
this.setUserToken(`anonymous-${createUUID()}`);
return;
}
if (!supportsCookies()) {
return;
}
const foundToken = getCookie(COOKIE_KEY);
if (
!foundToken ||
foundToken === "" ||
foundToken.indexOf("anonymous-") !== 0
) {
const savedUserToken = this.setUserToken(`anonymous-${createUUID()}`);
setCookie(COOKIE_KEY, savedUserToken, this._cookieDuration);
} else {
this.setUserToken(foundToken);
}
}
export function setUserToken(
this: AlgoliaAnalytics,
userToken: number | string
): number | string {
this._userToken = userToken;
if (isFunction(this._onUserTokenChangeCallback)) {
this._onUserTokenChangeCallback(this._userToken);
}
return this._userToken;
}
export function getUserToken(
this: AlgoliaAnalytics,
options?: any,
callback?: (err: any, userToken?: number | string) => void
): number | string | undefined {
if (isFunction(callback)) {
callback(null, this._userToken);
}
return this._userToken;
}
export function onUserTokenChange(
this: AlgoliaAnalytics,
callback?: (userToken?: number | string) => void,
options?: { immediate: boolean }
): void {
this._onUserTokenChangeCallback = callback;
if (
options &&
options.immediate &&
isFunction(this._onUserTokenChangeCallback)
) {
this._onUserTokenChangeCallback(this._userToken);
}
}

View File

@@ -1,63 +0,0 @@
import { addEventType } from "./_addEventType";
import type AlgoliaAnalytics from "./insights";
import type { WithAdditionalParams } from "./utils";
import { extractAdditionalParams } from "./utils";
export interface InsightsSearchClickEvent {
eventName: string;
userToken?: string;
timestamp?: number;
index: string;
queryID: string;
objectIDs: string[];
positions: number[];
}
export function clickedObjectIDsAfterSearch(
this: AlgoliaAnalytics,
...params: Array<WithAdditionalParams<InsightsSearchClickEvent>>
): ReturnType<AlgoliaAnalytics["sendEvents"]> {
const { events, additionalParams } =
extractAdditionalParams<InsightsSearchClickEvent>(params);
return this.sendEvents(addEventType("click", events), additionalParams);
}
export interface InsightsClickObjectIDsEvent {
eventName: string;
userToken?: string;
timestamp?: number;
index: string;
objectIDs: string[];
}
export function clickedObjectIDs(
this: AlgoliaAnalytics,
...params: Array<WithAdditionalParams<InsightsClickObjectIDsEvent>>
): ReturnType<AlgoliaAnalytics["sendEvents"]> {
const { events, additionalParams } =
extractAdditionalParams<InsightsClickObjectIDsEvent>(params);
return this.sendEvents(addEventType("click", events), additionalParams);
}
export interface InsightsClickFiltersEvent {
eventName: string;
userToken?: string;
timestamp?: number;
index: string;
filters: string[];
}
export function clickedFilters(
this: AlgoliaAnalytics,
...params: Array<WithAdditionalParams<InsightsClickFiltersEvent>>
): ReturnType<AlgoliaAnalytics["sendEvents"]> {
const { events, additionalParams } =
extractAdditionalParams<InsightsClickFiltersEvent>(params);
return this.sendEvents(addEventType("click", events), additionalParams);
}

View File

@@ -1,119 +0,0 @@
import { addEventType, addEventTypeAndSubtype } from "./_addEventType";
import type AlgoliaAnalytics from "./insights";
import type { InsightsEvent } from "./types";
import type { WithAdditionalParams } from "./utils";
import { extractAdditionalParams } from "./utils";
export interface InsightsSearchConversionEvent {
eventName: string;
userToken?: string;
timestamp?: number;
index: string;
queryID: string;
objectIDs: string[];
objectData?: InsightsEvent["objectData"];
currency?: InsightsEvent["currency"];
}
export function convertedObjectIDsAfterSearch(
this: AlgoliaAnalytics,
...params: Array<WithAdditionalParams<InsightsSearchConversionEvent>>
): ReturnType<AlgoliaAnalytics["sendEvents"]> {
const { events, additionalParams } =
extractAdditionalParams<InsightsSearchConversionEvent>(params);
return this.sendEvents(addEventType("conversion", events), additionalParams);
}
export function addedToCartObjectIDsAfterSearch(
this: AlgoliaAnalytics,
...params: Array<WithAdditionalParams<InsightsSearchConversionEvent>>
): ReturnType<AlgoliaAnalytics["sendEvents"]> {
const { events, additionalParams } =
extractAdditionalParams<InsightsSearchConversionEvent>(params);
return this.sendEvents(
addEventTypeAndSubtype("conversion", "addToCart", events),
additionalParams
);
}
export function purchasedObjectIDsAfterSearch(
this: AlgoliaAnalytics,
...params: Array<WithAdditionalParams<InsightsSearchConversionEvent>>
): ReturnType<AlgoliaAnalytics["sendEvents"]> {
const { events, additionalParams } =
extractAdditionalParams<InsightsSearchConversionEvent>(params);
return this.sendEvents(
addEventTypeAndSubtype("conversion", "purchase", events),
additionalParams
);
}
export interface InsightsSearchConversionObjectIDsEvent {
eventName: string;
userToken?: string;
timestamp?: number;
index: string;
objectIDs: string[];
objectData?: InsightsEvent["objectData"];
currency?: InsightsEvent["currency"];
}
export function convertedObjectIDs(
this: AlgoliaAnalytics,
...params: Array<WithAdditionalParams<InsightsSearchConversionObjectIDsEvent>>
): ReturnType<AlgoliaAnalytics["sendEvents"]> {
const { events, additionalParams } =
extractAdditionalParams<InsightsSearchConversionObjectIDsEvent>(params);
return this.sendEvents(addEventType("conversion", events), additionalParams);
}
export function addedToCartObjectIDs(
this: AlgoliaAnalytics,
...params: Array<WithAdditionalParams<InsightsSearchConversionObjectIDsEvent>>
): ReturnType<AlgoliaAnalytics["sendEvents"]> {
const { events, additionalParams } =
extractAdditionalParams<InsightsSearchConversionObjectIDsEvent>(params);
return this.sendEvents(
addEventTypeAndSubtype("conversion", "addToCart", events),
additionalParams
);
}
export function purchasedObjectIDs(
this: AlgoliaAnalytics,
...params: Array<WithAdditionalParams<InsightsSearchConversionObjectIDsEvent>>
): ReturnType<AlgoliaAnalytics["sendEvents"]> {
const { events, additionalParams } =
extractAdditionalParams<InsightsSearchConversionObjectIDsEvent>(params);
return this.sendEvents(
addEventTypeAndSubtype("conversion", "purchase", events),
additionalParams
);
}
export interface InsightsSearchConversionFiltersEvent {
eventName: string;
userToken?: string;
timestamp?: number;
index: string;
filters: string[];
}
export function convertedFilters(
this: AlgoliaAnalytics,
...params: Array<WithAdditionalParams<InsightsSearchConversionFiltersEvent>>
): ReturnType<AlgoliaAnalytics["sendEvents"]> {
const { events, additionalParams } =
extractAdditionalParams<InsightsSearchConversionFiltersEvent>(params);
return this.sendEvents(addEventType("conversion", events), additionalParams);
}

View File

@@ -1,15 +0,0 @@
import { createInsightsClient } from "./_createInsightsClient";
import { getFunctionalInterface } from "./_getFunctionalInterface";
import { processQueue } from "./_processQueue";
import AlgoliaAnalytics from "./insights";
import { getRequesterForBrowser } from "./utils/getRequesterForBrowser";
export {
getRequesterForBrowser,
AlgoliaAnalytics,
getFunctionalInterface,
processQueue
};
export * from "./types";
export default createInsightsClient(getRequesterForBrowser());

View File

@@ -1,15 +0,0 @@
import { createInsightsClient } from "./_createInsightsClient";
import { getFunctionalInterface } from "./_getFunctionalInterface";
import { processQueue } from "./_processQueue";
import AlgoliaAnalytics from "./insights";
import { getRequesterForNode } from "./utils/getRequesterForNode";
export {
getRequesterForNode,
AlgoliaAnalytics,
getFunctionalInterface,
processQueue
};
export * from "./types";
export default createInsightsClient(getRequesterForNode());

View File

@@ -1,21 +0,0 @@
import { version } from "../package.json";
import { processQueue } from "./_processQueue";
import AlgoliaAnalytics from "./insights";
import { getRequesterForBrowser } from "./utils/getRequesterForBrowser";
import type { RequestFnType } from "./utils/request";
export function createInsightsClient(
requestFn: RequestFnType
): AlgoliaAnalytics {
const instance = new AlgoliaAnalytics({ requestFn });
if (typeof window === "object") {
// Process queue upon script execution
processQueue.call(instance, window);
}
instance.version = version;
return instance;
}
export default createInsightsClient(getRequesterForBrowser());

View File

@@ -1,107 +0,0 @@
import { DEFAULT_ALGOLIA_AGENTS } from "./_algoliaAgent";
import { MONTH } from "./_tokenUtils";
import type AlgoliaAnalytics from "./insights";
import { isUndefined, isNumber } from "./utils";
type InsightRegion = "de" | "us";
const SUPPORTED_REGIONS: InsightRegion[] = ["de", "us"];
export interface InitParams {
apiKey?: string;
appId?: string;
userHasOptedOut?: boolean;
anonymousUserToken?: boolean;
useCookie?: boolean;
cookieDuration?: number;
region?: InsightRegion;
userToken?: string;
partial?: boolean;
host?: string;
}
/**
* Binds credentials and settings to class.
*
* @param options - InitParams.
*/
export function init(this: AlgoliaAnalytics, options: InitParams = {}): void {
if (
!isUndefined(options.region) &&
SUPPORTED_REGIONS.indexOf(options.region) === -1
) {
throw new Error(
`optional region is incorrect, please provide either one of: ${SUPPORTED_REGIONS.join(
", "
)}.`
);
}
if (
!isUndefined(options.cookieDuration) &&
(!isNumber(options.cookieDuration) ||
!isFinite(options.cookieDuration) ||
Math.floor(options.cookieDuration) !== options.cookieDuration)
) {
throw new Error(
`optional cookieDuration is incorrect, expected an integer.`
);
}
/* eslint-disable no-console */
if (__DEV__) {
console.info(`Since v2.0.4, search-insights no longer validates event payloads.
You can visit https://algolia.com/events/debugger instead.`);
}
/* eslint-enable */
setOptions(this, options, {
_userHasOptedOut: Boolean(options.userHasOptedOut),
_region: options.region,
_host: options.host,
_anonymousUserToken: options.anonymousUserToken ?? true,
_useCookie: options.useCookie ?? false,
_cookieDuration: options.cookieDuration || 6 * MONTH
});
this._endpointOrigin =
this._host ||
(this._region
? `https://insights.${this._region}.algolia.io`
: "https://insights.algolia.io");
// user agent
this._ua = [...DEFAULT_ALGOLIA_AGENTS];
if (options.userToken) {
this.setUserToken(options.userToken);
} else if (!this._userToken && !this._userHasOptedOut && this._useCookie) {
this.setAnonymousUserToken();
}
}
type ThisParams = Pick<
AlgoliaAnalytics,
| "_anonymousUserToken"
| "_cookieDuration"
| "_host"
| "_region"
| "_useCookie"
| "_userHasOptedOut"
>;
function setOptions(
target: AlgoliaAnalytics,
{ partial, ...options }: InitParams,
defaultValues: ThisParams
): void {
if (!partial) {
Object.assign(target, defaultValues);
}
Object.assign(
target,
(Object.keys(options) as Array<keyof typeof options>).reduce(
(acc, key) => ({ ...acc, [`_${key}`]: options[key] }),
{}
)
);
}

View File

@@ -1,130 +0,0 @@
import { version } from "../package.json";
import { addAlgoliaAgent } from "./_algoliaAgent";
import { getVersion } from "./_getVersion";
import { makeSendEvents } from "./_sendEvent";
import {
getUserToken,
setUserToken,
setAnonymousUserToken,
onUserTokenChange,
MONTH
} from "./_tokenUtils";
import {
clickedObjectIDsAfterSearch,
clickedObjectIDs,
clickedFilters
} from "./click";
import {
convertedObjectIDsAfterSearch,
addedToCartObjectIDsAfterSearch,
purchasedObjectIDsAfterSearch,
convertedObjectIDs,
addedToCartObjectIDs,
purchasedObjectIDs,
convertedFilters
} from "./conversion";
import { init } from "./init";
import type { RequestFnType } from "./utils/request";
import { viewedObjectIDs, viewedFilters } from "./view";
type Queue = {
queue: string[][];
};
type AnalyticsFunction = {
[key: string]: (fnName: string, fnArgs: any[]) => void;
};
export type AlgoliaAnalyticsObject = AnalyticsFunction | Queue;
declare global {
interface Window {
AlgoliaAnalyticsObject?: string;
}
}
/**
* AlgoliaAnalytics class.
*/
class AlgoliaAnalytics {
_apiKey?: string;
_appId?: string;
_region?: string;
_host?: string;
_endpointOrigin = "https://insights.algolia.io";
_anonymousUserToken = true;
_userToken?: number | string;
_userHasOptedOut = false;
_useCookie = false;
_cookieDuration = 6 * MONTH;
// user agent
_ua: string[] = [];
_onUserTokenChangeCallback?: (userToken?: number | string) => void;
version: string = version;
// Public methods
init: typeof init;
getVersion: typeof getVersion;
addAlgoliaAgent: typeof addAlgoliaAgent;
setUserToken: typeof setUserToken;
setAnonymousUserToken: typeof setAnonymousUserToken;
getUserToken: typeof getUserToken;
onUserTokenChange: typeof onUserTokenChange;
sendEvents: ReturnType<typeof makeSendEvents>;
clickedObjectIDsAfterSearch: typeof clickedObjectIDsAfterSearch;
clickedObjectIDs: typeof clickedObjectIDs;
clickedFilters: typeof clickedFilters;
convertedObjectIDsAfterSearch: typeof convertedObjectIDsAfterSearch;
purchasedObjectIDsAfterSearch: typeof purchasedObjectIDsAfterSearch;
addedToCartObjectIDsAfterSearch: typeof addedToCartObjectIDsAfterSearch;
convertedObjectIDs: typeof convertedObjectIDs;
addedToCartObjectIDs: typeof addedToCartObjectIDs;
purchasedObjectIDs: typeof purchasedObjectIDs;
convertedFilters: typeof convertedFilters;
viewedObjectIDs: typeof viewedObjectIDs;
viewedFilters: typeof viewedFilters;
constructor({ requestFn }: { requestFn: RequestFnType }) {
this.sendEvents = makeSendEvents(requestFn).bind(this);
this.init = init.bind(this);
this.addAlgoliaAgent = addAlgoliaAgent.bind(this);
this.setUserToken = setUserToken.bind(this);
this.setAnonymousUserToken = setAnonymousUserToken.bind(this);
this.getUserToken = getUserToken.bind(this);
this.onUserTokenChange = onUserTokenChange.bind(this);
this.clickedObjectIDsAfterSearch = clickedObjectIDsAfterSearch.bind(this);
this.clickedObjectIDs = clickedObjectIDs.bind(this);
this.clickedFilters = clickedFilters.bind(this);
this.convertedObjectIDsAfterSearch =
convertedObjectIDsAfterSearch.bind(this);
this.purchasedObjectIDsAfterSearch =
purchasedObjectIDsAfterSearch.bind(this);
this.addedToCartObjectIDsAfterSearch =
addedToCartObjectIDsAfterSearch.bind(this);
this.convertedObjectIDs = convertedObjectIDs.bind(this);
this.addedToCartObjectIDs = addedToCartObjectIDs.bind(this);
this.purchasedObjectIDs = purchasedObjectIDs.bind(this);
this.convertedFilters = convertedFilters.bind(this);
this.viewedObjectIDs = viewedObjectIDs.bind(this);
this.viewedFilters = viewedFilters.bind(this);
this.getVersion = getVersion.bind(this);
}
}
export default AlgoliaAnalytics;

View File

@@ -1,129 +0,0 @@
import type { addAlgoliaAgent } from "./_algoliaAgent";
import type { getVersion } from "./_getVersion";
import type { makeSendEvents } from "./_sendEvent";
import type {
getUserToken,
setUserToken,
onUserTokenChange
} from "./_tokenUtils";
import type {
clickedObjectIDsAfterSearch,
clickedObjectIDs,
clickedFilters
} from "./click";
import type {
convertedObjectIDsAfterSearch,
convertedObjectIDs,
convertedFilters,
purchasedObjectIDs,
purchasedObjectIDsAfterSearch,
addedToCartObjectIDsAfterSearch,
addedToCartObjectIDs
} from "./conversion";
import type { init } from "./init";
import type { viewedObjectIDs, viewedFilters } from "./view";
export type InsightsMethodMap = {
init: Parameters<typeof init>;
getVersion: Parameters<typeof getVersion>;
addAlgoliaAgent: Parameters<typeof addAlgoliaAgent>;
setUserToken: Parameters<typeof setUserToken>;
getUserToken: Parameters<typeof getUserToken>;
onUserTokenChange: Parameters<typeof onUserTokenChange>;
clickedObjectIDsAfterSearch: Parameters<typeof clickedObjectIDsAfterSearch>;
clickedObjectIDs: Parameters<typeof clickedObjectIDs>;
clickedFilters: Parameters<typeof clickedFilters>;
convertedObjectIDsAfterSearch: Parameters<
typeof convertedObjectIDsAfterSearch
>;
convertedObjectIDs: Parameters<typeof convertedObjectIDs>;
convertedFilters: Parameters<typeof convertedFilters>;
viewedObjectIDs: Parameters<typeof viewedObjectIDs>;
viewedFilters: Parameters<typeof viewedFilters>;
purchasedObjectIDs: Parameters<typeof purchasedObjectIDs>;
purchasedObjectIDsAfterSearch: Parameters<
typeof purchasedObjectIDsAfterSearch
>;
addedToCartObjectIDs: Parameters<typeof addedToCartObjectIDs>;
addedToCartObjectIDsAfterSearch: Parameters<
typeof addedToCartObjectIDsAfterSearch
>;
sendEvents: Parameters<ReturnType<typeof makeSendEvents>>;
};
type MethodType<MethodName extends keyof InsightsMethodMap> = (
method: MethodName,
...args: InsightsMethodMap[MethodName]
) => void;
export type Init = MethodType<"init">;
export type GetVersion = MethodType<"getVersion">;
export type AddAlgoliaAgent = MethodType<"addAlgoliaAgent">;
export type SetUserToken = MethodType<"setUserToken">;
export type GetUserToken = MethodType<"getUserToken">;
export type OnUserTokenChange = MethodType<"onUserTokenChange">;
export type ClickedObjectIDsAfterSearch =
MethodType<"clickedObjectIDsAfterSearch">;
export type ClickedObjectIDs = MethodType<"clickedObjectIDs">;
export type ClickedFilters = MethodType<"clickedFilters">;
export type ConvertedObjectIDsAfterSearch =
MethodType<"convertedObjectIDsAfterSearch">;
export type ConvertedObjectIDs = MethodType<"convertedObjectIDs">;
export type ConvertedFilters = MethodType<"convertedFilters">;
export type ViewedObjectIDs = MethodType<"viewedObjectIDs">;
export type ViewedFilters = MethodType<"viewedFilters">;
export type SendEvents = MethodType<"sendEvents">;
export type InsightsClient = (<MethodName extends keyof InsightsMethodMap>(
method: MethodName,
...args: InsightsMethodMap[MethodName]
) => void) & { version?: string };
export type InsightsEventType = "click" | "conversion" | "view";
export type InsightsEventConversionSubType = "addToCart" | "purchase";
export type InsightsEventObjectData = {
queryID?: string;
price?: number | string;
discount?: number | string;
quantity?: number;
};
export type InsightsEvent = {
eventType: InsightsEventType;
eventSubtype?: InsightsEventConversionSubType;
eventName: string;
userToken?: number | string;
timestamp?: number;
index: string;
queryID?: string;
objectIDs?: string[];
positions?: number[];
objectData?: InsightsEventObjectData[];
filters?: string[];
value?: number | string;
currency?: string;
};
export type InsightsAdditionalEventParams = {
headers?: Record<string, string>;
};

View File

@@ -1,4 +0,0 @@
declare module "*/package.json";
declare const __DEV__: boolean;
declare const __FLAVOR__: string;

View File

@@ -1,25 +0,0 @@
import type { InsightsAdditionalEventParams } from "../types";
export type WithAdditionalParams<TEventType> =
| InsightsAdditionalEventParams
| TEventType;
export function extractAdditionalParams<TEventType extends { index: string }>(
params: Array<InsightsAdditionalEventParams | TEventType>
): { events: TEventType[]; additionalParams?: InsightsAdditionalEventParams } {
return params.reduce(
({ events, additionalParams }, param) => {
// Real events all have `index` as a mandatory parameter, which we
// can rely on to distinguish them from additional parameters
if ("index" in param) {
return { additionalParams, events: [...events, param] };
}
return { events, additionalParams: param };
},
{
events: [] as TEventType[],
additionalParams: undefined as InsightsAdditionalEventParams | undefined
}
);
}

View File

@@ -1,35 +0,0 @@
export const supportsCookies = (): boolean => {
try {
return Boolean(navigator.cookieEnabled);
} catch (e) {
return false;
}
};
export const supportsSendBeacon = (): boolean => {
try {
return Boolean(navigator.sendBeacon);
} catch (e) {
return false;
}
};
export const supportsXMLHttpRequest = (): boolean => {
try {
return Boolean(XMLHttpRequest);
} catch (e) {
return false;
}
};
export const supportsNodeHttpModule = (): boolean => {
try {
/* eslint-disable @typescript-eslint/no-var-requires */
const { request: nodeHttpRequest } = require("http");
const { request: nodeHttpsRequest } = require("https");
/* eslint-enable */
return Boolean(nodeHttpRequest) && Boolean(nodeHttpsRequest);
} catch (e) {
return false;
}
};

View File

@@ -1,17 +0,0 @@
import { supportsSendBeacon, supportsXMLHttpRequest } from "./featureDetection";
import type { RequestFnType } from "./request";
import { requestWithSendBeacon, requestWithXMLHttpRequest } from "./request";
export function getRequesterForBrowser(): RequestFnType {
if (supportsSendBeacon()) {
return requestWithSendBeacon;
}
if (supportsXMLHttpRequest()) {
return requestWithXMLHttpRequest;
}
throw new Error(
"Could not find a supported HTTP request client in this environment."
);
}

View File

@@ -1,13 +0,0 @@
import { supportsNodeHttpModule } from "./featureDetection";
import type { RequestFnType } from "./request";
import { requestWithNodeHttpModule } from "./request";
export function getRequesterForNode(): RequestFnType {
if (supportsNodeHttpModule()) {
return requestWithNodeHttpModule;
}
throw new Error(
"Could not find a supported HTTP request client in this environment."
);
}

View File

@@ -1,15 +0,0 @@
// use theses type checking helpers to avoid mistyping "undefind", I mean "undfined"
export const isUndefined = (value: any): value is undefined =>
typeof value === "undefined";
export const isString = (value: any): value is string =>
typeof value === "string";
export const isNumber = (value: any): value is number =>
typeof value === "number";
/* eslint-disable @typescript-eslint/ban-types */
export const isFunction = (value: any): value is Function =>
typeof value === "function";
/* eslint-enable */
export * from "./extractAdditionalParams";
export * from "./featureDetection";

View File

@@ -1,80 +0,0 @@
import type { request as nodeRequest } from "http";
import type { UrlWithStringQuery } from "url";
export type RequestFnType = (
url: string,
data: Record<string, unknown>
) => Promise<boolean>;
export const requestWithXMLHttpRequest: RequestFnType = (url, data) => {
return new Promise((resolve, reject) => {
const serializedData = JSON.stringify(data);
const req = new XMLHttpRequest();
req.addEventListener("readystatechange", () => {
if (req.readyState === 4 && req.status === 200) {
resolve(true);
} else if (req.readyState === 4) {
resolve(false);
}
});
/* eslint-disable prefer-promise-reject-errors */
req.addEventListener("error", () => reject());
/* eslint-enable */
req.addEventListener("timeout", () => resolve(false));
req.open("POST", url);
req.setRequestHeader("Content-Type", "application/json");
req.setRequestHeader("Content-Length", `${serializedData.length}`);
req.send(serializedData);
});
};
export const requestWithSendBeacon: RequestFnType = (url, data) => {
const serializedData = JSON.stringify(data);
const beacon = navigator.sendBeacon(url, serializedData);
return Promise.resolve(beacon ? true : requestWithXMLHttpRequest(url, data));
};
export const requestWithNodeHttpModule: RequestFnType = (url, data) => {
return new Promise((resolve, reject) => {
const serializedData = JSON.stringify(data);
/* eslint-disable @typescript-eslint/no-var-requires */
const { protocol, host, path }: UrlWithStringQuery =
require("url").parse(url);
/* eslint-enable */
const options = {
protocol,
host,
path,
method: "POST",
headers: {
"Content-Type": "application/json",
"Content-Length": serializedData.length
}
};
const { request }: { request: typeof nodeRequest } = url.startsWith(
"https://"
)
? require("https")
: require("http");
const req = request(options, ({ statusCode }) => {
if (statusCode === 200) {
resolve(true);
} else {
resolve(false);
}
});
req.on("error", (error: any) => {
/* eslint-disable no-console */
console.error(error);
/* eslint-enable */
reject(error);
});
req.on("timeout", () => resolve(false));
req.write(serializedData);
req.end();
});
};

View File

@@ -1,15 +0,0 @@
/**
* Create UUID according to
* https://www.ietf.org/rfc/rfc4122.txt.
*
* @returns Generated UUID.
*/
export function createUUID(): string {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
/* eslint-disable no-bitwise */
const r = (Math.random() * 16) | 0;
const v = c === "x" ? r : (r & 0x3) | 0x8;
/* eslint-enable */
return v.toString(16);
});
}

View File

@@ -1,42 +0,0 @@
import { addEventType } from "./_addEventType";
import type AlgoliaAnalytics from "./insights";
import type { WithAdditionalParams } from "./utils";
import { extractAdditionalParams } from "./utils";
export interface InsightsSearchViewObjectIDsEvent {
eventName: string;
userToken?: string;
timestamp?: number;
index: string;
objectIDs: string[];
}
export function viewedObjectIDs(
this: AlgoliaAnalytics,
...params: Array<WithAdditionalParams<InsightsSearchViewObjectIDsEvent>>
): ReturnType<AlgoliaAnalytics["sendEvents"]> {
const { events, additionalParams } =
extractAdditionalParams<InsightsSearchViewObjectIDsEvent>(params);
return this.sendEvents(addEventType("view", events), additionalParams);
}
export interface InsightsSearchViewFiltersEvent {
eventName: string;
userToken?: string;
timestamp?: number;
index: string;
filters: string[];
}
export function viewedFilters(
this: AlgoliaAnalytics,
...params: Array<WithAdditionalParams<InsightsSearchViewFiltersEvent>>
): ReturnType<AlgoliaAnalytics["sendEvents"]> {
const { events, additionalParams } =
extractAdditionalParams<InsightsSearchViewFiltersEvent>(params);
return this.sendEvents(addEventType("view", events), additionalParams);
}

View File

@@ -1,88 +0,0 @@
{
"name": "search-insights",
"description": "Library for reporting click, conversion and view metrics using the Algolia Insights API",
"version": "2.8.3",
"jsdelivr": "dist/search-insights.min.js",
"main": "index-node.cjs.js",
"types": "index-node.cjs.d.ts",
"browser": "index-browser.cjs.js",
"react-native": {
"http": "./empty-module.cjs.js",
"https": "./empty-module.cjs.js"
},
"files": [
"dist",
"lib",
"!**/__tests__/**",
"empty-module.cjs.js",
"empty-module.cjs.d.ts",
"index-browser.cjs.d.ts",
"index-node.cjs.d.ts"
],
"scripts": {
"build": "rollup --environment NODE_ENV:'production' -c rollup.config.mjs && tsc --build tsconfig.declaration.json",
"build:dev": "rollup --watch --environment NODE_ENV:'development' -c rollup.config.mjs",
"lint": "eslint --ext .js,.ts,.tsx lib",
"lint:fix": "npm run lint -- --fix",
"prettier": "prettier 'lib/**/*.ts' 'docs/**/*.md' --write",
"test": "jest --runInBand",
"test:watch": "yarn test --watch",
"test:size": "bundlesize",
"toc": "markdown-toc -i --maxdepth=3 --bullets=\"-\" README.md",
"type-check": "tsc",
"type-check:watch": "yarn type-check --watch",
"release": "shipjs prepare"
},
"repository": {
"type": "git",
"url": "git+https://github.com/algolia/search-insights.js.git"
},
"author": {
"name": "Algolia",
"url": "https://www.algolia.com"
},
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.22.11",
"@babel/eslint-parser": "^7.22.11",
"@rollup/plugin-buble": "^1.0.2",
"@rollup/plugin-commonjs": "^25.0.4",
"@rollup/plugin-json": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.2.1",
"@rollup/plugin-replace": "^5.0.2",
"@rollup/plugin-typescript": "^11.1.3",
"@types/istanbul-reports": "^1.1.1",
"@types/jest": "^29.5.4",
"@types/jsdom": "^21.1.2",
"@types/node": "^20.5.7",
"@typescript-eslint/eslint-plugin": "^6.5.0",
"@typescript-eslint/parser": "^6.5.0",
"bundlesize2": "^0.0.31",
"eslint": "^8.48.0",
"eslint-config-algolia": "^22.0.0",
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-import": "^2.28.1",
"eslint-plugin-jsdoc": "^46.5.1",
"eslint-plugin-prettier": "^5.0.0",
"jest": "^29.6.4",
"jest-environment-jsdom": "^29.6.4",
"jest-localstorage-mock": "^2.4.26",
"jest-watch-typeahead": "^2.2.2",
"markdown-toc": "^1.2.0",
"prettier": "^3.0.3",
"rollup": "^3.28.1",
"rollup-plugin-filesize": "^10.0.0",
"rollup-plugin-uglify": "^6.0.4",
"shipjs": "^0.26.3",
"ts-jest": "^29.1.1",
"typescript": "^5.2.2"
},
"bundlesize": [
{
"path": "./dist/search-insights.min.js",
"maxSize": "2.95 kB"
}
],
"packageManager": "yarn@1.22.19"
}