@sesamy/sesamy-js 1.0.0 → 1.0.1

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.
@@ -1,124 +0,0 @@
1
- import { onUserActivity } from "@analytics/activity-utils";
2
-
3
- // IDLE_TIME is in ms
4
- const timeout = 5000;
5
-
6
- export interface ElementTrackerOptions {
7
- element: HTMLElement;
8
- viewCallback?: () => void;
9
- activeDurationCallback?: (duration: number) => void;
10
- idleDurationCallback?: (duration: number) => void;
11
- }
12
-
13
- export default class ElementTracker {
14
- element: HTMLElement;
15
-
16
- isInViewport = false;
17
-
18
- isAwake = false;
19
-
20
- isFlushing?: boolean;
21
-
22
- observer: IntersectionObserver;
23
-
24
- lastEventAt = Date.now();
25
-
26
- registeredView = false;
27
-
28
- viewCallback?: () => void;
29
-
30
- activeDurationCallback?: (duration: number, flushing?: boolean) => void;
31
-
32
- idleDurationCallback?: (duration: number, flushing?: boolean) => void;
33
-
34
- constructor(options: ElementTrackerOptions) {
35
- this.element = options.element;
36
- // We NEED to have callbacks here rather than using events as events will be lost when the browser is unloading
37
- this.viewCallback = options.viewCallback;
38
- this.activeDurationCallback = options.activeDurationCallback;
39
- this.idleDurationCallback = options.idleDurationCallback;
40
-
41
- // Setup the interaction observer
42
- this.observer = new IntersectionObserver(
43
- (entries) => {
44
- // I guess there will only be one entry? Verify?
45
- entries.forEach((entry) => {
46
- this.handleInViewPort(entry.isIntersecting);
47
- });
48
- },
49
- {
50
- threshold: 0,
51
- },
52
- );
53
- this.observer.observe(this.element);
54
-
55
- // Setup the active/idle
56
- onUserActivity({
57
- onIdle: (elapsedTime: number) => this.handleAwake(false, elapsedTime),
58
- onWakeUp: (elapsedTime: number) => this.handleAwake(true, elapsedTime),
59
- timeout,
60
- });
61
- }
62
-
63
- /**
64
- * Flush the awake timer in case the page is unloading
65
- */
66
- flush() {
67
- this.isFlushing = true;
68
- this.handleAwake(
69
- !this.isAwake,
70
- Math.round((Date.now() - this.lastEventAt) / 1000),
71
- );
72
- }
73
-
74
- handleInViewPort(isInViewport: boolean) {
75
- if (isInViewport) {
76
- // A view envent only occurs if the element is active.
77
- this.isAwake = true;
78
- this.trackInViewport();
79
- } else {
80
- // An article outside the viewport is not active
81
- this.handleAwake(
82
- false,
83
- Math.round((Date.now() - this.lastEventAt) / 1000),
84
- );
85
- }
86
-
87
- this.isInViewport = isInViewport;
88
- }
89
-
90
- handleAwake(isAwake: boolean, elapsedTime: number) {
91
- // Store the current awake state
92
- this.isAwake = isAwake;
93
- this.lastEventAt = isAwake
94
- ? Date.now() - elapsedTime * timeout
95
- : Date.now();
96
-
97
- if (!this.isInViewport) {
98
- return;
99
- }
100
- this.trackAwake(isAwake, elapsedTime);
101
- }
102
-
103
- trackAwake(awake: boolean, elapsedTime: number) {
104
- if (!awake && this.activeDurationCallback) {
105
- this.activeDurationCallback(elapsedTime, this.isFlushing);
106
- }
107
-
108
- if (awake && this.idleDurationCallback) {
109
- this.idleDurationCallback(elapsedTime, this.isFlushing);
110
- }
111
- }
112
-
113
- trackInViewport() {
114
- if (this.registeredView) {
115
- return;
116
- }
117
-
118
- this.registeredView = true;
119
-
120
- if (this.viewCallback) {
121
- this.viewCallback();
122
- }
123
- }
124
- }
@@ -1,214 +0,0 @@
1
- import Analytics, { AnalyticsInstance } from "analytics";
2
- import saturated from "saturated";
3
- import { name, version } from "../../../package.json";
4
- import { TrackEvent } from "./types/track-event";
5
- import { AnalyticsConfig } from "../../types/Config";
6
- import { routeChangeListener } from "./listeners";
7
- import ElementTracker from "./element-tracker";
8
- import { ANALYTICS_BASE_URL } from "../../constants";
9
-
10
- type Analytic = {
11
- anonymousId: string;
12
- userId?: string;
13
- properties: { [key: string]: string | number };
14
- event: string;
15
- type: string;
16
- };
17
-
18
- let flushing = false;
19
-
20
- let _clientId: string;
21
- let _enabled: boolean;
22
- let _endpoint: string;
23
-
24
- export interface AnalyticsEventWithType extends Analytic {
25
- type: string;
26
- }
27
-
28
- export function initAnalytics({
29
- clientId,
30
- enabled = true,
31
- endpoint = ANALYTICS_BASE_URL,
32
- }: AnalyticsConfig) {
33
- _clientId = clientId;
34
- _enabled = enabled;
35
- _endpoint = endpoint;
36
-
37
- if (!_enabled) {
38
- return;
39
- }
40
-
41
- // Register route change listener
42
- routeChangeListener();
43
-
44
- // Register body events
45
- const bodyTracker = new ElementTracker({
46
- element: document.body,
47
- viewCallback: () => {
48
- analytics.page();
49
- },
50
- activeDurationCallback: (duration: number, flushing?: boolean) => {
51
- analytics.track("activeDuration", {
52
- duration,
53
- flushing,
54
- });
55
- },
56
- idleDurationCallback: (duration: number, flushing?: boolean) => {
57
- analytics.track("idleDuration", {
58
- duration,
59
- flushing,
60
- });
61
- },
62
- });
63
-
64
- addUnloadPageListener(document.body, () => {
65
- bodyTracker.flush();
66
- });
67
- }
68
-
69
- function createMessage(payload: AnalyticsEventWithType[]): string {
70
- return JSON.stringify(
71
- payload.map((item) => ({
72
- ...item,
73
- timestamp: new Date().toISOString(),
74
- originalTimestamp: new Date().toISOString(),
75
- version,
76
- event: item.event || "page",
77
- context: {
78
- page: {
79
- url: window.location.hostname,
80
- path: window.location.pathname,
81
- title: document.title,
82
- search: window.location.search,
83
- referrer: document.referrer,
84
- },
85
- locale: navigator.language,
86
- library: name,
87
- userAgent: navigator.userAgent,
88
- clientId: _clientId,
89
- },
90
- })),
91
- );
92
- }
93
-
94
- const queue = saturated(
95
- async (arr) => {
96
- if (arr.length > 0) {
97
- const payload = createMessage(arr);
98
-
99
- if (flushing) {
100
- navigator.sendBeacon(_endpoint, payload);
101
- } else {
102
- const response = await fetch(_endpoint, {
103
- method: "POST",
104
- body: payload,
105
- headers: {
106
- "Content-Type": "text/plain",
107
- },
108
- });
109
-
110
- if (!response.ok) {
111
- // TODO: Retry, maybe store data in local storage
112
- }
113
- }
114
- }
115
- },
116
- {
117
- max: 10, // limit
118
- interval: 3000, // 3s
119
- },
120
- );
121
-
122
- function send(payload: AnalyticsEventWithType) {
123
- if (payload.properties.flushing) {
124
- const payloadWithoutFlushing = { ...payload };
125
- delete payloadWithoutFlushing.properties.flushing;
126
-
127
- navigator.sendBeacon(_endpoint, createMessage([payloadWithoutFlushing]));
128
- } else {
129
- queue.push(payload);
130
- }
131
- }
132
-
133
- export const analytics: AnalyticsInstance = Analytics({
134
- app: name,
135
- version,
136
- plugins: [
137
- {
138
- name: "custom-analytics-plugin",
139
- page: ({ payload }: { payload: Analytic }) => {
140
- const { properties, anonymousId, userId, event } = payload;
141
- const analyticsEvent = {
142
- anonymousId,
143
- userId,
144
- properties,
145
- event,
146
- type: "page",
147
- };
148
- // Send data to custom collection endpoint
149
- send(analyticsEvent);
150
- },
151
- track: ({ payload }: { payload: Analytic }) => {
152
- const { properties, anonymousId, userId, event } = payload;
153
- const analyticsEvent = {
154
- anonymousId,
155
- userId,
156
- properties,
157
- event,
158
- type: "track",
159
- };
160
- send(analyticsEvent);
161
- },
162
- },
163
- ],
164
- });
165
-
166
- export function getAnonymousUserId() {
167
- return analytics.user().anonymousId;
168
- }
169
-
170
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
171
- export function track(eventName: string, payload: any): void {
172
- analytics.track(eventName, payload);
173
- }
174
-
175
- export function trackEvent(event: TrackEvent): void {
176
- analytics.track(event.name, event);
177
- }
178
-
179
- export function flushQueue() {
180
- flushing = true;
181
- return queue.flush();
182
- }
183
-
184
- export function enableInteractions(callback?: () => void) {
185
- analytics.plugins.enable("custom-analytics-plugin", callback);
186
- }
187
-
188
- export function disableInteractions(callback?: () => void) {
189
- analytics.plugins.disable(
190
- "custom-analytics-plugin",
191
- callback || (() => true),
192
- );
193
- }
194
-
195
- export type Action = () => void;
196
- const unloadPageListeners = new Map<Element, Action>();
197
-
198
- export function addUnloadPageListener(element: Element, action: Action) {
199
- unloadPageListeners.set(element, action);
200
- }
201
-
202
- export function removeUnloadPageListener(element: Element) {
203
- unloadPageListeners.delete(element);
204
- }
205
-
206
- window.addEventListener("beforeunload", () => {
207
- // Flush the queues for all the registered element trackers
208
- unloadPageListeners.forEach((action, element) => {
209
- action.bind(element)();
210
- });
211
-
212
- // Flush the outbound queue
213
- flushQueue();
214
- });
@@ -1,2 +0,0 @@
1
- export * from './scroll.js';
2
- export * from './route.js';
@@ -1,8 +0,0 @@
1
- import onRouteChange from "@analytics/router-utils";
2
- import { analytics } from "../index.js";
3
-
4
- export function routeChangeListener() {
5
- onRouteChange(() => {
6
- analytics.page();
7
- });
8
- }
@@ -1,61 +0,0 @@
1
- import { onScrollChange } from "@analytics/scroll-utils";
2
- import { TrackEvents } from "../types/track-event";
3
- import { trackEvent } from "..";
4
-
5
- export type ScrollEvent = {
6
- direction: string;
7
- range: number[];
8
- scrollMax: number;
9
- scrollMin: number;
10
- trigger: number;
11
- };
12
-
13
- export function addScrollListener(itemSrc: string, publisherContentId: string) {
14
- onScrollChange({
15
- 25: (scrollData: ScrollEvent) => {
16
- trackEvent({
17
- name: TrackEvents.Scroll,
18
- scrollData: scrollData.direction,
19
- percentage: scrollData.trigger,
20
- itemSrc,
21
- publisherContentId,
22
- });
23
- },
24
- 50: (scrollData: ScrollEvent) => {
25
- trackEvent({
26
- name: TrackEvents.Scroll,
27
- scrollData: scrollData.direction,
28
- percentage: scrollData.trigger,
29
- itemSrc,
30
- publisherContentId,
31
- });
32
- },
33
- 75: (scrollData: ScrollEvent) => {
34
- trackEvent({
35
- name: TrackEvents.Scroll,
36
- scrollData: scrollData.direction,
37
- percentage: scrollData.trigger,
38
- itemSrc,
39
- publisherContentId,
40
- });
41
- },
42
- 90: (scrollData: ScrollEvent) => {
43
- trackEvent({
44
- name: TrackEvents.Scroll,
45
- scrollData: scrollData.direction,
46
- percentage: scrollData.trigger,
47
- itemSrc,
48
- publisherContentId,
49
- });
50
- },
51
- 100: (scrollData: ScrollEvent) => {
52
- trackEvent({
53
- name: TrackEvents.Scroll,
54
- scrollData: scrollData.direction,
55
- percentage: scrollData.trigger,
56
- itemSrc,
57
- publisherContentId,
58
- });
59
- },
60
- });
61
- }
@@ -1,52 +0,0 @@
1
- interface OnDomActivityOptions {
2
- throttle?: number;
3
- }
4
-
5
- interface OnUserActivityOptions {
6
- onIdle?: (elapsedTime: number, event?: any) => void;
7
- onWakeUp?: (elapsedTime: number, event?: any) => void;
8
- onHeartbeat?: (elapsedTime: number, event?: any) => void;
9
- timeout?: number;
10
- throttle?: number;
11
- }
12
-
13
- interface UserActivityStatus {
14
- disable: () => () => void;
15
- getStatus: () => {
16
- isIdle: boolean;
17
- isDisabled: boolean;
18
- active: number;
19
- idle: number;
20
- };
21
- }
22
-
23
- declare module "@analytics/activity-utils" {
24
- /**
25
- * Function to handle user inactivity.
26
- * @param onIdle Function to be called when the user is idle.
27
- * @param opts Optional configuration object.
28
- * @returns An object with methods to control and get the status of the listener.
29
- */
30
- function onIdle(
31
- onIdle: (elapsedTime: number, event?: any) => void,
32
- opts?: OnUserActivityOptions,
33
- ): UserActivityStatus;
34
-
35
- /**
36
- * Function to handle user wake up from idle.
37
- * @param onWakeUp Function to be called when the user wakes up from idle.
38
- * @param opts Optional configuration object.
39
- * @returns An object with methods to control and get the status of the listener.
40
- */
41
- function onWakeUp(
42
- onWakeUp: (elapsedTime: number, event?: any) => void,
43
- opts?: OnUserActivityOptions,
44
- ): UserActivityStatus;
45
-
46
- /**
47
- * Function to handle user activity.
48
- * @param options Configuration object for user activity.
49
- * @returns An object with methods to control and get the status of the listener.
50
- */
51
- function onUserActivity(options: OnUserActivityOptions): UserActivityStatus;
52
- }
@@ -1,7 +0,0 @@
1
- declare module '@analytics/router-utils' {
2
- interface definitionInterface {
3
- (message: string): void;
4
- }
5
- function onRouteChange(callback: definitionInterface): void;
6
- export default onRouteChange;
7
- }
@@ -1,4 +0,0 @@
1
- declare module '@analytics/scroll-utils' {
2
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
3
- function onScrollChange(t: any): any;
4
- }
@@ -1,70 +0,0 @@
1
- export enum TrackEvents {
2
- ViewArticle = 'viewArticle',
3
- ActiveDuration = 'activeDuration',
4
- IdleDuration = 'idleDuration',
5
- Scroll = 'scroll',
6
- ChangeView = 'changeView',
7
- AddToCart = 'addToCart',
8
- ViewArticleListing = 'viewArticleListing',
9
- }
10
-
11
- interface ViewArticleListingProps {
12
- name: TrackEvents.ViewArticleListing;
13
- publisherContentId?: string;
14
- itemSrc: string;
15
- }
16
-
17
- interface AddToCartEventProps {
18
- name: TrackEvents.AddToCart;
19
- publisherContentId?: string;
20
- itemSrc: string;
21
- }
22
-
23
- interface ChangeViewEventProps {
24
- name: TrackEvents.ChangeView;
25
- view: string;
26
- }
27
-
28
- interface ScrollEventProps {
29
- name: TrackEvents.Scroll;
30
- publisherContentId?: string;
31
- itemSrc: string;
32
- scrollData: string;
33
- percentage: number;
34
- }
35
-
36
- interface IdleDurationEventProps {
37
- name: TrackEvents.IdleDuration;
38
- duration: number;
39
- publisherContentId?: string;
40
- itemSrc: string;
41
- }
42
-
43
- interface ActiveDurationEventProps {
44
- name: TrackEvents.ActiveDuration;
45
- duration: number;
46
- publisherContentId?: string;
47
- itemSrc: string;
48
- }
49
-
50
- interface ViewArticleEventProps {
51
- name: TrackEvents.ViewArticle;
52
- itemSrc: string;
53
- publisherContentId?: string;
54
- state: 'public' | 'locked' | 'unlocked' | 'logged-in';
55
- }
56
-
57
- interface Flushing {
58
- flushing?: boolean;
59
- }
60
-
61
- export type TrackEvent = Flushing &
62
- (
63
- | ViewArticleEventProps
64
- | ActiveDurationEventProps
65
- | IdleDurationEventProps
66
- | ScrollEventProps
67
- | ChangeViewEventProps
68
- | AddToCartEventProps
69
- | ViewArticleListingProps
70
- );
@@ -1,60 +0,0 @@
1
- import { Auth0Client, createAuth0Client } from "@auth0/auth0-spa-js";
2
- import { BASE_URL_DOMAIN } from "../../constants";
3
-
4
- let auth0Client: Auth0Client;
5
-
6
- export async function init({ clientId }: { clientId: string }) {
7
-
8
- auth0Client = await createAuth0Client({
9
- domain: `token.${BASE_URL_DOMAIN}`,
10
- clientId,
11
- cacheLocation: 'localstorage'
12
- });
13
-
14
- if (window.location.search.includes("code=")) {
15
- try {
16
- await auth0Client.handleRedirectCallback();
17
- window.history.replaceState({}, document.title, "/");
18
- } catch (err) {
19
- // Fail silently
20
- }
21
- }
22
- }
23
-
24
- export async function isAuthenticated() {
25
- if (!auth0Client) {
26
- throw new Error("Auth0 client not initialized");
27
- }
28
- return auth0Client.isAuthenticated();
29
- }
30
-
31
- export async function getUser() {
32
- if (!auth0Client) {
33
- throw new Error("Auth0 client not initialized");
34
- }
35
- return auth0Client.getUser();
36
- }
37
-
38
- export function loginWithRedirect() {
39
- if (!auth0Client) {
40
- throw new Error("Auth0 client not initialized");
41
- }
42
-
43
- return auth0Client.loginWithRedirect({
44
- authorizationParams: {
45
- redirect_uri: window.location.href,
46
- },
47
- });
48
- }
49
-
50
- export function logout() {
51
- if (!auth0Client) {
52
- throw new Error("Auth0 client not initialized");
53
- }
54
-
55
- return auth0Client.logout({
56
- logoutParams: {
57
- returnTo: window.location.href,
58
- },
59
- });
60
- }
package/src/state.ts DELETED
@@ -1,3 +0,0 @@
1
- {
2
- // Soon to come more stuff here..
3
- }
package/src/style.css DELETED
@@ -1,97 +0,0 @@
1
- :root {
2
- font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
3
- line-height: 1.5;
4
- font-weight: 400;
5
-
6
- color-scheme: light dark;
7
- color: rgba(255, 255, 255, 0.87);
8
- background-color: #242424;
9
-
10
- font-synthesis: none;
11
- text-rendering: optimizeLegibility;
12
- -webkit-font-smoothing: antialiased;
13
- -moz-osx-font-smoothing: grayscale;
14
- }
15
-
16
- a {
17
- font-weight: 500;
18
- color: #646cff;
19
- text-decoration: inherit;
20
- }
21
- a:hover {
22
- color: #535bf2;
23
- }
24
-
25
- body {
26
- margin: 0;
27
- display: flex;
28
- place-items: center;
29
- min-width: 320px;
30
- min-height: 100vh;
31
- }
32
-
33
- h1 {
34
- font-size: 3.2em;
35
- line-height: 1.1;
36
- }
37
-
38
- sesamy-app {
39
- max-width: 1280px;
40
- margin: 0 auto;
41
- padding: 2rem;
42
- text-align: center;
43
- }
44
-
45
- .logo {
46
- height: 6em;
47
- padding: 1.5em;
48
- will-change: filter;
49
- transition: filter 300ms;
50
- }
51
- .logo:hover {
52
- filter: drop-shadow(0 0 2em #646cffaa);
53
- }
54
- .logo.vanilla:hover {
55
- filter: drop-shadow(0 0 2em #3178c6aa);
56
- }
57
-
58
- .card {
59
- padding: 2em;
60
- }
61
-
62
- .read-the-docs {
63
- color: #888;
64
- }
65
-
66
- button {
67
- border-radius: 8px;
68
- border: 1px solid transparent;
69
- padding: 0.6em 1.2em;
70
- font-size: 1em;
71
- font-weight: 500;
72
- font-family: inherit;
73
- background-color: #1a1a1a;
74
- cursor: pointer;
75
- transition: border-color 0.25s;
76
- }
77
- button:hover {
78
- border-color: #646cff;
79
- }
80
- button:focus,
81
- button:focus-visible {
82
- outline: 4px auto -webkit-focus-ring-color;
83
- }
84
- .hidden { display: none; }
85
-
86
- @media (prefers-color-scheme: light) {
87
- :root {
88
- color: #213547;
89
- background-color: #ffffff;
90
- }
91
- a:hover {
92
- color: #747bff;
93
- }
94
- button {
95
- background-color: #f9f9f9;
96
- }
97
- }