@codecademy/tracking 1.2.0-alpha.ec7903070d.0 → 2.0.0-alpha.319255f0ae.0
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/package.json +1 -1
- package/dist/events/index.d.ts +0 -3
- package/dist/events/index.js +0 -3
- package/dist/events/track.d.ts +0 -12
- package/dist/events/track.js +0 -119
- package/dist/events/types.d.ts +0 -264
- package/dist/events/types.js +0 -49
- package/dist/events/user.d.ts +0 -2
- package/dist/events/user.js +0 -11
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -3
- package/dist/integrations/consent.d.ts +0 -9
- package/dist/integrations/consent.js +0 -10
- package/dist/integrations/device.d.ts +0 -13
- package/dist/integrations/device.js +0 -19
- package/dist/integrations/fides.d.ts +0 -1
- package/dist/integrations/fides.js +0 -54
- package/dist/integrations/gtm.d.ts +0 -9
- package/dist/integrations/gtm.js +0 -36
- package/dist/integrations/index.d.ts +0 -31
- package/dist/integrations/index.js +0 -43
- package/dist/integrations/onetrust.d.ts +0 -7
- package/dist/integrations/onetrust.js +0 -34
- package/dist/integrations/partytown/config.d.ts +0 -2
- package/dist/integrations/partytown/config.js +0 -70
- package/dist/integrations/partytown/gtmDoubleFrame.d.ts +0 -1
- package/dist/integrations/partytown/gtmDoubleFrame.js +0 -15
- package/dist/integrations/partytown/index.d.ts +0 -1
- package/dist/integrations/partytown/index.js +0 -24
- package/dist/integrations/types.d.ts +0 -6
- package/dist/integrations/types.js +0 -1
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codecademy/tracking",
|
|
3
3
|
"description": "Tracking library for Codecademy",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "2.0.0-alpha.319255f0ae.0",
|
|
5
5
|
"author": "Codecademy Engineering <dev@codecademy.com>",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@qwik.dev/partytown": "0.11.0"
|
package/dist/events/index.d.ts
DELETED
package/dist/events/index.js
DELETED
package/dist/events/track.d.ts
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import type { BaseEventData, EventDataTypes, TrackingOptions, UserClickData, UserImpressionData, UserVisitData } from './types';
|
|
2
|
-
export type TrackerOptions = {
|
|
3
|
-
apiBaseUrl: string;
|
|
4
|
-
verbose?: boolean;
|
|
5
|
-
};
|
|
6
|
-
export declare const createTracker: ({ apiBaseUrl, verbose }: TrackerOptions) => {
|
|
7
|
-
event: <Category extends keyof EventDataTypes, Event extends string & keyof EventDataTypes[Category], Data extends EventDataTypes[Category][Event] & BaseEventData>(category: Category, event: Event, userData: Data, options?: TrackingOptions) => void;
|
|
8
|
-
click: (data: UserClickData) => void;
|
|
9
|
-
impression: (data: UserImpressionData) => void;
|
|
10
|
-
visit: (data: UserVisitData) => void;
|
|
11
|
-
pushDataLayerEvent: (eventName: string) => void;
|
|
12
|
-
};
|
package/dist/events/track.js
DELETED
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
2
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
3
|
-
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
4
|
-
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
5
|
-
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
|
|
6
|
-
function _slicedToArray(r, e) { return _arrayWithHoles(r) || _iterableToArrayLimit(r, e) || _unsupportedIterableToArray(r, e) || _nonIterableRest(); }
|
|
7
|
-
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
8
|
-
function _unsupportedIterableToArray(r, a) { if (r) { if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = {}.toString.call(r).slice(8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? Array.from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
|
|
9
|
-
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
|
|
10
|
-
function _iterableToArrayLimit(r, l) { var t = null == r ? null : "undefined" != typeof Symbol && r[Symbol.iterator] || r["@@iterator"]; if (null != t) { var e, n, i, u, a = [], f = !0, o = !1; try { if (i = (t = t.call(r)).next, 0 === l) { if (Object(t) !== t) return; f = !1; } else for (; !(f = (e = i.call(t)).done) && (a.push(e.value), a.length !== l); f = !0); } catch (r) { o = !0, n = r; } finally { try { if (!f && null != t.return && (u = t.return(), Object(u) !== u)) return; } finally { if (o) throw n; } } return a; } }
|
|
11
|
-
function _arrayWithHoles(r) { if (Array.isArray(r)) return r; }
|
|
12
|
-
import { getClientType } from '../integrations/device';
|
|
13
|
-
const browserSupportsKeepalive = () => 'keepalive' in window.Request.prototype;
|
|
14
|
-
export const createTracker = _ref => {
|
|
15
|
-
let apiBaseUrl = _ref.apiBaseUrl,
|
|
16
|
-
verbose = _ref.verbose;
|
|
17
|
-
const beacon = (endpoint, data) => {
|
|
18
|
-
const _URL = new URL(apiBaseUrl),
|
|
19
|
-
origin = _URL.origin;
|
|
20
|
-
const uri = new URL(endpoint, origin).toString();
|
|
21
|
-
const form = new FormData();
|
|
22
|
-
for (const _ref2 of Object.entries(data)) {
|
|
23
|
-
var _ref3 = _slicedToArray(_ref2, 2);
|
|
24
|
-
const k = _ref3[0];
|
|
25
|
-
const v = _ref3[1];
|
|
26
|
-
form.append(k, v.toString());
|
|
27
|
-
}
|
|
28
|
-
try {
|
|
29
|
-
// Firefox allows users to disable navigator.sendBeacon, and very old Safari versions don't have it.
|
|
30
|
-
// [WEB-1700]: Additionally, Chrome 79-80 gives "Illegal invocation" with ?., so through 2022 we should support them.
|
|
31
|
-
// It seems similar to this: https://github.com/vercel/next.js/issues/23856
|
|
32
|
-
if (navigator.sendBeacon && navigator.sendBeacon(uri, form)) {
|
|
33
|
-
return;
|
|
34
|
-
}
|
|
35
|
-
} catch (_unused) {
|
|
36
|
-
// Even with the proper scoping, Chrome 79-80 still gives "Illegal invocation" crashes. Sigh.
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
// Either way, we fall back to standard fetch if sendBeacon fails.
|
|
40
|
-
// We don't mind this rejecting with an error because it's tracking, and we'll know if that starts to fail.
|
|
41
|
-
window.fetch(uri, _objectSpread({
|
|
42
|
-
method: 'POST',
|
|
43
|
-
body: form
|
|
44
|
-
}, browserSupportsKeepalive() && {
|
|
45
|
-
keepalive: true
|
|
46
|
-
}));
|
|
47
|
-
};
|
|
48
|
-
const serverSideBeacon = (endpoint, data) => {
|
|
49
|
-
const _URL2 = new URL(apiBaseUrl),
|
|
50
|
-
origin = _URL2.origin;
|
|
51
|
-
const uri = new URL(endpoint, origin).toString();
|
|
52
|
-
const form = new URLSearchParams();
|
|
53
|
-
for (const _ref4 of Object.entries(data)) {
|
|
54
|
-
var _ref5 = _slicedToArray(_ref4, 2);
|
|
55
|
-
const k = _ref5[0];
|
|
56
|
-
const v = _ref5[1];
|
|
57
|
-
form.append(k, v.toString());
|
|
58
|
-
}
|
|
59
|
-
fetch(uri, {
|
|
60
|
-
method: 'POST',
|
|
61
|
-
body: form
|
|
62
|
-
});
|
|
63
|
-
};
|
|
64
|
-
const event = function (category, event, userData) {
|
|
65
|
-
let options = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
|
|
66
|
-
// support server-side-only as well as client-side events
|
|
67
|
-
const properties = typeof window !== 'undefined' ? _objectSpread(_objectSpread({}, userData), {}, {
|
|
68
|
-
fullpath: window.location.pathname + window.location.search,
|
|
69
|
-
search: window.location.search,
|
|
70
|
-
path: window.location.pathname,
|
|
71
|
-
title: window.document.title,
|
|
72
|
-
url: window.location.href,
|
|
73
|
-
referrer: userData.referrer || window.document.referrer,
|
|
74
|
-
client: getClientType()
|
|
75
|
-
}) : userData;
|
|
76
|
-
if (verbose) {
|
|
77
|
-
console.groupCollapsed("%cTracking Event Fired: ".concat(category, ":").concat(event), 'color: #4b35ef; font-style: italic;');
|
|
78
|
-
console.log({
|
|
79
|
-
category,
|
|
80
|
-
event,
|
|
81
|
-
properties: JSON.parse(JSON.stringify(properties))
|
|
82
|
-
});
|
|
83
|
-
console.groupEnd();
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
// Use /analytics path if path is not already specified in apiBaseUrl
|
|
87
|
-
const _URL3 = new URL(apiBaseUrl),
|
|
88
|
-
pathname = _URL3.pathname;
|
|
89
|
-
const basePath = pathname === '/' ? '/analytics' : pathname;
|
|
90
|
-
if (typeof window !== 'undefined') {
|
|
91
|
-
// This allows the UTM query params to get registered in the user session.
|
|
92
|
-
const queryParams = window.location.search;
|
|
93
|
-
beacon("".concat(basePath, "/").concat(category).concat(queryParams), {
|
|
94
|
-
category,
|
|
95
|
-
event,
|
|
96
|
-
properties: JSON.stringify(properties),
|
|
97
|
-
gdpr_safe: "".concat(options.gdprSafe)
|
|
98
|
-
});
|
|
99
|
-
} else {
|
|
100
|
-
serverSideBeacon("".concat(basePath, "/").concat(category), {
|
|
101
|
-
category,
|
|
102
|
-
event,
|
|
103
|
-
properties: JSON.stringify(properties)
|
|
104
|
-
});
|
|
105
|
-
}
|
|
106
|
-
};
|
|
107
|
-
return {
|
|
108
|
-
event,
|
|
109
|
-
click: data => event('user', 'click', data),
|
|
110
|
-
impression: data => event('user', 'impression', data),
|
|
111
|
-
visit: data => event('user', 'visit', data),
|
|
112
|
-
pushDataLayerEvent: eventName => {
|
|
113
|
-
var _ref6;
|
|
114
|
-
((_ref6 = window).dataLayer || (_ref6.dataLayer = [])).push({
|
|
115
|
-
event: eventName
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
};
|
|
119
|
-
};
|
package/dist/events/types.d.ts
DELETED
|
@@ -1,264 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The Data types for all of our events.
|
|
3
|
-
* Follows the format EventDataTypes[Category].[Event].EventData
|
|
4
|
-
* Category + Event gives the corresponding event table in redshift
|
|
5
|
-
*/
|
|
6
|
-
export type EventDataTypes = {
|
|
7
|
-
user: {
|
|
8
|
-
click: UserClickData;
|
|
9
|
-
visit: UserVisitData;
|
|
10
|
-
impression: UserImpressionData;
|
|
11
|
-
email_trigger: BaseEventAnyData;
|
|
12
|
-
content_completed: BaseEventAnyData;
|
|
13
|
-
submit: BaseEventAnyData;
|
|
14
|
-
workspace_init: BaseEventAnyData;
|
|
15
|
-
meaningful_content_loaded: BaseEventAnyData;
|
|
16
|
-
practice_completed: BaseEventAnyData;
|
|
17
|
-
};
|
|
18
|
-
ad: {
|
|
19
|
-
click: BaseEventAnyData;
|
|
20
|
-
impression: BaseEventAnyData;
|
|
21
|
-
};
|
|
22
|
-
calendar: {
|
|
23
|
-
reminder: BaseEventAnyData;
|
|
24
|
-
};
|
|
25
|
-
notification: {
|
|
26
|
-
clicked: BaseEventAnyData;
|
|
27
|
-
ion: BaseEventAnyData;
|
|
28
|
-
};
|
|
29
|
-
form: {
|
|
30
|
-
submit: BaseEventAnyData;
|
|
31
|
-
};
|
|
32
|
-
sorting_quiz: {
|
|
33
|
-
result: BaseEventAnyData;
|
|
34
|
-
impression: BaseEventAnyData;
|
|
35
|
-
answer: EventAnswerData;
|
|
36
|
-
};
|
|
37
|
-
onboarding_survey: {
|
|
38
|
-
answer: BaseEventAnyData;
|
|
39
|
-
recommendation: BaseEventAnyData;
|
|
40
|
-
submission_recommendation: BaseEventAnyData;
|
|
41
|
-
user_selected_recommendation: BaseEventAnyData;
|
|
42
|
-
};
|
|
43
|
-
exercise: {
|
|
44
|
-
force_pass: BaseEventAnyData;
|
|
45
|
-
};
|
|
46
|
-
experiment: {
|
|
47
|
-
contentful_experiment_assignment_event: BaseEventAnyData;
|
|
48
|
-
};
|
|
49
|
-
payments: {
|
|
50
|
-
cancel_survey: BaseEventAnyData;
|
|
51
|
-
extend_trial_survey: BaseEventAnyData;
|
|
52
|
-
};
|
|
53
|
-
search: {
|
|
54
|
-
visit: BaseEventAnyData;
|
|
55
|
-
click: BaseEventAnyData;
|
|
56
|
-
query: BaseEventAnyData;
|
|
57
|
-
result: BaseEventAnyData;
|
|
58
|
-
};
|
|
59
|
-
page: {
|
|
60
|
-
career_path_visited: PagePathVisitedData;
|
|
61
|
-
skill_path_visited: PagePathVisitedData;
|
|
62
|
-
course_page_visited: CoursePageVisitedData;
|
|
63
|
-
};
|
|
64
|
-
business: {
|
|
65
|
-
filter_event: BusinessFilterData;
|
|
66
|
-
search_event: BusinessSearchData;
|
|
67
|
-
};
|
|
68
|
-
gpt_plugin: {
|
|
69
|
-
search: ChatGPTPluginSearchEventData;
|
|
70
|
-
};
|
|
71
|
-
};
|
|
72
|
-
/**
|
|
73
|
-
* Base event data shared by all events
|
|
74
|
-
*/
|
|
75
|
-
export type BaseEventData = {
|
|
76
|
-
fullpath?: null;
|
|
77
|
-
search?: null;
|
|
78
|
-
path?: null;
|
|
79
|
-
title?: null;
|
|
80
|
-
url?: null;
|
|
81
|
-
referrer?: string | null;
|
|
82
|
-
id?: null;
|
|
83
|
-
};
|
|
84
|
-
/**
|
|
85
|
-
* Generic type to use for event data not typed yet
|
|
86
|
-
*/
|
|
87
|
-
export type BaseEventAnyData = BaseEventData & {
|
|
88
|
-
[key: string]: any;
|
|
89
|
-
};
|
|
90
|
-
/**
|
|
91
|
-
* Options to pass to the tracking function
|
|
92
|
-
*/
|
|
93
|
-
export type TrackingOptions = {
|
|
94
|
-
/** tells backend not to merge user-identifying data onto the event payload */
|
|
95
|
-
gdprSafe?: boolean;
|
|
96
|
-
};
|
|
97
|
-
/**
|
|
98
|
-
* The Content IDs related to the current event, to help build the content context of the event.
|
|
99
|
-
* These IDs get hashed into a single value and overwrite content_id before they are sent to
|
|
100
|
-
* redshift in lib/content_group_id.rb
|
|
101
|
-
*/
|
|
102
|
-
export type TrackingContentIds = {
|
|
103
|
-
assessment_id?: string;
|
|
104
|
-
content_item_id?: string;
|
|
105
|
-
exercise_id?: string;
|
|
106
|
-
learning_standard_id?: string;
|
|
107
|
-
module_id?: string;
|
|
108
|
-
path_id?: string;
|
|
109
|
-
program_id?: string;
|
|
110
|
-
program_unit_id?: string;
|
|
111
|
-
review_card_id?: string;
|
|
112
|
-
skill_benchmark_id?: string;
|
|
113
|
-
track_id?: string;
|
|
114
|
-
journey_id?: string;
|
|
115
|
-
external_course_id?: string;
|
|
116
|
-
external_path_id?: string;
|
|
117
|
-
lo_id?: string;
|
|
118
|
-
};
|
|
119
|
-
/**
|
|
120
|
-
* Shared data relevant for all user events
|
|
121
|
-
*/
|
|
122
|
-
export type UserSharedData = BaseEventData & {
|
|
123
|
-
/** the click target of the event */
|
|
124
|
-
target?: string;
|
|
125
|
-
/** the page the event is coming from */
|
|
126
|
-
page_name?: string;
|
|
127
|
-
/** a context id for the event, for events that occur in more than one place */
|
|
128
|
-
context?: string;
|
|
129
|
-
/** the link being clicked on */
|
|
130
|
-
href?: string;
|
|
131
|
-
/** a version id for the element (ex. different version ids for redesigns) */
|
|
132
|
-
version?: string;
|
|
133
|
-
/** an object of content ids related to this event */
|
|
134
|
-
content_ids?: TrackingContentIds;
|
|
135
|
-
/** the repo that this event is being fired from */
|
|
136
|
-
source_codebase?: string;
|
|
137
|
-
/** Should be used for arbitrary JSON that has been passed through JSON.stringify. */
|
|
138
|
-
misc?: string;
|
|
139
|
-
};
|
|
140
|
-
/**
|
|
141
|
-
* Data sent to user click event table
|
|
142
|
-
* NOTE: avoid adding additional properties to these objects
|
|
143
|
-
* Instead, reuse existing properties, or make any additional properties generic so that they can be reused.
|
|
144
|
-
* https://www.notion.so/codecademy/Guide-to-Event-Tracking-Schema-5d40b09a297743f7a30a2690208194c8#800bbf6cdf2e44de9823cd75bcc574e5
|
|
145
|
-
*/
|
|
146
|
-
export type UserClickData = UserSharedData & {
|
|
147
|
-
target: string;
|
|
148
|
-
id?: string;
|
|
149
|
-
distinct_id?: string;
|
|
150
|
-
content_id?: string;
|
|
151
|
-
slug?: string;
|
|
152
|
-
name?: string;
|
|
153
|
-
action?: string;
|
|
154
|
-
type?: string;
|
|
155
|
-
location?: string;
|
|
156
|
-
element?: string;
|
|
157
|
-
weekly_goal?: string | number;
|
|
158
|
-
complete?: string;
|
|
159
|
-
video_url?: string;
|
|
160
|
-
path_id?: string;
|
|
161
|
-
path_slug?: string;
|
|
162
|
-
event_name?: string;
|
|
163
|
-
onboarding_entrypoint?: string;
|
|
164
|
-
content_slug?: string;
|
|
165
|
-
module_id?: string;
|
|
166
|
-
track_slug?: string;
|
|
167
|
-
module_slug?: string;
|
|
168
|
-
button?: string;
|
|
169
|
-
current_challenge_day?: string | number;
|
|
170
|
-
track_id?: string;
|
|
171
|
-
course?: string;
|
|
172
|
-
path_name?: string;
|
|
173
|
-
event_id?: string;
|
|
174
|
-
unit?: string;
|
|
175
|
-
lesson?: string;
|
|
176
|
-
community_prompt?: string;
|
|
177
|
-
contentItem?: any;
|
|
178
|
-
unit_slug?: string;
|
|
179
|
-
course_slug?: string;
|
|
180
|
-
course_progress?: number;
|
|
181
|
-
assessment_id?: string;
|
|
182
|
-
container_slugs?: string[];
|
|
183
|
-
search_id?: string;
|
|
184
|
-
business_user?: BaseEventAnyData;
|
|
185
|
-
};
|
|
186
|
-
/**
|
|
187
|
-
* Data sent to user visit event table
|
|
188
|
-
* NOTE: avoid adding additional properties to these objects
|
|
189
|
-
* Instead, reuse existing properties, or make any additional properties generic so that they can be reused.
|
|
190
|
-
* https://www.notion.so/codecademy/Guide-to-Event-Tracking-Schema-5d40b09a297743f7a30a2690208194c8#800bbf6cdf2e44de9823cd75bcc574e5
|
|
191
|
-
*/
|
|
192
|
-
export type UserVisitData = UserSharedData & {
|
|
193
|
-
page_name: string;
|
|
194
|
-
category?: string;
|
|
195
|
-
distinct_id?: string;
|
|
196
|
-
type?: string;
|
|
197
|
-
target?: string;
|
|
198
|
-
section?: string;
|
|
199
|
-
plan?: string;
|
|
200
|
-
path_id?: string;
|
|
201
|
-
post?: string;
|
|
202
|
-
story_type?: string;
|
|
203
|
-
path_title?: string;
|
|
204
|
-
onboarding_entrypoint?: string;
|
|
205
|
-
course_slug?: string;
|
|
206
|
-
course?: string;
|
|
207
|
-
interstitial_name?: string;
|
|
208
|
-
content_id?: string;
|
|
209
|
-
story_slug?: string;
|
|
210
|
-
unit?: string;
|
|
211
|
-
lesson?: string;
|
|
212
|
-
};
|
|
213
|
-
export type UserImpressionData = Pick<UserSharedData, 'context' | 'source_codebase' | 'content_ids' | 'misc'> & {
|
|
214
|
-
page_name: string;
|
|
215
|
-
target: string;
|
|
216
|
-
slug?: string;
|
|
217
|
-
};
|
|
218
|
-
export type EventAnswerData = BaseEventData & {
|
|
219
|
-
question_index: number;
|
|
220
|
-
answer_index: number;
|
|
221
|
-
answer: any;
|
|
222
|
-
answer_slug: string;
|
|
223
|
-
};
|
|
224
|
-
export type User = {
|
|
225
|
-
id?: string;
|
|
226
|
-
auth_token: string;
|
|
227
|
-
profile_image_url?: string;
|
|
228
|
-
email?: string;
|
|
229
|
-
is_pro?: boolean;
|
|
230
|
-
username?: string;
|
|
231
|
-
location: {
|
|
232
|
-
in_eu: boolean;
|
|
233
|
-
geo_country: string;
|
|
234
|
-
};
|
|
235
|
-
features: string[];
|
|
236
|
-
};
|
|
237
|
-
export type UseUserResponse = {
|
|
238
|
-
user?: User;
|
|
239
|
-
status: string;
|
|
240
|
-
};
|
|
241
|
-
export type PagePathVisitedData = BaseEventData & {
|
|
242
|
-
path_id: string;
|
|
243
|
-
path_full_title: string;
|
|
244
|
-
};
|
|
245
|
-
export type CoursePageVisitedData = BaseEventData & {
|
|
246
|
-
course_id: string;
|
|
247
|
-
course_full_title: string;
|
|
248
|
-
};
|
|
249
|
-
export type FilterType = string | string[] | number | boolean;
|
|
250
|
-
export type BusinessFilterData = BaseEventData & {
|
|
251
|
-
filter_key: string;
|
|
252
|
-
filter_value: FilterType;
|
|
253
|
-
};
|
|
254
|
-
export type BusinessSearchData = BaseEventData & {
|
|
255
|
-
search_query: string;
|
|
256
|
-
};
|
|
257
|
-
export declare enum ChatGPTSearchResource {
|
|
258
|
-
CATALOG = "catalog",
|
|
259
|
-
LITERATURE = "literature"
|
|
260
|
-
}
|
|
261
|
-
export type ChatGPTPluginSearchEventData = {
|
|
262
|
-
resource: ChatGPTSearchResource;
|
|
263
|
-
query: string;
|
|
264
|
-
};
|
package/dist/events/types.js
DELETED
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The Data types for all of our events.
|
|
3
|
-
* Follows the format EventDataTypes[Category].[Event].EventData
|
|
4
|
-
* Category + Event gives the corresponding event table in redshift
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Base event data shared by all events
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Generic type to use for event data not typed yet
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Options to pass to the tracking function
|
|
17
|
-
*/
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* The Content IDs related to the current event, to help build the content context of the event.
|
|
21
|
-
* These IDs get hashed into a single value and overwrite content_id before they are sent to
|
|
22
|
-
* redshift in lib/content_group_id.rb
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Shared data relevant for all user events
|
|
27
|
-
*/
|
|
28
|
-
|
|
29
|
-
/**
|
|
30
|
-
* Data sent to user click event table
|
|
31
|
-
* NOTE: avoid adding additional properties to these objects
|
|
32
|
-
* Instead, reuse existing properties, or make any additional properties generic so that they can be reused.
|
|
33
|
-
* https://www.notion.so/codecademy/Guide-to-Event-Tracking-Schema-5d40b09a297743f7a30a2690208194c8#800bbf6cdf2e44de9823cd75bcc574e5
|
|
34
|
-
*/
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Data sent to user visit event table
|
|
38
|
-
* NOTE: avoid adding additional properties to these objects
|
|
39
|
-
* Instead, reuse existing properties, or make any additional properties generic so that they can be reused.
|
|
40
|
-
* https://www.notion.so/codecademy/Guide-to-Event-Tracking-Schema-5d40b09a297743f7a30a2690208194c8#800bbf6cdf2e44de9823cd75bcc574e5
|
|
41
|
-
*/
|
|
42
|
-
|
|
43
|
-
export let ChatGPTSearchResource = /*#__PURE__*/function (ChatGPTSearchResource) {
|
|
44
|
-
ChatGPTSearchResource["CATALOG"] = "catalog";
|
|
45
|
-
ChatGPTSearchResource["LITERATURE"] = "literature";
|
|
46
|
-
return ChatGPTSearchResource;
|
|
47
|
-
}({});
|
|
48
|
-
|
|
49
|
-
// does not extend base event (all client side fields there)
|
package/dist/events/user.d.ts
DELETED
package/dist/events/user.js
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export const fetchUser = async apiBaseUrl => {
|
|
2
|
-
const response = await fetch("".concat(apiBaseUrl, "/users/web"), {
|
|
3
|
-
method: 'GET',
|
|
4
|
-
headers: {
|
|
5
|
-
'Content-type': 'application/json',
|
|
6
|
-
Accept: 'application/json'
|
|
7
|
-
},
|
|
8
|
-
credentials: 'include'
|
|
9
|
-
});
|
|
10
|
-
return response.json();
|
|
11
|
-
};
|
package/dist/index.d.ts
DELETED
package/dist/index.js
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @see https://www.notion.so/codecademy/GDPR-Compliance-141ebcc7ffa542daa0da56e35f482b41
|
|
3
|
-
*/
|
|
4
|
-
export let Consent = /*#__PURE__*/function (Consent) {
|
|
5
|
-
Consent["Functional"] = "C0003";
|
|
6
|
-
Consent["Performance"] = "C0002";
|
|
7
|
-
Consent["StrictlyNecessary"] = "C0001";
|
|
8
|
-
Consent["Targeting"] = "C0004";
|
|
9
|
-
return Consent;
|
|
10
|
-
}({});
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @returns Whether the site is running both in ChromeOS and in PWA mode.
|
|
3
|
-
*/
|
|
4
|
-
export declare const isChromeOSPWA: () => boolean;
|
|
5
|
-
/**
|
|
6
|
-
* @returns Whether the site is running in ChromeOS
|
|
7
|
-
*/
|
|
8
|
-
export declare const isChromeOS: () => boolean;
|
|
9
|
-
export declare enum ClientTypes {
|
|
10
|
-
PWA = "pwa",
|
|
11
|
-
Default = "default"
|
|
12
|
-
}
|
|
13
|
-
export declare const getClientType: () => ClientTypes;
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @returns Whether the site is running both in ChromeOS and in PWA mode.
|
|
3
|
-
*/
|
|
4
|
-
export const isChromeOSPWA = () => isChromeOS() && 'getDigitalGoodsService' in window &&
|
|
5
|
-
// https://stackoverflow.com/questions/41742390/javascript-to-check-if-pwa-or-mobile-web
|
|
6
|
-
window.matchMedia('(display-mode: standalone)').matches;
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* @returns Whether the site is running in ChromeOS
|
|
10
|
-
*/
|
|
11
|
-
export const isChromeOS = () => typeof navigator !== 'undefined' &&
|
|
12
|
-
// https://stackoverflow.com/questions/29657165/detecting-chrome-os-with-javascript
|
|
13
|
-
/\bCrOS\b/.test(navigator.userAgent);
|
|
14
|
-
export let ClientTypes = /*#__PURE__*/function (ClientTypes) {
|
|
15
|
-
ClientTypes["PWA"] = "pwa";
|
|
16
|
-
ClientTypes["Default"] = "default";
|
|
17
|
-
return ClientTypes;
|
|
18
|
-
}({});
|
|
19
|
-
export const getClientType = () => isChromeOSPWA() ? ClientTypes.PWA : ClientTypes.Default;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare const initializeFides: () => Promise<void>;
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
import { theme } from '@codecademy/gamut-styles';
|
|
2
|
-
/**
|
|
3
|
-
* Fides property ID for `www.codecademy.com`.
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
const PROPERTY_ID = 'FDS-3RC5S1';
|
|
7
|
-
const ot_fides_mapping = encodeURIComponent(JSON.stringify({
|
|
8
|
-
C0001: ['essential'],
|
|
9
|
-
C0002: ['analytics'],
|
|
10
|
-
C0003: ['functional'],
|
|
11
|
-
C0004: ['marketing']
|
|
12
|
-
}));
|
|
13
|
-
const importFides = async () => {
|
|
14
|
-
var _win$define;
|
|
15
|
-
const win = window;
|
|
16
|
-
// Disable AMD globals for the Fides script
|
|
17
|
-
const oldAmd = (_win$define = win.define) === null || _win$define === void 0 ? void 0 : _win$define.amd;
|
|
18
|
-
if (oldAmd) {
|
|
19
|
-
win.define.amd = undefined;
|
|
20
|
-
}
|
|
21
|
-
// Fides gets stored on the window object
|
|
22
|
-
await import(/* webpackIgnore: true */"https://skillsoft-codecademy.fides-cdn.ethyca.com/fides.js?property_id=".concat(PROPERTY_ID, "&ot_fides_mapping=").concat(ot_fides_mapping));
|
|
23
|
-
if (oldAmd) {
|
|
24
|
-
win.define.amd = oldAmd;
|
|
25
|
-
}
|
|
26
|
-
if (!win.Fides) {
|
|
27
|
-
throw new Error('Failed to import Fides');
|
|
28
|
-
}
|
|
29
|
-
return win.Fides;
|
|
30
|
-
};
|
|
31
|
-
export const initializeFides = async () => {
|
|
32
|
-
try {
|
|
33
|
-
const fides = await importFides();
|
|
34
|
-
fides.gtm();
|
|
35
|
-
const unsubscribe = fides.onFidesEvent('FidesUIShown', detail => {
|
|
36
|
-
if (detail.extraDetails.servingComponent === 'banner') {
|
|
37
|
-
const banner = document.getElementById('fides-banner');
|
|
38
|
-
if (banner) {
|
|
39
|
-
banner.setAttribute('tabIndex', '-1');
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
unsubscribe();
|
|
43
|
-
});
|
|
44
|
-
} catch (err) {
|
|
45
|
-
console.error('Error initializing Fides', err);
|
|
46
|
-
}
|
|
47
|
-
const style = document.createElement('style');
|
|
48
|
-
style.textContent = rawStyles;
|
|
49
|
-
document.body.appendChild(style);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
// For now, these three values duplicate theme colors from gamut-styles
|
|
53
|
-
// We don't want to take a full dependency on that package here...
|
|
54
|
-
const rawStyles = "\n:root {\n /* Colors */\n\n --fides-overlay-primary-color: ".concat(theme.colors.hyper, ";\n --fides-overlay-body-font-color: #484848;\n\n /* Buttons */\n\n --fides-overlay-primary-button-background-hover-color: ").concat(theme.colors.hyper, ";\n\n /* Toggles */\n --fides-overlay-primary-active-color: var(--fides-overlay-primary-color);\n --fides-overlay-primary-active-disabled-color: #bda4f7;\n --fides-overlay-inactive-color: #cbd5e0;\n --fides-overlay-disabled-color: #e1e7ee;\n\n /* Everything else */\n --fides-overlay-button-border-radius: ").concat(theme.borderRadii.md, ";\n --fides-overlay-font-family: inherit;\n --fides-overlay-font-size-body: 0.875rem !important;\n --fides-overlay-line-height: 1.375rem !important;\n --fides-overlay-padding: padding: 1rem !important;\n --fides-overlay-padding: 0.875rem 1rem !important;\n}\n\n.fides-banner, .fides-modal-container {\n -webkit-font-smoothing: auto;\n}\n\ndiv#fides-overlay {\n font-size: var(--fides-overlay-font-size-body);\n line-height: var(--fides-overlay-line-height);\n z-index: 1000;\n position: fixed;\n white-space: pre-line;\n font-family: inherit;\n line-height: calc(1em + 0.4rem);\n -webkit-font-smoothing: auto;\n z-index: 9948031 !important\n}\n\n#fides-modal-link {\n cursor: pointer;\n display: none;\n}\n\n#fides-modal .fides-notice-toggle-title:hover {\n background-color: ").concat(theme.colors.white, " !important\n}\n\n#fides-modal .fides-modal-content {\n background-color: ").concat(theme.colors.white, " !important;\n border:0;\n font-size: 14px;\n line-height: 1.4;\n}\n\n.fides-modal-description a:focus {\n outline: 1px solid ").concat(theme.colors.black, " !important;\n}\n\n.fides-notice-toggle-title a:focus {\n outline: 1px solid ").concat(theme.colors.black, " !important;\n}\n\n#fides-modal .fides-notice-toggle, #fides-modal fides-notice-toggle-expanded {\n background-color: ").concat(theme.colors.white, " !important;\n}\n\n#fides-modal .fides-banner-button-secondary.fides-save-button {\n color: var(--fides-overlay-primary-button-background-color) !important;\n}\n\n#fides-modal .fides-modal-footer {\n background-color: ").concat(theme.colors.white, "\n}\n\n#fides-modal .fides-toggle-display {\n color: transparent;\n padding: 0;\n padding-block: 2px;\n --offset: 0.2em !important;\n --diameter: 1.2em !important;\n background-color: #828285\n}\n\n.fides-toggle .fides-toggle-input:checked + .fides-toggle-display {\n background-color: var(--fides-overlay-primary-active-color) !important;\n}\n\n#fides-modal .fides-divider {\n display: none !important\n}\n\n#fides-modal .fides-modal-title {\n text-align: left !important;\n font-size: 20px !important;\n}\n\ndiv#fides-banner-container {\n bottom: 0 !important;\n left: 0 !important;\n}\n\ndiv#fides-banner-container button.fides-banner-button {\n font-size: 16px !important;\n}\n\ndiv#fides-banner {\n line-height: var(--fides-overlay-line-height);\n color: var(--fides-overlay-body-font-color) !important;\n width: 100% !important;\n overflow-y: hidden;\n border: 0 !important;\n box-shadow: 0 0 18px rgba(0, 0, 0, 0.2) !important;\n background-color: ").concat(theme.colors.white, ";\n -webkit-font-smoothing: auto;\n bottom: 1px;\n}\n\ndiv#fides-banner:focus {\n outline: 1px solid ").concat(theme.colors.black, " !important\n}\n\ndiv#fides-banner-inner {\n display: flex;\n flex-direction: column;\n align-items: center;\n max-width: 1436px;\n margin: 0 auto;\n row-gap: 16px;\n row-gap: unset !important\n}\n\n/* Responsive banner */\n\ndiv#fides-banner-description {\n margin-top: 0;\n margin-bottom: 10px;\n}\n\ndiv#fides-banner-description span {\n line-height: 1.375rem !important;\n}\n\ndiv#fides-banner-description > div {\n text-align: center;\n}\n\ndiv#fides-banner-description > div a {\n font-weight: bold;\n}\n\ndiv#fides-button-group {\n justify-content: center;\n gap: 2em;\n background-color: transparent;\n}\n\n#fides-banner div#fides-button-group {\n margin-top: 0.5em;\n display: flex;\n display: flex;\n justify-content: center;\n background-color: transparent;\n gap: 16px !important;\n}\n\ndiv#fides-button-group .fides-banner-secondary-actions > button {\n cursor: pointer;\n text-decoration: none;\n font-weight: bold;\n padding: 10px 16px !important\n padding-top: 3px !important;\n margin-top: 0;\n border: 1px solid var(--fides-overlay-primary-color);\n border-radius: 2px;\n box-sizing: border-box;\n}\n\n#fides-banner .fides-acknowledge-button, #fides-banner .fides-manage-preferences-button {\n margin-right: 0px !important;\n}\n\n.fides-modal-footer div#fides-button-group {\n width: 100% !important\n}\n\n#fides-modal .fides-modal-button-group.fides-modal-primary-actions {\n margin-left: 0 !important;\n}\n\n.fides-gpc-label {\n display: none !important;\n}\n\nbutton.fides-banner-button.fides-banner-button-tertiary {\n background: none;\n border: none;\n padding: 0;\n color: var(--fides-overlay-link-font-color);\n text-decoration: underline;\n cursor: pointer;\n line-height: 2em;\n}\n\n/** Modal */\n\ndiv.fides-modal-content {\n line-height: var(--fides-overlay-line-height);\n color: var(--fides-overlay-body-font-color) !important;\n box-sizing: border-box;\n padding: var(--fides-overlay-padding);\n border: 1px solid var(--fides-overlay-primary-color);\n background-color: var(--fides-overlay-background-color);\n border-radius: var(--fides-overlay-component-border-radius);\n max-height: 100%;\n max-width: 100%;\n overflow-y: scroll;\n z-index: 2;\n position: fixed;\n top: 50%;\n left: 50%;\n transform: translate(-50%, -50%);\n}\n\n.fides-toggle .fides-toggle-display {\n --offset: 0.1em;\n --diameter: 1em;\n /** Because we have a \"hidden\" attr on this toggle element, some CSS libs customers use may include a global display: none on the hidden attr. To prevent our toggles from being hidden we use !important here **/\n display: inline-flex !important;\n align-items: center;\n justify-content: space-around;\n width: calc(var(--diameter) * 2 + var(--offset) * 2);\n height: calc(var(--diameter) + var(--offset) * 2);\n box-sizing: content-box;\n position: relative;\n border-radius: 100vw;\n background-color: var(--fides-overlay-inactive-color);\n transition: 250ms;\n}\n\n/* Checked/unchecked states */\n.fides-toggle .fides-toggle-input:checked + .fides-toggle-display {\n background-color: var(--fides-overlay-primary-active-color);\n}\n.fides-toggle .fides-toggle-input:checked + .fides-toggle-display::before {\n transform: translate(100%, -50%);\n}\n\n/* Disabled state */\n.fides-toggle .fides-toggle-input:disabled {\n cursor: not-allowed;\n}\n.fides-toggle .fides-toggle-input:disabled + .fides-toggle-display {\n background-color: var(--fides-overlay-disabled-color);\n}\n.fides-toggle .fides-toggle-input:disabled:checked + .fides-toggle-display {\n background-color: var(--fides-overlay-primary-active-disabled-color);\n}\n\n/* Focus ring when using keyboard */\n.fides-toggle .fides-toggle-input:focus + .fides-toggle-display {\n /* Firefox only has Highlight, not -webkit-focus-ring-color */\n outline: 1px auto Highlight;\n outline: 1px auto -webkit-focus-ring-color;\n}\n\n/* Disclosure */\n\n.fides-notice-toggle .fides-notice-toggle-title {\n border: 0;\n}\n\n#fides-modal .fides-modal-secondary-actions {\n display: none !important;\n}\n\n.fides-notice-toggle .fides-notice-toggle-trigger {\n padding-left: 4px;\n position: relative;\n left: -4px;\n}\n\n.fides-notice-toggle-trigger > .fides-flex-center.fides-justify-space-between {\n font-weight: bold\n}\n\n/* Tabs */\n\n.fides-tab-button::focus-visible {\n outline: 1px auto ").concat(theme.colors.black, ";\n}\n\n.fides-tab-button:focus:not(:focus-visible) {\n outline: 4px solid ").concat(theme.colors.hyper, " !important;\n}\n\n.fides-toggle-input.focus-visible + .fides-toggle-display,\n.fides-banner-button.fides-banner-button-primary.focus-visible,\n.fides-banner-button.fides-banner-button-secondary.focus-visible,\n.fides-banner-button.fides-banner-button-tertiary.focus-visible {\n outline: 3px solid ").concat(theme.colors.hyper, " !important;\n outline-offset: 2px;\n}\n\n/* Table */\n\n.fides-cookies-table {\n border-collapse: collapse;\n width: 100%;\n text-align: left;\n}\n\n.fides-cookies-table th {\n text-transform: uppercase;\n}\n\n.fides-cookies-table td, .fides-cookies-table th {\n border: 1px solid var(--fides-overlay-row-divider-color);\n padding-left: 1.1em;\n padding-right: 0.6em;\n}\n\n#fides-banner #fides-button-group button {\n font-weight: bold;\n padding: 10px 16px;\n margin-top: 0;\n border: 1px solid var(--fides-overlay-primary-color);\n border-radius: 2px;\n}\n\n#fides-banner #fides-button-group div:nth-child(2) > button:nth-child(1) {\n background-color: white;\n color: #3a10e5;\n}\n\n#fides-banner-button-tertiary {\n display: none;\n}\n\n#fides-banner-heading {\n display: none !important;\n}\n\ndiv#fides-banner-inner div#fides-button-group {\n flex-direction: row !important;\n}\n\n.fides-banner-description a:hover, .fides-modal-description a:hover {\n text-decoration: none;\n}\n\n#fides-banner-inner-container a.focus-visible {\n outline: 1px solid ").concat(theme.colors.black, " !important;\n}\n\ndiv#fides-banner-inner div#fides-button-group {\n padding-top: 0 !important\n}\n\n#fides-banner .fides-acknowledge-button, #fides-banner .fides-manage-preferences-button {\n width: auto !important\n}\n\n#fides-banner .fides-banner-button-group.fides-banner-primary-actions {\n align-items: flex-end !important;\n align-self: stretch !important\n}\n\n#fides-banner .fides-banner-button-group.fides-banner-secondary-actions {\n align-items: flex-start !important;\n}\n\n.fides-notice-toggle:focus-visible {\n outline: 1px solid ").concat(theme.colors.black, " !important;\n}\n\n@media (min-width: 37.5rem) {\n #fides-banner {\n padding: 0.875rem 1rem !important;\n }\n}\n\n").concat(theme.breakpoints.sm, " {\n div#fides-button-group .fides-banner-secondary-actions > button {\n padding: 4px 16px !important\n }\n\n div#fides-banner-inner {\n row-gap: 16px;\n }\n\n #fides-banner {\n padding: 0.875rem 1.25rem !important;\n }\n}\n\n@media only screen and (min-width: 1650px) {\n #fides-banner-inner {\n flex-direction: row !important;\n max-width: 1600px !important;\n }\n\n #fides-banner-inner-container {\n width: 72%;\n }\n\n #fides-banner div#fides-button-group {\n width: 28% !important;\n }\n\n div#fides-banner-description {\n margin-bottom: 0 !important;\n }\n}");
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { TrackingWindow } from './types';
|
|
2
|
-
export type GTMSettings = {
|
|
3
|
-
environment: string;
|
|
4
|
-
scope: TrackingWindow;
|
|
5
|
-
optedOutExternalTracking?: boolean;
|
|
6
|
-
enablePartytown?: boolean;
|
|
7
|
-
};
|
|
8
|
-
export declare const OPT_OUT_DATALAYER_VAR = "user_opted_out_external_tracking";
|
|
9
|
-
export declare const initializeGTM: ({ scope, environment, optedOutExternalTracking, enablePartytown, }: GTMSettings) => void;
|
package/dist/integrations/gtm.js
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
export const OPT_OUT_DATALAYER_VAR = 'user_opted_out_external_tracking';
|
|
2
|
-
export const initializeGTM = _ref => {
|
|
3
|
-
var _scope$dataLayer;
|
|
4
|
-
let scope = _ref.scope,
|
|
5
|
-
environment = _ref.environment,
|
|
6
|
-
optedOutExternalTracking = _ref.optedOutExternalTracking,
|
|
7
|
-
enablePartytown = _ref.enablePartytown;
|
|
8
|
-
(_scope$dataLayer = scope.dataLayer) !== null && _scope$dataLayer !== void 0 ? _scope$dataLayer : scope.dataLayer = [];
|
|
9
|
-
scope.dataLayer.push({
|
|
10
|
-
'gtm.start': new Date().getTime(),
|
|
11
|
-
event: 'gtm.js'
|
|
12
|
-
});
|
|
13
|
-
if (optedOutExternalTracking) {
|
|
14
|
-
scope.dataLayer.push({
|
|
15
|
-
[OPT_OUT_DATALAYER_VAR]: true
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
let preview_env = '';
|
|
19
|
-
if (environment === 'development') {
|
|
20
|
-
preview_env = '>m_auth=DoN0WSxjuUkImaph8PYXmA>m_preview=env-233';
|
|
21
|
-
} else if (environment === 'staging') {
|
|
22
|
-
preview_env = '>m_auth=VrQuCDuWXkLlTwNHJYEKTg>m_preview=env-232';
|
|
23
|
-
}
|
|
24
|
-
const gtm = document.createElement('script');
|
|
25
|
-
gtm.src = "https://www.googletagmanager.com/gtm.js?id=GTM-KTLK85W".concat(preview_env);
|
|
26
|
-
if (enablePartytown) {
|
|
27
|
-
gtm.type = 'text/partytown';
|
|
28
|
-
} else {
|
|
29
|
-
gtm.async = true;
|
|
30
|
-
}
|
|
31
|
-
document.getElementsByTagName('head')[0].appendChild(gtm);
|
|
32
|
-
if (enablePartytown) {
|
|
33
|
-
// Let Partytown know that a new script has been added.
|
|
34
|
-
window.dispatchEvent(new CustomEvent('ptupdate'));
|
|
35
|
-
}
|
|
36
|
-
};
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { TrackingWindow } from './types';
|
|
2
|
-
export type TrackingIntegrationsSettings = {
|
|
3
|
-
/**
|
|
4
|
-
* Current environment.
|
|
5
|
-
*/
|
|
6
|
-
environment: string;
|
|
7
|
-
/**
|
|
8
|
-
* Global scope (often the window) where globals such as analytics are stored.
|
|
9
|
-
*/
|
|
10
|
-
scope: TrackingWindow;
|
|
11
|
-
/**
|
|
12
|
-
* Whether user has opted out or is excluded from external tracking
|
|
13
|
-
*/
|
|
14
|
-
optedOutExternalTracking?: boolean;
|
|
15
|
-
/**
|
|
16
|
-
* id for the one trust script being used, defaults to the script for `www.codecademy.com`
|
|
17
|
-
*/
|
|
18
|
-
oneTrustScript?: string;
|
|
19
|
-
/**
|
|
20
|
-
* Use Partytown to load 3rd party scripts in a worker.
|
|
21
|
-
*/
|
|
22
|
-
enablePartytown?: boolean;
|
|
23
|
-
/**
|
|
24
|
-
* Whether to use Fides (new implementation) or OneTrust
|
|
25
|
-
*/
|
|
26
|
-
isFidesEnabled?: boolean;
|
|
27
|
-
};
|
|
28
|
-
/**
|
|
29
|
-
* @see README.md for details and usage.
|
|
30
|
-
*/
|
|
31
|
-
export declare const initializeTrackingIntegrations: ({ environment, scope, optedOutExternalTracking, oneTrustScript, enablePartytown, isFidesEnabled, }: TrackingIntegrationsSettings) => Promise<void>;
|
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import { initializeFides } from './fides';
|
|
2
|
-
import { initializeGTM } from './gtm';
|
|
3
|
-
import { initializeOneTrust } from './onetrust';
|
|
4
|
-
import { initializePartytown } from './partytown';
|
|
5
|
-
let init = false;
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* @see README.md for details and usage.
|
|
9
|
-
*/
|
|
10
|
-
export const initializeTrackingIntegrations = async _ref => {
|
|
11
|
-
let environment = _ref.environment,
|
|
12
|
-
scope = _ref.scope,
|
|
13
|
-
optedOutExternalTracking = _ref.optedOutExternalTracking,
|
|
14
|
-
oneTrustScript = _ref.oneTrustScript,
|
|
15
|
-
enablePartytown = _ref.enablePartytown,
|
|
16
|
-
isFidesEnabled = _ref.isFidesEnabled;
|
|
17
|
-
if (init) return; // Prevent multiple initializations
|
|
18
|
-
init = true;
|
|
19
|
-
if (enablePartytown) {
|
|
20
|
-
initializePartytown();
|
|
21
|
-
} else {
|
|
22
|
-
// Wait to allow any other post-hydration logic to run first
|
|
23
|
-
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
24
|
-
}
|
|
25
|
-
if (isFidesEnabled) {
|
|
26
|
-
await initializeFides();
|
|
27
|
-
} else {
|
|
28
|
-
// Load in OneTrust's banner and wait for its `OptanonWrapper` callback
|
|
29
|
-
await initializeOneTrust({
|
|
30
|
-
scope,
|
|
31
|
-
environment,
|
|
32
|
-
scriptId: oneTrustScript
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
// Load GTM
|
|
37
|
-
initializeGTM({
|
|
38
|
-
scope,
|
|
39
|
-
environment,
|
|
40
|
-
optedOutExternalTracking,
|
|
41
|
-
enablePartytown
|
|
42
|
-
});
|
|
43
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Onetrust script ID for `www.codecademy.com`, other domains require passing in a specific script ID
|
|
3
|
-
*/
|
|
4
|
-
const DEFAULT_SCRIPT_ID = 'cfa7b129-f37b-4f5a-9991-3f75ba7b85fb';
|
|
5
|
-
export const initializeOneTrust = async _ref => {
|
|
6
|
-
let environment = _ref.environment,
|
|
7
|
-
scope = _ref.scope,
|
|
8
|
-
_ref$scriptId = _ref.scriptId,
|
|
9
|
-
scriptId = _ref$scriptId === void 0 ? DEFAULT_SCRIPT_ID : _ref$scriptId;
|
|
10
|
-
const script = document.createElement('script');
|
|
11
|
-
script.setAttribute('async', 'true');
|
|
12
|
-
script.setAttribute('src', 'https://cdn.cookielaw.org/scripttemplates/otSDKStub.js');
|
|
13
|
-
script.setAttribute('type', 'text/javascript');
|
|
14
|
-
script.setAttribute('data-domain-script', "".concat(scriptId).concat(environment === 'production' ? '' : '-test'));
|
|
15
|
-
document.body.appendChild(script);
|
|
16
|
-
const style = document.createElement('style');
|
|
17
|
-
style.textContent = rawStyles;
|
|
18
|
-
document.body.appendChild(style);
|
|
19
|
-
return new Promise(resolve => {
|
|
20
|
-
scope.OptanonWrapper = () => {
|
|
21
|
-
var _scope$dataLayer, _script$parentNode;
|
|
22
|
-
(_scope$dataLayer = scope.dataLayer) !== null && _scope$dataLayer !== void 0 ? _scope$dataLayer : scope.dataLayer = [];
|
|
23
|
-
scope.dataLayer.push({
|
|
24
|
-
event: 'OneTrustGroupsUpdated'
|
|
25
|
-
});
|
|
26
|
-
resolve();
|
|
27
|
-
(_script$parentNode = script.parentNode) === null || _script$parentNode === void 0 ? void 0 : _script$parentNode.removeChild(script);
|
|
28
|
-
};
|
|
29
|
-
});
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
// For now, these three values duplicate theme colors from gamut-styles
|
|
33
|
-
// We don't want to take a full dependency on that package here...
|
|
34
|
-
const rawStyles = "\n:root {\n --onetrust-brand-purple: #3A10E5;\n --onetrust-color-gray-500: #828285;\n --onetrust-color-white: #fff;\n}\n\n#onetrust-banner-sdk {\n padding: 1rem !important;\n}\n#onetrust-banner-sdk > .ot-sdk-container {\n width: 100% !important;\n}\n#onetrust-banner-sdk > .ot-sdk-container > .ot-sdk-row {\n display: flex !important;\n flex-direction: column !important;\n align-items: center !important;\n max-width: 1436px !important;\n margin: 0 auto !important;\n}\n#onetrust-banner-sdk > .ot-sdk-container > .ot-sdk-row:after {\n content: none !important;\n}\n#onetrust-banner-sdk > div > .ot-sdk-container > .ot-sdk-row {\n display: flex !important;\n flex-direction: column !important;\n align-items: center !important;\n max-width: 1436px !important;\n margin: 0 auto !important;\n}\n#onetrust-banner-sdk > div > .ot-sdk-container > .ot-sdk-row:after {\n content: none !important;\n}\n#onetrust-group-container {\n display: flex !important;\n justify-content: center;\n float: none !important;\n width: 100% !important;\n max-width: 1148px !important;\n margin-left: 0 !important;\n margin-bottom: 0.625rem !important;\n}\n\n#onetrust-policy,\n#onetrust-policy-text {\n margin: 0 !important;\n font-size: 0.875rem !important;\n line-height: 1.375rem !important;\n text-align: center !important;\n float: none !important;\n}\n#onetrust-policy-text a {\n text-decoration: none;\n line-height: 26px !important;\n margin-left: 0 !important;\n}\n#onetrust-button-group-parent {\n position: relative !important;\n top: initial !important;\n left: initial !important;\n transform: initial !important;\n width: 264px !important;\n margin: 0 !important;\n padding: 0 !important;\n float: none !important;\n}\n#onetrust-button-group {\n display: flex !important;\n margin: 0 !important;\n}\n#onetrust-pc-btn-handler, #onetrust-accept-btn-handler {\n min-width: initial !important;\n padding: 0.375rem 1rem !important;\n margin: 0 !important;\n opacity: 1 !important;\n border-radius: 2px !important;\n line-height: 1.5 !important;\n user-select: none !important;\n font-size: 1rem !important;\n}\n#onetrust-pc-btn-handler:focus, #onetrust-accept-btn-handler:focus {\n box-shadow: 0 0 0 2px var(--onetrust-color-white), 0 0 0 4px var(--onetrust-brand-purple);\n text-decoration: none !important;\n outline: none !important;\n}\n#onetrust-pc-btn-handler{\n color: var(--onetrust-brand-purple) !important;\n border: 1px solid var(--onetrust-brand-purple)!important;\n background: var(--onetrust-color-white) !important\n}\n#onetrust-accept-btn-handler {\n color: var(--onetrust-color-white) !important;\n background: var(--onetrust-brand-purple)!important;\n margin-left: 1rem !important;\n}\n#onetrust-close-btn-container {\n display: none !important;\n}\n\n.pc-logo {\n display: none !important;\n}\n\n#accept-recommended-btn-handler,\n.ot-pc-refuse-all-handler,\n.save-preference-btn-handler {\n margin-left: 4px !important;\n font-size: 14px !important;\n}\n\n#accept-recommended-btn-handler:focus,\n#onetrust-pc-sdk .ot-pc-refuse-all-handler:focus,\n#onetrust-pc-sdk .save-preference-btn-handler:focus {\n box-shadow: 0 0 0 2px var(--onetrust-color-white), 0 0 0 4px var(--onetrust-brand-purple);\n text-decoration: none !important;\n outline: none !important;\n opacity: 1 !important;\n}\n\n.ot-switch-label {\n border: 1px solid var(--onetrust-color-gray-500) !important;\n background-color: var(--onetrust-color-gray-500) !important;\n}\n\n.ot-switch-nob {\n background: var(--onetrust-color-white) !important;\n}\n\n.ot-switch-inner:before {\n background-color: var(--onetrust-brand-purple) !important;\n}\n\n.switch-checkbox:checked+.ot-switch-label .ot-switch-nob {\n border-color: var(--onetrust-brand-purple) !important;\n}\n\n.ot-pc-footer-logo {\n display: none !important;\n}\n\n#onetrust-banner-sdk>.ot-sdk-container {\n overflow: visible !important;\n}\n\n#onetrust-pc-sdk .category-item .ot-switch.ot-toggle input:focus + .ot-switch-label {\n \toutline-color: var(--onetrust-brand-purple) !important;\n}\n#onetrust-pc-sdk .category-item .ot-switch.ot-toggle input:focus+.ot-switch-label {\n outline-width: 3px !important;\n outline-offset: 2px !important;\n}\n\n@media (max-width: 30rem) {\n #accept-recommended-btn-handler,\n .ot-pc-refuse-all-handler,\n .save-preference-btn-handler {\n width: 96% !important;\n }\n}\n\n@media (min-width: 37.5rem) {\n #onetrust-banner-sdk {\n padding: 0.875rem 1rem !important;\n }\n}\n@media (min-width: 48rem) {\n #onetrust-banner-sdk {\n padding: 0.875rem 1.25rem !important;\n }\n}\n@media (min-width: 1650px) {\n #onetrust-banner-sdk > .ot-sdk-container > .ot-sdk-row {\n flex-direction: row !important;\n justify-content: space-between !important;\n }\n #onetrust-banner-sdk > div > .ot-sdk-container > .ot-sdk-row {\n flex-direction: row !important;\n justify-content: space-between !important;\n }\n #onetrust-group-container {\n margin-bottom: 0 !important;\n }\n #onetrust-button-group {\n flex-direction: row !important;\n }\n}\n";
|
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
export const partytownConfig = () => ({
|
|
2
|
-
forward: ['dataLayer.push',
|
|
3
|
-
// for GTM
|
|
4
|
-
'fbq',
|
|
5
|
-
// for Facebook Pixel
|
|
6
|
-
'_hsq.push' // for Hubspot
|
|
7
|
-
],
|
|
8
|
-
lib: '/partytown/',
|
|
9
|
-
// path for loading from static asset CMS
|
|
10
|
-
loadScriptsOnMainThread: [/pepperjam/,
|
|
11
|
-
// Pepperjam
|
|
12
|
-
/snap/,
|
|
13
|
-
// Snap Pixel
|
|
14
|
-
/lightboxcdn/,
|
|
15
|
-
// Digioh
|
|
16
|
-
/linkedin/,
|
|
17
|
-
// linkedin
|
|
18
|
-
/debug/ // GTM debugging
|
|
19
|
-
],
|
|
20
|
-
// This function runs in a worker and can't access other vars in this file.
|
|
21
|
-
resolveUrl(url, location, type) {
|
|
22
|
-
// Hoist GTM iframe out of Partytown so that GTM can create its own worker normally.
|
|
23
|
-
if (url.hostname === 'www.googletagmanager.com' && type === 'iframe') {
|
|
24
|
-
new BroadcastChannel('gtm-iframe').postMessage(url.href);
|
|
25
|
-
return new URL('data:'); // blank url to prevent iframe within Partytown
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/*
|
|
29
|
-
* Proxy Facebook Pixel requests to resolve CORS issues
|
|
30
|
-
* see https://partytown.builder.io/facebook-pixel#proxy-requests
|
|
31
|
-
*/
|
|
32
|
-
if (url.hostname === 'connect.facebook.net') {
|
|
33
|
-
return new URL("partytown-fb".concat(url.pathname).concat(url.search), location.origin);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/*
|
|
37
|
-
* Proxy Reddit Pixel requests to resolve CORS issues
|
|
38
|
-
*/
|
|
39
|
-
if (url.hostname === 'www.redditstatic.com') {
|
|
40
|
-
return new URL("partytown-reddit".concat(url.pathname).concat(url.search), location.origin);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
/*
|
|
44
|
-
* Proxy Google Ads requests to resolve CORS issues
|
|
45
|
-
*/
|
|
46
|
-
if (url.hostname === 'googleads.g.doubleclick.net') {
|
|
47
|
-
let p = url.pathname;
|
|
48
|
-
if (p.endsWith('/')) {
|
|
49
|
-
// Google Ads returns a redirect if path has a trailing slash
|
|
50
|
-
p = p.slice(0, -1);
|
|
51
|
-
}
|
|
52
|
-
return new URL("partytown-googleads".concat(p).concat(url.search), location.origin);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
/*
|
|
56
|
-
* Proxy Bing requests to resolve CORS issues
|
|
57
|
-
*/
|
|
58
|
-
if (url.hostname === 'bat.bing.com') {
|
|
59
|
-
return new URL("partytown-bing".concat(url.pathname).concat(url.search), location.origin);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/*
|
|
63
|
-
* Proxy YouTube requests to resolve CORS issues
|
|
64
|
-
*/
|
|
65
|
-
if (url.hostname === 'www.youtube.com') {
|
|
66
|
-
return new URL("partytown-youtube".concat(url.pathname).concat(url.search), location.origin);
|
|
67
|
-
}
|
|
68
|
-
return url;
|
|
69
|
-
}
|
|
70
|
-
});
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function gtmDoubleFrame(src: string): void;
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
function hiddenFrame(doc) {
|
|
2
|
-
const f = doc.createElement('iframe');
|
|
3
|
-
f.setAttribute('height', '0');
|
|
4
|
-
f.setAttribute('width', '0');
|
|
5
|
-
f.setAttribute('style', 'display: none; visibility: hidden;');
|
|
6
|
-
doc.body.appendChild(f);
|
|
7
|
-
return f;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
// Double frame is what GTM would normally use without Partytown.
|
|
11
|
-
export function gtmDoubleFrame(src) {
|
|
12
|
-
const outerFrame = hiddenFrame(document);
|
|
13
|
-
const innerFrame = hiddenFrame(outerFrame.contentWindow.document);
|
|
14
|
-
innerFrame.src = src;
|
|
15
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export declare function initializePartytown(): void;
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { partytownSnippet } from '@qwik.dev/partytown/integration';
|
|
2
|
-
import { partytownConfig } from './config';
|
|
3
|
-
import { gtmDoubleFrame } from './gtmDoubleFrame';
|
|
4
|
-
|
|
5
|
-
// Encapsulate to avoid collision of global vars aliased in minification.
|
|
6
|
-
const encapsulate = js => "(() => {".concat(js, "})();");
|
|
7
|
-
export function initializePartytown() {
|
|
8
|
-
const ptScript = document.createElement('script');
|
|
9
|
-
ptScript.innerHTML = encapsulate(partytownSnippet(partytownConfig()));
|
|
10
|
-
document.head.appendChild(ptScript);
|
|
11
|
-
new BroadcastChannel('gtm-iframe').onmessage = _ref => {
|
|
12
|
-
let data = _ref.data;
|
|
13
|
-
gtmDoubleFrame(data);
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
/*
|
|
17
|
-
* Img elements added by GTM tags for Google Ads normally set themselves as
|
|
18
|
-
* position:absolute. Since Partytown prevents this, a stylesheet is added to
|
|
19
|
-
* restore the style (and remove the added whitespace).
|
|
20
|
-
*/
|
|
21
|
-
const styles = document.createElement('style');
|
|
22
|
-
styles.innerText = "body > img[aria-hidden=true] { position: absolute; }";
|
|
23
|
-
document.head.appendChild(styles);
|
|
24
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|