give global properties __ prefix to easier find them
This commit is contained in:
@@ -42,7 +42,7 @@ function parsePath(path?: string): {
|
|||||||
return {
|
return {
|
||||||
query: parseSearchParams(url.searchParams),
|
query: parseSearchParams(url.searchParams),
|
||||||
path: url.pathname,
|
path: url.pathname,
|
||||||
hash: url.hash ?? undefined,
|
hash: url.hash || undefined,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return {
|
return {
|
||||||
@@ -69,15 +69,18 @@ export async function postEvent(
|
|||||||
reply: FastifyReply
|
reply: FastifyReply
|
||||||
) {
|
) {
|
||||||
let deviceId: string | null = null;
|
let deviceId: string | null = null;
|
||||||
const projectId = request.projectId;
|
const { projectId, body } = request;
|
||||||
const body = request.body;
|
const properties = body.properties ?? {};
|
||||||
|
const getProperty = (name: string): string | undefined => {
|
||||||
|
return (properties[name] as string | null | undefined) ?? undefined;
|
||||||
|
};
|
||||||
const profileId = body.profileId ?? '';
|
const profileId = body.profileId ?? '';
|
||||||
const createdAt = new Date(body.timestamp);
|
const createdAt = new Date(body.timestamp);
|
||||||
const url = body.properties?.path;
|
const url = getProperty('__path');
|
||||||
const { path, hash, query } = parsePath(url);
|
const { path, hash, query } = parsePath(url);
|
||||||
const referrer = isSameDomain(body.properties?.referrer, url)
|
const referrer = isSameDomain(getProperty('__referrer'), url)
|
||||||
? null
|
? null
|
||||||
: parseReferrer(body.properties?.referrer);
|
: parseReferrer(getProperty('__referrer'));
|
||||||
const utmReferrer = getReferrerWithQuery(query);
|
const utmReferrer = getReferrerWithQuery(query);
|
||||||
const ip = getClientIp(request)!;
|
const ip = getClientIp(request)!;
|
||||||
const origin = request.headers.origin!;
|
const origin = request.headers.origin!;
|
||||||
@@ -112,7 +115,14 @@ export async function postEvent(
|
|||||||
sessionId: event?.sessionId || '',
|
sessionId: event?.sessionId || '',
|
||||||
profileId,
|
profileId,
|
||||||
projectId,
|
projectId,
|
||||||
properties: body.properties ?? {},
|
properties: Object.assign(
|
||||||
|
{},
|
||||||
|
omit(['__path', '__referrer'], properties),
|
||||||
|
{
|
||||||
|
hash,
|
||||||
|
query,
|
||||||
|
}
|
||||||
|
),
|
||||||
createdAt,
|
createdAt,
|
||||||
country: event?.country ?? '',
|
country: event?.country ?? '',
|
||||||
city: event?.city ?? '',
|
city: event?.city ?? '',
|
||||||
@@ -205,7 +215,7 @@ export async function postEvent(
|
|||||||
profileId,
|
profileId,
|
||||||
projectId,
|
projectId,
|
||||||
sessionId: createSessionStart ? uuid() : sessionStartEvent?.sessionId ?? '',
|
sessionId: createSessionStart ? uuid() : sessionStartEvent?.sessionId ?? '',
|
||||||
properties: Object.assign({}, omit(['path', 'referrer'], body.properties), {
|
properties: Object.assign({}, omit(['__path', '__referrer'], properties), {
|
||||||
hash,
|
hash,
|
||||||
query,
|
query,
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -191,10 +191,6 @@ export async function createEvent(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (payload.properties.hash === '') {
|
|
||||||
delete payload.properties.hash;
|
|
||||||
}
|
|
||||||
|
|
||||||
const event: IClickhouseEvent = {
|
const event: IClickhouseEvent = {
|
||||||
id: uuid(),
|
id: uuid(),
|
||||||
name: payload.name,
|
name: payload.name,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import Constants from 'expo-constants';
|
|||||||
|
|
||||||
import type { MixanOptions } from '@mixan/sdk';
|
import type { MixanOptions } from '@mixan/sdk';
|
||||||
import { Mixan } from '@mixan/sdk';
|
import { Mixan } from '@mixan/sdk';
|
||||||
|
import type { PostEventPayload } from '@mixan/types';
|
||||||
|
|
||||||
type MixanNativeOptions = MixanOptions;
|
type MixanNativeOptions = MixanOptions;
|
||||||
|
|
||||||
@@ -24,19 +25,22 @@ export class MixanNative extends Mixan<MixanNativeOptions> {
|
|||||||
|
|
||||||
private async setProperties() {
|
private async setProperties() {
|
||||||
this.setGlobalProperties({
|
this.setGlobalProperties({
|
||||||
version: Application.nativeApplicationVersion,
|
__version: Application.nativeApplicationVersion,
|
||||||
buildNumber: Application.nativeBuildVersion,
|
__buildNumber: Application.nativeBuildVersion,
|
||||||
referrer:
|
__referrer:
|
||||||
Platform.OS === 'android'
|
Platform.OS === 'android'
|
||||||
? await Application.getInstallReferrerAsync()
|
? await Application.getInstallReferrerAsync()
|
||||||
: undefined,
|
: undefined,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public screenView(route: string, properties?: Record<string, unknown>): void {
|
public screenView(
|
||||||
|
route: string,
|
||||||
|
properties?: PostEventPayload['properties']
|
||||||
|
): void {
|
||||||
super.event('screen_view', {
|
super.event('screen_view', {
|
||||||
...properties,
|
...properties,
|
||||||
path: route,
|
__path: route,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
import Script from 'next/script';
|
import Script from 'next/script';
|
||||||
|
|
||||||
import type { MixanEventOptions } from '@mixan/sdk';
|
|
||||||
import type { MixanWebOptions } from '@mixan/sdk-web';
|
import type { MixanWebOptions } from '@mixan/sdk-web';
|
||||||
import type { UpdateProfilePayload } from '@mixan/types';
|
import type {
|
||||||
|
MixanEventOptions,
|
||||||
|
PostEventPayload,
|
||||||
|
UpdateProfilePayload,
|
||||||
|
} from '@mixan/types';
|
||||||
|
|
||||||
const CDN_URL = 'http://localhost:3002/op.js';
|
const CDN_URL = 'http://localhost:3002/op.js';
|
||||||
|
|
||||||
@@ -73,11 +76,14 @@ export function SetProfileId({ value }: SetProfileIdProps) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function trackEvent(name: string, data?: Record<string, unknown>) {
|
export function trackEvent(
|
||||||
|
name: string,
|
||||||
|
data?: PostEventPayload['properties']
|
||||||
|
) {
|
||||||
window.op('event', name, data);
|
window.op('event', name, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function trackScreenView(data?: Record<string, unknown>) {
|
export function trackScreenView(data?: PostEventPayload['properties']) {
|
||||||
trackEvent('screen_view', data);
|
trackEvent('screen_view', data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import type { MixanOptions } from '@mixan/sdk';
|
import type { MixanOptions } from '@mixan/sdk';
|
||||||
import { Mixan } from '@mixan/sdk';
|
import { Mixan } from '@mixan/sdk';
|
||||||
|
import type { PostEventPayload } from '@mixan/types';
|
||||||
|
|
||||||
export type MixanWebOptions = MixanOptions & {
|
export type MixanWebOptions = MixanOptions & {
|
||||||
trackOutgoingLinks?: boolean;
|
trackOutgoingLinks?: boolean;
|
||||||
@@ -22,7 +23,7 @@ export class MixanWeb extends Mixan<MixanWebOptions> {
|
|||||||
|
|
||||||
if (!this.isServer()) {
|
if (!this.isServer()) {
|
||||||
this.setGlobalProperties({
|
this.setGlobalProperties({
|
||||||
referrer: document.referrer,
|
__referrer: document.referrer,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (this.options.trackOutgoingLinks) {
|
if (this.options.trackOutgoingLinks) {
|
||||||
@@ -134,7 +135,7 @@ export class MixanWeb extends Mixan<MixanWebOptions> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public screenView(properties?: Record<string, unknown>): void {
|
public screenView(properties?: PostEventPayload['properties']): void {
|
||||||
if (this.isServer()) {
|
if (this.isServer()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -148,8 +149,8 @@ export class MixanWeb extends Mixan<MixanWebOptions> {
|
|||||||
this.lastPath = path;
|
this.lastPath = path;
|
||||||
super.event('screen_view', {
|
super.event('screen_view', {
|
||||||
...(properties ?? {}),
|
...(properties ?? {}),
|
||||||
path,
|
__path: path,
|
||||||
title: document.title,
|
__title: document.title,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import type {
|
import type {
|
||||||
DecrementProfilePayload,
|
DecrementProfilePayload,
|
||||||
IncrementProfilePayload,
|
IncrementProfilePayload,
|
||||||
|
MixanEventOptions,
|
||||||
PostEventPayload,
|
PostEventPayload,
|
||||||
UpdateProfilePayload,
|
UpdateProfilePayload,
|
||||||
} from '@mixan/types';
|
} from '@mixan/types';
|
||||||
@@ -21,10 +22,6 @@ export interface MixanState {
|
|||||||
properties: Record<string, unknown>;
|
properties: Record<string, unknown>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface MixanEventOptions {
|
|
||||||
profileId?: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function awaitProperties(
|
function awaitProperties(
|
||||||
properties: Record<string, string | Promise<string | null>>
|
properties: Record<string, string | Promise<string | null>>
|
||||||
): Promise<Record<string, string>> {
|
): Promise<Record<string, string>> {
|
||||||
@@ -168,10 +165,7 @@ export class Mixan<Options extends MixanOptions = MixanOptions> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public event(
|
public event(name: string, properties?: PostEventPayload['properties']) {
|
||||||
name: string,
|
|
||||||
properties?: Record<string, unknown> & MixanEventOptions
|
|
||||||
) {
|
|
||||||
const profileId = properties?.profileId ?? this.state.profileId;
|
const profileId = properties?.profileId ?? this.state.profileId;
|
||||||
delete properties?.profileId;
|
delete properties?.profileId;
|
||||||
this.api
|
this.api
|
||||||
@@ -200,7 +194,6 @@ export class Mixan<Options extends MixanOptions = MixanOptions> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public clear() {
|
public clear() {
|
||||||
this.state.properties = {};
|
|
||||||
this.state.deviceId = undefined;
|
this.state.deviceId = undefined;
|
||||||
this.state.profileId = undefined;
|
this.state.profileId = undefined;
|
||||||
if (this.options.removeDeviceId) {
|
if (this.options.removeDeviceId) {
|
||||||
|
|||||||
@@ -1,360 +0,0 @@
|
|||||||
import type {
|
|
||||||
EventPayload,
|
|
||||||
MixanErrorResponse,
|
|
||||||
ProfilePayload,
|
|
||||||
} from '@mixan/types';
|
|
||||||
|
|
||||||
export interface NewMixanOptions {
|
|
||||||
url: string;
|
|
||||||
clientId: string;
|
|
||||||
clientSecret: string;
|
|
||||||
batchInterval?: number;
|
|
||||||
maxBatchSize?: number;
|
|
||||||
sessionTimeout?: number;
|
|
||||||
session?: boolean;
|
|
||||||
verbose?: boolean;
|
|
||||||
profile?: boolean;
|
|
||||||
trackIp?: boolean;
|
|
||||||
setItem: (key: string, profileId: string) => void;
|
|
||||||
getItem: (key: string) => string | null;
|
|
||||||
removeItem: (key: string) => void;
|
|
||||||
}
|
|
||||||
export type MixanOptions = Required<NewMixanOptions>;
|
|
||||||
|
|
||||||
class Fetcher {
|
|
||||||
private url: string;
|
|
||||||
private clientId: string;
|
|
||||||
private clientSecret: string;
|
|
||||||
private logger: (...args: any[]) => void;
|
|
||||||
|
|
||||||
constructor(options: MixanOptions) {
|
|
||||||
this.url = options.url;
|
|
||||||
this.clientId = options.clientId;
|
|
||||||
this.clientSecret = options.clientSecret;
|
|
||||||
this.logger = options.verbose ? console.log : () => {};
|
|
||||||
}
|
|
||||||
|
|
||||||
post<PostData, PostResponse>(
|
|
||||||
path: string,
|
|
||||||
data?: PostData,
|
|
||||||
options?: RequestInit
|
|
||||||
): Promise<PostResponse | null> {
|
|
||||||
const url = `${this.url}${path}`;
|
|
||||||
this.logger(`Mixan request: ${url}`, JSON.stringify(data, null, 2));
|
|
||||||
|
|
||||||
return fetch(url, {
|
|
||||||
headers: {
|
|
||||||
['mixan-client-id']: this.clientId,
|
|
||||||
['mixan-client-secret']: this.clientSecret,
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify(data ?? {}),
|
|
||||||
keepalive: true,
|
|
||||||
...(options ?? {}),
|
|
||||||
})
|
|
||||||
.then(async (res) => {
|
|
||||||
const response = (await res.json()) as
|
|
||||||
| MixanErrorResponse
|
|
||||||
| PostResponse;
|
|
||||||
|
|
||||||
if (!response) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
typeof response === 'object' &&
|
|
||||||
'status' in response &&
|
|
||||||
response.status === 'error'
|
|
||||||
) {
|
|
||||||
this.logger(
|
|
||||||
`Mixan request failed: [${options?.method ?? 'POST'}] ${url}`,
|
|
||||||
JSON.stringify(response, null, 2)
|
|
||||||
);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return response as PostResponse;
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
this.logger(
|
|
||||||
`Mixan request failed: [${options?.method ?? 'POST'}] ${url}`
|
|
||||||
);
|
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
class Batcher<T> {
|
|
||||||
queue: T[] = [];
|
|
||||||
timer?: ReturnType<typeof setTimeout>;
|
|
||||||
callback: (queue: T[]) => void;
|
|
||||||
maxBatchSize: number;
|
|
||||||
batchInterval: number;
|
|
||||||
|
|
||||||
constructor(options: MixanOptions, callback: (queue: T[]) => void) {
|
|
||||||
this.callback = callback;
|
|
||||||
this.maxBatchSize = options.maxBatchSize;
|
|
||||||
this.batchInterval = options.batchInterval;
|
|
||||||
}
|
|
||||||
|
|
||||||
add(payload: T) {
|
|
||||||
this.queue.push(payload);
|
|
||||||
this.flush();
|
|
||||||
}
|
|
||||||
|
|
||||||
flush() {
|
|
||||||
if (this.timer) {
|
|
||||||
clearTimeout(this.timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.queue.length === 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.queue.length >= this.maxBatchSize) {
|
|
||||||
this.send();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.timer = setTimeout(this.send.bind(this), this.batchInterval);
|
|
||||||
}
|
|
||||||
|
|
||||||
send() {
|
|
||||||
if (this.timer) {
|
|
||||||
clearTimeout(this.timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.queue.length > 0) {
|
|
||||||
this.callback(this.queue);
|
|
||||||
this.queue = [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Mixan {
|
|
||||||
private fetch: Fetcher;
|
|
||||||
private eventBatcher: Batcher<EventPayload>;
|
|
||||||
private profileId?: string;
|
|
||||||
private options: MixanOptions;
|
|
||||||
private logger: (...args: any[]) => void;
|
|
||||||
private globalProperties: Record<string, unknown> = {};
|
|
||||||
private lastEventAt: string;
|
|
||||||
private promiseIp: Promise<string | null>;
|
|
||||||
|
|
||||||
constructor(options: NewMixanOptions) {
|
|
||||||
this.logger = options.verbose ? console.log : () => {};
|
|
||||||
this.options = {
|
|
||||||
sessionTimeout: 1000 * 60 * 30,
|
|
||||||
session: true,
|
|
||||||
verbose: false,
|
|
||||||
batchInterval: 10000,
|
|
||||||
maxBatchSize: 10,
|
|
||||||
trackIp: false,
|
|
||||||
profile: true,
|
|
||||||
...options,
|
|
||||||
};
|
|
||||||
|
|
||||||
this.lastEventAt =
|
|
||||||
this.options.getItem('@mixan:lastEventAt') ?? '1970-01-01';
|
|
||||||
this.fetch = new Fetcher(this.options);
|
|
||||||
this.eventBatcher = new Batcher(this.options, (queue) => {
|
|
||||||
this.fetch.post(
|
|
||||||
'/events',
|
|
||||||
queue.map((item) => ({
|
|
||||||
...item,
|
|
||||||
properties: {
|
|
||||||
...this.globalProperties,
|
|
||||||
...item.properties,
|
|
||||||
},
|
|
||||||
profileId: item.profileId ?? this.profileId ?? null,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.promiseIp = this.options.trackIp
|
|
||||||
? fetch('https://api.ipify.org')
|
|
||||||
.then((res) => res.text())
|
|
||||||
.catch(() => null)
|
|
||||||
: Promise.resolve(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
async ip() {
|
|
||||||
return this.promiseIp;
|
|
||||||
}
|
|
||||||
|
|
||||||
timestamp(modify = 0) {
|
|
||||||
return new Date(Date.now() + modify).toISOString();
|
|
||||||
}
|
|
||||||
|
|
||||||
init(properties?: Record<string, unknown>) {
|
|
||||||
if (properties) {
|
|
||||||
this.setGlobalProperties(properties);
|
|
||||||
}
|
|
||||||
this.logger('Mixan: Init');
|
|
||||||
this.setAnonymousUser();
|
|
||||||
}
|
|
||||||
|
|
||||||
event(name: string, properties: Record<string, unknown> = {}) {
|
|
||||||
const now = new Date();
|
|
||||||
const isSessionStart =
|
|
||||||
this.options.session &&
|
|
||||||
now.getTime() - new Date(this.lastEventAt).getTime() >
|
|
||||||
this.options.sessionTimeout;
|
|
||||||
|
|
||||||
if (isSessionStart) {
|
|
||||||
this.logger('Mixan: Session start');
|
|
||||||
this.eventBatcher.add({
|
|
||||||
name: 'session_start',
|
|
||||||
time: this.timestamp(-10),
|
|
||||||
properties: {},
|
|
||||||
profileId: this.profileId ?? null,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger('Mixan: Queue event', name);
|
|
||||||
this.eventBatcher.add({
|
|
||||||
name,
|
|
||||||
properties,
|
|
||||||
time: this.timestamp(),
|
|
||||||
profileId: this.profileId ?? null,
|
|
||||||
});
|
|
||||||
this.lastEventAt = this.timestamp();
|
|
||||||
this.options.setItem('@mixan:lastEventAt', this.lastEventAt);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async setAnonymousUser(retryCount = 0) {
|
|
||||||
if (!this.options.profile) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const profileId = this.options.getItem('@mixan:profileId');
|
|
||||||
if (profileId) {
|
|
||||||
this.profileId = profileId;
|
|
||||||
await this.setUser({
|
|
||||||
properties: this.globalProperties,
|
|
||||||
});
|
|
||||||
this.logger('Mixan: Use existing profile', this.profileId);
|
|
||||||
} else {
|
|
||||||
const res = await this.fetch.post<ProfilePayload, { id: string }>(
|
|
||||||
'/profiles',
|
|
||||||
{
|
|
||||||
properties: this.globalProperties,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (res) {
|
|
||||||
this.profileId = res.id;
|
|
||||||
this.options.setItem('@mixan:profileId', res.id);
|
|
||||||
this.logger('Mixan: Create new profile', this.profileId);
|
|
||||||
} else if (retryCount < 2) {
|
|
||||||
setTimeout(() => {
|
|
||||||
this.setAnonymousUser(retryCount + 1);
|
|
||||||
}, 500);
|
|
||||||
} else {
|
|
||||||
this.logger('Mixan: Failed to create new profile');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async setUser(profile: ProfilePayload) {
|
|
||||||
if (!this.options.profile) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.profileId) {
|
|
||||||
return this.logger('Mixan: Set user failed, no profileId');
|
|
||||||
}
|
|
||||||
this.logger('Mixan: Set user', profile);
|
|
||||||
await this.fetch.post(`/profiles/${this.profileId}`, profile, {
|
|
||||||
method: 'PUT',
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
async setUserProperty(
|
|
||||||
name: string,
|
|
||||||
value: string | number | boolean | Record<string, unknown> | unknown[]
|
|
||||||
) {
|
|
||||||
if (!this.options.profile) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.profileId) {
|
|
||||||
return this.logger('Mixan: Set user property, no profileId');
|
|
||||||
}
|
|
||||||
this.logger('Mixan: Set user property', name, value);
|
|
||||||
await this.fetch.post(`/profiles/${this.profileId}`, {
|
|
||||||
properties: {
|
|
||||||
[name]: value,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
setGlobalProperties(properties: Record<string, unknown>) {
|
|
||||||
if (typeof properties !== 'object') {
|
|
||||||
return this.logger(
|
|
||||||
'Mixan: Set global properties failed, properties must be an object'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.logger('Mixan: Set global properties', properties);
|
|
||||||
this.globalProperties = {
|
|
||||||
...this.globalProperties,
|
|
||||||
...properties,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
async increment(name: string, value = 1) {
|
|
||||||
if (!this.options.profile) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.profileId) {
|
|
||||||
this.logger('Mixan: Increment failed, no profileId');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger('Mixan: Increment user property', name, value);
|
|
||||||
await this.fetch.post(
|
|
||||||
`/profiles/${this.profileId}/increment`,
|
|
||||||
{
|
|
||||||
name,
|
|
||||||
value,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: 'PUT',
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async decrement(name: string, value = 1) {
|
|
||||||
if (!this.options.profile) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!this.profileId) {
|
|
||||||
this.logger('Mixan: Decrement failed, no profileId');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.logger('Mixan: Decrement user property', name, value);
|
|
||||||
await this.fetch.post(
|
|
||||||
`/profiles/${this.profileId}/decrement`,
|
|
||||||
{
|
|
||||||
name,
|
|
||||||
value,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
method: 'PUT',
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
flush() {
|
|
||||||
this.logger('Mixan: Flushing events queue');
|
|
||||||
this.eventBatcher.send();
|
|
||||||
}
|
|
||||||
|
|
||||||
clear() {
|
|
||||||
this.logger('Mixan: Clear, send remaining events and remove profileId');
|
|
||||||
this.eventBatcher.send();
|
|
||||||
this.options.removeItem('@mixan:profileId');
|
|
||||||
this.options.removeItem('@mixan:lastEventAt');
|
|
||||||
this.profileId = undefined;
|
|
||||||
this.setAnonymousUser();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -134,16 +134,16 @@ export interface MixanResponse<T> {
|
|||||||
|
|
||||||
// NEW
|
// NEW
|
||||||
|
|
||||||
|
export interface MixanEventOptions {
|
||||||
|
profileId?: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface PostEventPayload {
|
export interface PostEventPayload {
|
||||||
name: string;
|
name: string;
|
||||||
timestamp: string;
|
timestamp: string;
|
||||||
deviceId?: string;
|
deviceId?: string;
|
||||||
profileId?: string;
|
profileId?: string;
|
||||||
properties?: Record<string, unknown> & {
|
properties?: Record<string, unknown> & MixanEventOptions;
|
||||||
title?: string | undefined;
|
|
||||||
referrer?: string | undefined;
|
|
||||||
path?: string | undefined;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface UpdateProfilePayload {
|
export interface UpdateProfilePayload {
|
||||||
|
|||||||
Reference in New Issue
Block a user