Skip to content
This repository was archived by the owner on Aug 2, 2023. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 26 additions & 20 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,20 +1,26 @@
# Visual Studio Code temporary files
.vscode/

# Build results
build/

# npm packages
node_modules

# npm logs
npm-debug.log*

# yarn uses its own yarn.lock file
package-lock.json

# yarn logs
yarn-error.log

# chrome debug
debug.log
# Visual Studio Code temporary files
.vscode/

# Build results
build/
clarity.js
decode.js
docs

# npm packages
.rpt2_cache

# npm packages
node_modules

# npm logs
npm-debug.log*

# yarn uses its own yarn.lock file
package-lock.json

# yarn logs
yarn-error.log

# chrome debug
debug.log
146 changes: 117 additions & 29 deletions src/clarity.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,117 @@
import { IConfig } from "@clarity-types/config";
import { State } from "@clarity-types/core";
import { config } from "./config";
import { activate, onCustomEvent, onSetPageInfo, onTrigger, state, teardown } from "./core";
import { mapProperties } from "./utils";
export { version } from "./core";

export function start(customConfig?: IConfig): void {
if (state !== State.Activated) {
mapProperties(customConfig, null, true, config);
activate();
}
}

export function stop(): void {
teardown();
}

export function trigger(key: string): void {
onTrigger(key);
}

export function event(kvps: { [key: string]: any }): void {
onCustomEvent(kvps);
}

export function setPageInfo(pageId: string, userId: string): void {
onSetPageInfo(pageId, userId);
}
import { Config } from "@clarity-types/core";
import * as core from "@src/core";
import configuration from "@src/core/config";
import { bind } from "@src/core/event";
import measure from "@src/core/measure";
import * as task from "@src/core/task";
import * as data from "@src/data";
import * as diagnostic from "@src/diagnostic";
import * as interaction from "@src/interaction";
import * as layout from "@src/layout";
import * as performance from "@src/performance";

const CLARITY = "clarity";
let status = false;
/**
* Configures clarity Starts the appl
* @param override options to start the application with
* @returns true if config acepted
*/
export function config(override: Config): boolean {
// Process custom configuration overrides, if available
if (status) { return false; }
for (let key in override) {
if (key in configuration) { configuration[key] = override[key]; }
}
return true;
}

export function start(override: Config = {}): void {
// Check that browser supports required APIs
// And, also that we are not attempting to start Clarity multiple times
if (core.check() && status === false) {
config(override);
status = true;

core.start();
data.start();
measure(diagnostic.start)();
measure(layout.start)();
measure(interaction.start)();
measure(performance.start)();
}
}

function restart(): void {
start();
tag(CLARITY, "restart");
}

// Suspend ends the current Clarity instance after a configured timeout period
// The way it differs from the "end" call is that it starts listening to
// user interaction events as soon as it terminates existing clarity instance.
// On the next interaction, it automatically starts another instance under a different page id
// E.g. if configured timeout is 10m, and user stays inactive for an hour.
// In this case, we will suspend clarity after 10m of inactivity and after another 50m when user interacts again
// Clarity will restart and start another instance seamlessly. Effectively not missing any active time, but also
// not holding the session during inactive time periods.
export function suspend(): void {
tag(CLARITY, "suspend");
end();
bind(document, "mousemove", restart);
bind(document, "touchstart", restart);
bind(window, "resize", restart);
bind(window, "scroll", restart);
bind(window, "pageshow", restart);
}

// By default Clarity is asynchronous and will yield by looking for requestIdleCallback.
// However, there can still be situations with single page apps where a user action can result
// in the whole DOM being destroyed and reconstructed. While Clarity will performan favorably out of the box,
// we do allow external clients to manually pause Clarity for that short burst of time and minimize
// performance impact even further. For reference, we are talking 10s of milliseconds optimization here, not seconds.
export function pause(): void {
if (status) {
tag(CLARITY, "pause");
task.pause();
}
}

// This is how external clients can get out of pause state, and resume Clarity to continue monitoring the page
export function resume(): void {
if (status) {
task.resume();
tag(CLARITY, "resume");
}
}

export function end(): void {
if (status) {
measure(performance.end)();
measure(interaction.end)();
measure(layout.end)();
measure(diagnostic.end)();
data.end();
core.end();

status = false;
}
}

export function tag(key: string, value: string): void {
// Do not process tags if Clarity is not already activated
if (status) {
measure(data.tag)(key, value);
}
}

export function upgrade(key: string): void {
// Do not process upgrade call if Clarity is not already activated and in lean mode
if (status && configuration.lean) {
measure(data.upgrade)(key);
}
}

export function active(): boolean {
return status;
}
50 changes: 26 additions & 24 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"lib": ["es2015", "dom"],
"noImplicitAny": true,
"noUnusedLocals": true,
"suppressImplicitAnyIndexErrors": true,
"baseUrl": ".",
"paths": {
"@src/*": ["src/*"],
"@karma/*": ["karma/*"],
"@clarity-types/*": ["types/*"]
}
},
"include":[
"src/**/*.ts",
"types/**/*.d.ts",
"karma/**/*.ts",
],
"atom": {
"rewriteTsconfig": false
}
}
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"lib": ["es2015", "dom"],
"noImplicitAny": true,
"noUnusedLocals": true,
"suppressImplicitAnyIndexErrors": true,
"baseUrl": ".",
"paths": {
"@src/*": ["src/*"],
"@decode/*": ["decode/*"],
"@karma/*": ["karma/*"],
"@clarity-types/*": ["types/*"]
}
},
"include":[
"src/**/*.ts",
"decode/**/*.ts",
"types/**/*.d.ts",
"karma/**/*.ts",
],
"atom": {
"rewriteTsconfig": false
}
}