@ginger-ai/ginger-js 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/dist/ginger.cjs.js +1 -1
- package/dist/ginger.cjs.js.map +1 -1
- package/dist/ginger.esm.js +1 -1
- package/dist/ginger.esm.js.map +1 -1
- package/dist/ginger.umd.js +1 -1
- package/dist/ginger.umd.js.map +1 -1
- package/package.json +1 -1
- package/src/behaviour/computeFieldInputMetrics.ts +106 -0
- package/src/behaviour/helpers.ts +60 -0
- package/src/behaviour/index.ts +202 -182
- package/src/client/index.ts +19 -11
- package/src/core/constants.ts +1 -1
- package/src/core/dto/metrics.dto.ts +8 -2
- package/src/core/helpers.ts +43 -3
- package/src/core/http/request.ts +2 -2
package/src/client/index.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
trackInputs,
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
trackingData,
|
|
4
|
+
removePageListener,
|
|
5
|
+
reset,
|
|
5
6
|
} from "../behaviour";
|
|
6
7
|
|
|
7
8
|
import { buildInitialPayload } from "../device";
|
|
@@ -23,10 +24,14 @@ import {
|
|
|
23
24
|
BehaviourPayloadResponseData,
|
|
24
25
|
} from "../core";
|
|
25
26
|
|
|
27
|
+
type EventPayload = {
|
|
28
|
+
event: BehaviourPayload;
|
|
29
|
+
};
|
|
30
|
+
|
|
26
31
|
interface GingerClient {
|
|
27
32
|
initialize(configs: Configurations): Promise<PayloadResponse | undefined>;
|
|
28
33
|
trackEvent(params: BehaviourParams): void;
|
|
29
|
-
getTrackedData():
|
|
34
|
+
getTrackedData(): EventPayload;
|
|
30
35
|
submitEvent(): Promise<BehaviourPayloadResponseData>;
|
|
31
36
|
}
|
|
32
37
|
|
|
@@ -43,7 +48,7 @@ export class GingerJsClient implements GingerClient {
|
|
|
43
48
|
|
|
44
49
|
async initialize() {
|
|
45
50
|
try {
|
|
46
|
-
const sdkInfo = { name:
|
|
51
|
+
const sdkInfo = { name: "@ginger-ai/ginger-js", version: "0.0.3" };
|
|
47
52
|
const payload = await buildInitialPayload(this.requestId, sdkInfo);
|
|
48
53
|
const response = await this.httpClient.post<Payload, PayloadResponse>({
|
|
49
54
|
url: `/api/v1/devices`,
|
|
@@ -99,13 +104,15 @@ export class GingerJsClient implements GingerClient {
|
|
|
99
104
|
);
|
|
100
105
|
}
|
|
101
106
|
|
|
102
|
-
const trackData =
|
|
107
|
+
const trackData = trackingData();
|
|
103
108
|
|
|
104
109
|
return {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
110
|
+
event: {
|
|
111
|
+
event_type: this.trackDetails.event_type,
|
|
112
|
+
request_id: this.trackDetails.request_id,
|
|
113
|
+
fingerprint_id: this.trackDetails.fingerprint_id,
|
|
114
|
+
data: { ...trackData },
|
|
115
|
+
},
|
|
109
116
|
};
|
|
110
117
|
};
|
|
111
118
|
|
|
@@ -117,11 +124,12 @@ export class GingerJsClient implements GingerClient {
|
|
|
117
124
|
|
|
118
125
|
try {
|
|
119
126
|
const response = await this.httpClient.post<
|
|
120
|
-
|
|
127
|
+
EventPayload,
|
|
121
128
|
BehaviourPayloadResponse
|
|
122
129
|
>({ url: `/api/v1/events`, payload });
|
|
123
130
|
|
|
124
|
-
|
|
131
|
+
removePageListener();
|
|
132
|
+
reset();
|
|
125
133
|
return response.data;
|
|
126
134
|
} catch (error) {
|
|
127
135
|
throw new GingerClientError(
|
package/src/core/constants.ts
CHANGED
|
@@ -12,9 +12,15 @@ export interface FieldMetrics {
|
|
|
12
12
|
started_at: number;
|
|
13
13
|
ended_at: number;
|
|
14
14
|
interaction_count: number;
|
|
15
|
-
|
|
15
|
+
characters_count: number;
|
|
16
16
|
paste_count: number;
|
|
17
|
+
autofill_count: number;
|
|
17
18
|
corrections_count: number;
|
|
18
19
|
pauses: number;
|
|
19
|
-
|
|
20
|
+
hesitation_time: number;
|
|
21
|
+
pause_durations: number[];
|
|
22
|
+
key_hold_times: number[];
|
|
23
|
+
modifier_key_count: number;
|
|
20
24
|
}
|
|
25
|
+
|
|
26
|
+
export type FocusMetrics = Record<string, number | null>
|
package/src/core/helpers.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { GingerClientError } from "./util/error";
|
|
|
4
4
|
export default function getBasePath(apikey: string) {
|
|
5
5
|
if (apikey.includes("sk_live") || apikey.includes("pk_live"))
|
|
6
6
|
return CONSTANTS.LIVE_URL;
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
return CONSTANTS.TEST_URL;
|
|
9
9
|
}
|
|
10
10
|
|
|
@@ -21,9 +21,9 @@ export const pageVisibility = () => {
|
|
|
21
21
|
|
|
22
22
|
return {
|
|
23
23
|
getCount: () => leaveCount,
|
|
24
|
-
|
|
24
|
+
addPageListener: () =>
|
|
25
25
|
document.addEventListener("visibilitychange", visibilityHandler),
|
|
26
|
-
|
|
26
|
+
removePageListener: () =>
|
|
27
27
|
document.removeEventListener("visibilitychange", visibilityHandler),
|
|
28
28
|
};
|
|
29
29
|
};
|
|
@@ -31,3 +31,43 @@ export const pageVisibility = () => {
|
|
|
31
31
|
export const validatePresence = (key: string) => {
|
|
32
32
|
if (!key) throw new GingerClientError("'apikey' must be provided.");
|
|
33
33
|
};
|
|
34
|
+
|
|
35
|
+
const getEncoderKey = (apikey: string): string => {
|
|
36
|
+
const last6 = apikey.slice(-6);
|
|
37
|
+
const secondCharacterAfterPrefix = apikey.split("_")[2]?.[1];
|
|
38
|
+
return last6 + secondCharacterAfterPrefix;
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
export const encode = (apikey: string, payload: unknown): string => {
|
|
42
|
+
try {
|
|
43
|
+
const key = getEncoderKey(apikey);
|
|
44
|
+
const data = JSON.stringify(payload);
|
|
45
|
+
|
|
46
|
+
let encoded = "";
|
|
47
|
+
|
|
48
|
+
for (let i = 0; i < data.length; i++) {
|
|
49
|
+
const keyChar = key.charCodeAt(i % key.length);
|
|
50
|
+
// eslint-disable-next-line no-bitwise
|
|
51
|
+
encoded += String.fromCharCode(data.charCodeAt(i) ^ keyChar);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
return btoa(encoded);
|
|
55
|
+
} catch (error) {
|
|
56
|
+
throw new Error("Encoding failed");
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
export const decode = (apikey: string, encoded: string): unknown => {
|
|
61
|
+
const key = getEncoderKey(apikey);
|
|
62
|
+
const decoded = atob(encoded);
|
|
63
|
+
|
|
64
|
+
let result = "";
|
|
65
|
+
|
|
66
|
+
for (let i = 0; i < decoded.length; i++) {
|
|
67
|
+
const keyChar = key.charCodeAt(i % key.length);
|
|
68
|
+
// eslint-disable-next-line no-bitwise
|
|
69
|
+
result += String.fromCharCode(decoded.charCodeAt(i) ^ keyChar);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
return JSON.parse(result);
|
|
73
|
+
};
|
package/src/core/http/request.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { encode } from "../helpers";
|
|
1
2
|
import { handleException } from "../util/error";
|
|
2
3
|
|
|
3
4
|
type Method = "POST" | "GET" | "PUT" | "DELETE";
|
|
@@ -8,7 +9,6 @@ export const makeRequest = async <Request, Response>(
|
|
|
8
9
|
method: Method,
|
|
9
10
|
apikey: string
|
|
10
11
|
): Promise<Response> => {
|
|
11
|
-
|
|
12
12
|
try {
|
|
13
13
|
const response = await fetch(url, {
|
|
14
14
|
method,
|
|
@@ -17,7 +17,7 @@ export const makeRequest = async <Request, Response>(
|
|
|
17
17
|
Accept: "application/json",
|
|
18
18
|
Authorization: `Bearer ${apikey}`,
|
|
19
19
|
},
|
|
20
|
-
body: JSON.stringify(payload),
|
|
20
|
+
body: JSON.stringify(encode(apikey, payload)),
|
|
21
21
|
});
|
|
22
22
|
|
|
23
23
|
if (!response.ok) {
|