Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/newjitsu' into newjitsu
Browse files Browse the repository at this point in the history
  • Loading branch information
absorbb committed Nov 27, 2024
2 parents e5a85cf + 9bdebd7 commit 2284e60
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 16 deletions.
1 change: 1 addition & 0 deletions libs/jitsu-js/__tests__/playwright/cases/reset.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
window.testOnload = async j => {
await j.setAnonymousId("john-doe-id-1");
await j.identify("john-nondoe", { email: "[email protected]" });
await j.identify("john-nondoe", { email: "[email protected]", $doNotSend: true });
await j.track("pageLoaded", { trackParam: "trackValue" });
await j.reset();
await j.track("pageLoaded", { trackParam: "trackValue" });
Expand Down
3 changes: 3 additions & 0 deletions libs/jitsu-js/__tests__/playwright/integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,9 @@ test("reset", async ({ browser }) => {
const newAnonymousId = cookies[0].value;
console.log(`🍪Cookies`, cookies);

//second identify call should not reach the server, but it should change the traits
expect(firstTrack.body.context.traits?.email).toEqual("[email protected]");

expect(secondTrack.body.anonymousId).not.toBeNull();
expect(secondTrack.body.anonymousId).toBeDefined();
expect(secondTrack.body.anonymousId).toEqual(newAnonymousId);
Expand Down
54 changes: 42 additions & 12 deletions libs/jitsu-js/src/analytics-plugin.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
/* global analytics */

import {
DynamicJitsuOptions,
JitsuOptions,
PersistentStorage,
RuntimeFacade,
AnalyticsClientEvent,
Callback,
DynamicJitsuOptions,
ErrorHandler,
ID,
JitsuOptions,
JSONObject,
Options,
ErrorHandler,
PersistentStorage,
RuntimeFacade,
Traits,
} from "@jitsu/protocols/analytics";
import parse from "./index";

Expand Down Expand Up @@ -635,13 +636,13 @@ function getErrorHandler(opts: JitsuOptions): ErrorHandler {
if (typeof configuredHandler === "function") {
return configuredHandler;
} else if (configuredHandler === "rethrow") {
return e => {
throw e;
return (msg, ...args) => {
//ignore args, not clear what to do with them
throw new Error(msg);
};
} else {
//"log" and unsupported value
return e => {
console.error(`[JITSU ERROR] ${e?.message || e?.toString() || "unknown error"}`, e);
return (msg, ...args) => {
console.error(msg, ...args);
};
}
}
Expand Down Expand Up @@ -701,7 +702,7 @@ async function send(
clearTimeout(abortTimeout);
}
} catch (e: any) {
getErrorHandler(jitsuConfig)(new Error(`Calling ${url} failed: ${e.message}`));
getErrorHandler(jitsuConfig)(`Call to ${url} failed with error ${e.message}`);
return Promise.resolve();
}
let responseText;
Expand Down Expand Up @@ -729,7 +730,7 @@ async function send(
try {
responseJson = JSON.parse(responseText);
} catch (e) {
getErrorHandler(jitsuConfig)(new Error(`Can't parse JSON: ${responseText}: ${e?.message}`));
getErrorHandler(jitsuConfig)(`Can't parse JSON: ${responseText}: ${e?.message}`);
return Promise.resolve();
}

Expand All @@ -752,6 +753,23 @@ async function send(
return adjustedPayload;
}

const controllingTraits = ["$doNotSend"] as const;
/**
* Remove all members of traits that controls identify/group behavior (see analytics.d.ts), and should not be recorded. Returns
* copy of the object with these members removed.
*
* Do not modify traits object, but creates one
* @param traits
*/
function stripControllingTraits(traits: Traits): Exclude<Traits, (typeof controllingTraits)[number]> {
const res = { ...traits };
// see Traits definition in analytics.d.ts. We cannot define const here, so here's a little code duplication
for (const key of controllingTraits) {
delete res[key];
}
return res;
}

export const jitsuAnalyticsPlugin = (jitsuOptions: JitsuOptions = {}, storage: PersistentStorage): AnalyticsPlugin => {
// just to make sure that all undefined values are replaced with defaultConfig values
mergeConfig(jitsuOptions, jitsuOptions);
Expand Down Expand Up @@ -814,9 +832,16 @@ export const jitsuAnalyticsPlugin = (jitsuOptions: JitsuOptions = {}, storage: P
}
// Store traits in cache to be able to use them in page and track events that run asynchronously with current identify.
storage.setItem("__user_id", payload.userId);
const doNotSend = payload.traits?.$doNotSend;
if (payload.traits && typeof payload.traits === "object") {
payload.traits = stripControllingTraits(payload.traits);
storage.setItem("__user_traits", payload.traits);
}
console.log("payload", payload);
console.log("do not send value", payload.traits?.$doNotSend);
if (doNotSend) {
return Promise.resolve();
}
return send("identify", payload, config, instance, storage);
},
reset: args => {
Expand Down Expand Up @@ -860,9 +885,14 @@ export const jitsuAnalyticsPlugin = (jitsuOptions: JitsuOptions = {}, storage: P
const userId = options?.userId || user?.userId;
const anonymousId = options?.anonymousId || user?.anonymousId || storage.getItem("__anon_id");
storage.setItem("__group_id", groupId);
const doNotSend = traits?.$doNotSend;
if (traits && typeof traits === "object") {
traits = stripControllingTraits(traits);
storage.setItem("__group_traits", traits);
}
if (doNotSend) {
return Promise.resolve();
}
return send(
"group",
{ type: "group", groupId, traits, ...(anonymousId ? { anonymousId } : {}), ...(userId ? { userId } : {}) },
Expand Down
19 changes: 15 additions & 4 deletions types/protocols/analytics.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ interface AnalyticsContext {

locale?: string;

library?: {
xlibrary?: {
name: string;
version: string;
//allow to add custom fields
Expand Down Expand Up @@ -316,7 +316,7 @@ export type RuntimeFacade = {
pageTitle(): string | undefined;
};

export type ErrorHandler = (error: any) => void;
export type ErrorHandler = (message: string, ...args: any[]) => void;

export type JitsuOptions = {
/**
Expand Down Expand Up @@ -389,6 +389,17 @@ export type JitsuOptions = {

export type DynamicJitsuOptions = Pick<JitsuOptions, "privacy" | "debug" | "echoEvents">;

export type Traits = {
[key: string]: JSONValue;
//some traits, all starting with $, are reserved for signalling the behavior of the event

/**
* Tells Jitsu to process event, but not send it to server. Used for .identify() and .group() calls
* that are intended to update user/group state, but not send events
*/
$doNotSend?: boolean;
};

export interface AnalyticsInterface {
track(
eventName: string | JSONObject,
Expand All @@ -407,12 +418,12 @@ export interface AnalyticsInterface {

group(
groupId?: ID | object,
traits?: JSONObject | null,
traits?: Traits | null,
options?: Options,
callback?: Callback
): Promise<DispatchedEvent>;

identify(id?: ID | object, traits?: JSONObject | Callback | null, callback?: Callback): Promise<DispatchedEvent>;
identify(id?: ID | Traits, traits?: Traits | Callback | null, callback?: Callback): Promise<DispatchedEvent>;

reset(callback?: (...params: any[]) => any): Promise<any>;

Expand Down

0 comments on commit 2284e60

Please sign in to comment.