@blotoutio/providers-spotify-sdk 1.17.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/README.md ADDED
@@ -0,0 +1,15 @@
1
+ # providers-spotify-sdk
2
+
3
+ This library was generated with [Nx](https://nx.dev).
4
+
5
+ ## Building
6
+
7
+ Run `nx build providers-spotify-sdk` to build the library.
8
+
9
+ ## Running unit tests
10
+
11
+ Run `nx test providers-spotify-sdk` to execute the unit tests via [Jest](https://jestjs.io).
12
+
13
+ ## Running lint
14
+
15
+ Run `nx lint providers-spotify-sdk` to execute the lint via [ESLint](https://eslint.org/).
package/index.cjs.js ADDED
@@ -0,0 +1,357 @@
1
+ 'use strict';
2
+
3
+ const packageName = 'spotify';
4
+
5
+ const init = ({ manifest }) => {
6
+ var _a, _b;
7
+ if (typeof window === 'undefined' ||
8
+ typeof document === 'undefined' ||
9
+ !((_a = manifest === null || manifest === void 0 ? void 0 : manifest.variables) === null || _a === void 0 ? void 0 : _a['spotifyPixelId']) ||
10
+ !(manifest === null || manifest === void 0 ? void 0 : manifest.variables['enableBrowser'])) {
11
+ return;
12
+ }
13
+ const spotifyScriptURL = 'https://pixel.byspotify.com/ping.min.js';
14
+ const scriptId = 'spdt-capture';
15
+ if (!document.getElementById(scriptId)) {
16
+ window.spdt =
17
+ window.spdt ||
18
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
19
+ function (...args) {
20
+ (window.spdt.q = window.spdt.q || []).push(args);
21
+ };
22
+ const element = document.createElement('script');
23
+ element.id = scriptId;
24
+ element.async = true;
25
+ element.src = spotifyScriptURL;
26
+ const firstScript = document.getElementsByTagName('script')[0];
27
+ (_b = firstScript === null || firstScript === void 0 ? void 0 : firstScript.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(element, firstScript);
28
+ window.spdt('conf', { key: manifest.variables['spotifyPixelId'] });
29
+ }
30
+ };
31
+
32
+ const sha = async (algorithm, text) => {
33
+ if (!text) {
34
+ return '';
35
+ }
36
+ const encodedText = new TextEncoder().encode(text);
37
+ const hashBuffer = await crypto.subtle.digest({
38
+ name: algorithm,
39
+ }, encodedText);
40
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
41
+ return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
42
+ };
43
+ const sha256 = async (text) => {
44
+ return await sha('SHA-256', text);
45
+ };
46
+
47
+ const user = ({ userId, data }) => {
48
+ if (typeof window === 'undefined' ||
49
+ typeof window.spdt !== 'function' ||
50
+ !data) {
51
+ return;
52
+ }
53
+ const payload = {};
54
+ payload['id'] = userId;
55
+ if (data['email']) {
56
+ sha256(data['email'].toString())
57
+ .then((hashedEmail) => {
58
+ payload['email'] = hashedEmail;
59
+ window.spdt('alias', payload);
60
+ })
61
+ .catch(() => undefined);
62
+ }
63
+ else if (payload['id']) {
64
+ window.spdt('alias', { id: payload['id'] });
65
+ }
66
+ };
67
+
68
+ const parseNumericValue = (value) => {
69
+ const parsed = typeof value === 'number' ? value : parseFloat(value);
70
+ return Number.isFinite(parsed) ? parsed : undefined;
71
+ };
72
+
73
+ const getEventData = (eventName, data, options = {}) => {
74
+ var _a, _b, _c, _d, _e, _f, _g, _h;
75
+ switch (eventName) {
76
+ case 'Lead': {
77
+ return {
78
+ name: 'lead',
79
+ data: {
80
+ category: data.category,
81
+ currency: data.currency,
82
+ value: data.value,
83
+ type: data.name,
84
+ },
85
+ };
86
+ }
87
+ case 'AddToCart': {
88
+ const parsedValue = parseNumericValue(data.value);
89
+ if (parsedValue === undefined) {
90
+ console.error('addtocart : data.value should be a number');
91
+ return;
92
+ }
93
+ if (typeof data.currency !== 'string') {
94
+ console.error('addtocart : data.currecy should be a string');
95
+ return;
96
+ }
97
+ const currency = data.currency;
98
+ const items = [];
99
+ for (const item of (_a = data.contents) !== null && _a !== void 0 ? _a : []) {
100
+ const parsedItemPrice = parseNumericValue(item === null || item === void 0 ? void 0 : item.item_price);
101
+ if (parsedItemPrice === undefined) {
102
+ console.error('addtocart : content item_price should be a number');
103
+ continue;
104
+ }
105
+ const parsedItemQuantity = parseNumericValue(item === null || item === void 0 ? void 0 : item.quantity);
106
+ if (parsedItemQuantity === undefined) {
107
+ console.error('addtocart : content quantity should be a number');
108
+ continue;
109
+ }
110
+ if (typeof (item === null || item === void 0 ? void 0 : item.id) !== 'string') {
111
+ console.error('addtocart : content id should be a string');
112
+ continue;
113
+ }
114
+ items.push({
115
+ value: parsedItemPrice * parsedItemQuantity,
116
+ currency,
117
+ quantity: parsedItemQuantity,
118
+ product_id: item.id,
119
+ product_name: item.title,
120
+ product_type: item.type,
121
+ product_vendor: item.brand,
122
+ variant_id: item.variantId,
123
+ variant_name: item.sku,
124
+ });
125
+ }
126
+ return {
127
+ name: 'addtocart',
128
+ data: items,
129
+ };
130
+ }
131
+ case 'ViewContent': {
132
+ if (typeof data.currency !== 'string') {
133
+ console.error('product : data.currency should be a string');
134
+ return;
135
+ }
136
+ const items = [];
137
+ for (const item of (_b = data.contents) !== null && _b !== void 0 ? _b : []) {
138
+ const parsedItemPrice = parseNumericValue(item === null || item === void 0 ? void 0 : item.item_price);
139
+ if (parsedItemPrice === undefined) {
140
+ console.error('checkout : content item_price should be a number');
141
+ continue;
142
+ }
143
+ const parsedItemQuantity = parseNumericValue(item === null || item === void 0 ? void 0 : item.quantity);
144
+ if (parsedItemQuantity === undefined) {
145
+ console.error('checkout : content quantity should be a number');
146
+ continue;
147
+ }
148
+ if (typeof (item === null || item === void 0 ? void 0 : item.id) !== 'string') {
149
+ console.error('checkout : content id should be a string');
150
+ continue;
151
+ }
152
+ items.push({
153
+ value: parsedItemPrice * parsedItemQuantity,
154
+ currency: data.currency,
155
+ product_id: item.id,
156
+ product_name: item.title,
157
+ product_type: item.sku,
158
+ product_vendor: item.brand,
159
+ });
160
+ }
161
+ return {
162
+ name: 'product',
163
+ data: items,
164
+ };
165
+ }
166
+ case 'InitiateCheckout': {
167
+ const parsedValue = parseNumericValue(data.value);
168
+ if (parsedValue === undefined) {
169
+ console.error('checkout : data.value should be a number');
170
+ return;
171
+ }
172
+ if (typeof data.currency !== 'string') {
173
+ console.error('checkout : data.currency should be a string');
174
+ return;
175
+ }
176
+ const value = parsedValue;
177
+ const currency = data.currency;
178
+ const discount_code = (_d = (_c = data.discounts) === null || _c === void 0 ? void 0 : _c.map((discount) => discount.code).join(' ,')) !== null && _d !== void 0 ? _d : '';
179
+ const items = [];
180
+ for (const item of (_e = data.contents) !== null && _e !== void 0 ? _e : []) {
181
+ const parsedItemPrice = parseNumericValue(item === null || item === void 0 ? void 0 : item.item_price);
182
+ if (parsedItemPrice === undefined) {
183
+ console.error('checkout : content item_price should be a number');
184
+ continue;
185
+ }
186
+ const parsedItemQuantity = parseNumericValue(item === null || item === void 0 ? void 0 : item.quantity);
187
+ if (parsedItemQuantity === undefined) {
188
+ console.error('checkout : content quantity should be a number');
189
+ continue;
190
+ }
191
+ if (typeof (item === null || item === void 0 ? void 0 : item.id) !== 'string') {
192
+ console.error('checkout : content id should be a string');
193
+ continue;
194
+ }
195
+ items.push({
196
+ value: parsedItemPrice,
197
+ quantity: parsedItemQuantity,
198
+ product_id: item.id,
199
+ product_name: item.title,
200
+ product_type: item.sku,
201
+ product_vendor: item.brand,
202
+ });
203
+ }
204
+ return {
205
+ name: 'checkout',
206
+ data: {
207
+ value,
208
+ currency,
209
+ discount_code,
210
+ line_items: items,
211
+ },
212
+ };
213
+ }
214
+ case 'Purchase': {
215
+ const { isNewCustomer } = options;
216
+ if (isNewCustomer === undefined) {
217
+ console.error('purchase : isNewCustomer is not defined');
218
+ return;
219
+ }
220
+ const parsedValue = parseNumericValue(data.value);
221
+ if (parsedValue === undefined) {
222
+ console.error('purchase : data.value should be a number');
223
+ return;
224
+ }
225
+ if (typeof data.currency !== 'string') {
226
+ console.error('purchase : data.currency should be a string');
227
+ return;
228
+ }
229
+ if (typeof data.orderId !== 'string') {
230
+ console.error('purchase : data.orderId should be a string');
231
+ return;
232
+ }
233
+ const value = parsedValue;
234
+ const currency = data.currency;
235
+ const order_id = data.orderId;
236
+ const discount_code = (_g = ((_f = data.discounts) !== null && _f !== void 0 ? _f : []).map((discount) => discount.code).join(' ,')) !== null && _g !== void 0 ? _g : '';
237
+ const items = [];
238
+ for (const item of (_h = data.contents) !== null && _h !== void 0 ? _h : []) {
239
+ const parsedItemPrice = parseNumericValue(item === null || item === void 0 ? void 0 : item.item_price);
240
+ if (parsedItemPrice === undefined) {
241
+ console.error('purchase : content item_price should be a number');
242
+ continue;
243
+ }
244
+ const parsedItemQuantity = parseNumericValue(item === null || item === void 0 ? void 0 : item.quantity);
245
+ if (parsedItemQuantity === undefined) {
246
+ console.error('purchase : content quantity should be a number');
247
+ continue;
248
+ }
249
+ if (typeof (item === null || item === void 0 ? void 0 : item.id) !== 'string') {
250
+ console.error('purchase : content id should be a string');
251
+ continue;
252
+ }
253
+ items.push({
254
+ value: parsedItemPrice,
255
+ quantity: parsedItemQuantity,
256
+ product_id: item.id,
257
+ product_name: item.title,
258
+ product_type: item.type,
259
+ product_vendor: item.brand,
260
+ variant_id: item.variantId,
261
+ variant_name: item.sku,
262
+ });
263
+ }
264
+ const quantity = items.reduce((sum, item) => sum + item.quantity, 0);
265
+ return {
266
+ name: 'purchase',
267
+ data: {
268
+ value,
269
+ currency,
270
+ order_id,
271
+ discount_code,
272
+ quantity,
273
+ line_items: items,
274
+ is_new_customer: isNewCustomer,
275
+ },
276
+ };
277
+ }
278
+ case 'PageView': {
279
+ return {
280
+ name: 'view',
281
+ data: {},
282
+ };
283
+ }
284
+ }
285
+ return;
286
+ };
287
+
288
+ const isNewCustomer = async (getData) => {
289
+ const edgeData = await new Promise((resolve) => getData(['is_new_customer'], resolve));
290
+ /*
291
+ if we are getting undefined value for is_new_customer
292
+ from the custom table, we should send is_new_customer as true
293
+ to spotify.
294
+ */
295
+ return (edgeData['is_new_customer'] === undefined ||
296
+ edgeData['is_new_customer'] === 'true');
297
+ };
298
+
299
+ const handleTag = async ({ data, eventName, getEdgeData, }) => {
300
+ var _a, _b, _c;
301
+ if (!eventName || !data || !getEdgeData) {
302
+ return;
303
+ }
304
+ let options = {};
305
+ if (eventName === 'Purchase') {
306
+ const is_new_customer = await isNewCustomer(getEdgeData);
307
+ options = { isNewCustomer: is_new_customer };
308
+ }
309
+ const event = getEventData(eventName, data, options);
310
+ if (event) {
311
+ const { name, data } = event;
312
+ if (data && Array.isArray(data)) {
313
+ if (data.length === 0) {
314
+ (_a = window.spdt) === null || _a === void 0 ? void 0 : _a.call(window, name, []);
315
+ }
316
+ else {
317
+ for (const item of data) {
318
+ (_b = window.spdt) === null || _b === void 0 ? void 0 : _b.call(window, name, item);
319
+ }
320
+ }
321
+ }
322
+ else {
323
+ (_c = window.spdt) === null || _c === void 0 ? void 0 : _c.call(window, name, data);
324
+ }
325
+ }
326
+ };
327
+
328
+ const tag = ({ data, eventName, getEdgeData }) => {
329
+ const payload = {
330
+ sdkVersion: "1.17.0" ,
331
+ };
332
+ if (typeof window !== 'undefined' && typeof window.spdt === 'function') {
333
+ handleTag({ data, eventName, getEdgeData });
334
+ }
335
+ return payload;
336
+ };
337
+
338
+ // eslint-disable-next-line @nx/enforce-module-boundaries
339
+ const data = {
340
+ name: packageName,
341
+ init,
342
+ user,
343
+ tag,
344
+ };
345
+ try {
346
+ if (window) {
347
+ if (!window.edgetagProviders) {
348
+ window.edgetagProviders = [];
349
+ }
350
+ window.edgetagProviders.push(data);
351
+ }
352
+ }
353
+ catch {
354
+ // No window
355
+ }
356
+
357
+ module.exports = data;
package/index.d.ts ADDED
@@ -0,0 +1 @@
1
+ declare module '@blotoutio/providers-spotify-sdk'
package/index.js ADDED
@@ -0,0 +1,360 @@
1
+ var ProvidersSpotifySdk = (function () {
2
+ 'use strict';
3
+
4
+ const packageName = 'spotify';
5
+
6
+ const init = ({ manifest }) => {
7
+ var _a, _b;
8
+ if (typeof window === 'undefined' ||
9
+ typeof document === 'undefined' ||
10
+ !((_a = manifest === null || manifest === void 0 ? void 0 : manifest.variables) === null || _a === void 0 ? void 0 : _a['spotifyPixelId']) ||
11
+ !(manifest === null || manifest === void 0 ? void 0 : manifest.variables['enableBrowser'])) {
12
+ return;
13
+ }
14
+ const spotifyScriptURL = 'https://pixel.byspotify.com/ping.min.js';
15
+ const scriptId = 'spdt-capture';
16
+ if (!document.getElementById(scriptId)) {
17
+ window.spdt =
18
+ window.spdt ||
19
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
20
+ function (...args) {
21
+ (window.spdt.q = window.spdt.q || []).push(args);
22
+ };
23
+ const element = document.createElement('script');
24
+ element.id = scriptId;
25
+ element.async = true;
26
+ element.src = spotifyScriptURL;
27
+ const firstScript = document.getElementsByTagName('script')[0];
28
+ (_b = firstScript === null || firstScript === void 0 ? void 0 : firstScript.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(element, firstScript);
29
+ window.spdt('conf', { key: manifest.variables['spotifyPixelId'] });
30
+ }
31
+ };
32
+
33
+ const sha = async (algorithm, text) => {
34
+ if (!text) {
35
+ return '';
36
+ }
37
+ const encodedText = new TextEncoder().encode(text);
38
+ const hashBuffer = await crypto.subtle.digest({
39
+ name: algorithm,
40
+ }, encodedText);
41
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
42
+ return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
43
+ };
44
+ const sha256 = async (text) => {
45
+ return await sha('SHA-256', text);
46
+ };
47
+
48
+ const user = ({ userId, data }) => {
49
+ if (typeof window === 'undefined' ||
50
+ typeof window.spdt !== 'function' ||
51
+ !data) {
52
+ return;
53
+ }
54
+ const payload = {};
55
+ payload['id'] = userId;
56
+ if (data['email']) {
57
+ sha256(data['email'].toString())
58
+ .then((hashedEmail) => {
59
+ payload['email'] = hashedEmail;
60
+ window.spdt('alias', payload);
61
+ })
62
+ .catch(() => undefined);
63
+ }
64
+ else if (payload['id']) {
65
+ window.spdt('alias', { id: payload['id'] });
66
+ }
67
+ };
68
+
69
+ const parseNumericValue = (value) => {
70
+ const parsed = typeof value === 'number' ? value : parseFloat(value);
71
+ return Number.isFinite(parsed) ? parsed : undefined;
72
+ };
73
+
74
+ const getEventData = (eventName, data, options = {}) => {
75
+ var _a, _b, _c, _d, _e, _f, _g, _h;
76
+ switch (eventName) {
77
+ case 'Lead': {
78
+ return {
79
+ name: 'lead',
80
+ data: {
81
+ category: data.category,
82
+ currency: data.currency,
83
+ value: data.value,
84
+ type: data.name,
85
+ },
86
+ };
87
+ }
88
+ case 'AddToCart': {
89
+ const parsedValue = parseNumericValue(data.value);
90
+ if (parsedValue === undefined) {
91
+ console.error('addtocart : data.value should be a number');
92
+ return;
93
+ }
94
+ if (typeof data.currency !== 'string') {
95
+ console.error('addtocart : data.currecy should be a string');
96
+ return;
97
+ }
98
+ const currency = data.currency;
99
+ const items = [];
100
+ for (const item of (_a = data.contents) !== null && _a !== void 0 ? _a : []) {
101
+ const parsedItemPrice = parseNumericValue(item === null || item === void 0 ? void 0 : item.item_price);
102
+ if (parsedItemPrice === undefined) {
103
+ console.error('addtocart : content item_price should be a number');
104
+ continue;
105
+ }
106
+ const parsedItemQuantity = parseNumericValue(item === null || item === void 0 ? void 0 : item.quantity);
107
+ if (parsedItemQuantity === undefined) {
108
+ console.error('addtocart : content quantity should be a number');
109
+ continue;
110
+ }
111
+ if (typeof (item === null || item === void 0 ? void 0 : item.id) !== 'string') {
112
+ console.error('addtocart : content id should be a string');
113
+ continue;
114
+ }
115
+ items.push({
116
+ value: parsedItemPrice * parsedItemQuantity,
117
+ currency,
118
+ quantity: parsedItemQuantity,
119
+ product_id: item.id,
120
+ product_name: item.title,
121
+ product_type: item.type,
122
+ product_vendor: item.brand,
123
+ variant_id: item.variantId,
124
+ variant_name: item.sku,
125
+ });
126
+ }
127
+ return {
128
+ name: 'addtocart',
129
+ data: items,
130
+ };
131
+ }
132
+ case 'ViewContent': {
133
+ if (typeof data.currency !== 'string') {
134
+ console.error('product : data.currency should be a string');
135
+ return;
136
+ }
137
+ const items = [];
138
+ for (const item of (_b = data.contents) !== null && _b !== void 0 ? _b : []) {
139
+ const parsedItemPrice = parseNumericValue(item === null || item === void 0 ? void 0 : item.item_price);
140
+ if (parsedItemPrice === undefined) {
141
+ console.error('checkout : content item_price should be a number');
142
+ continue;
143
+ }
144
+ const parsedItemQuantity = parseNumericValue(item === null || item === void 0 ? void 0 : item.quantity);
145
+ if (parsedItemQuantity === undefined) {
146
+ console.error('checkout : content quantity should be a number');
147
+ continue;
148
+ }
149
+ if (typeof (item === null || item === void 0 ? void 0 : item.id) !== 'string') {
150
+ console.error('checkout : content id should be a string');
151
+ continue;
152
+ }
153
+ items.push({
154
+ value: parsedItemPrice * parsedItemQuantity,
155
+ currency: data.currency,
156
+ product_id: item.id,
157
+ product_name: item.title,
158
+ product_type: item.sku,
159
+ product_vendor: item.brand,
160
+ });
161
+ }
162
+ return {
163
+ name: 'product',
164
+ data: items,
165
+ };
166
+ }
167
+ case 'InitiateCheckout': {
168
+ const parsedValue = parseNumericValue(data.value);
169
+ if (parsedValue === undefined) {
170
+ console.error('checkout : data.value should be a number');
171
+ return;
172
+ }
173
+ if (typeof data.currency !== 'string') {
174
+ console.error('checkout : data.currency should be a string');
175
+ return;
176
+ }
177
+ const value = parsedValue;
178
+ const currency = data.currency;
179
+ const discount_code = (_d = (_c = data.discounts) === null || _c === void 0 ? void 0 : _c.map((discount) => discount.code).join(' ,')) !== null && _d !== void 0 ? _d : '';
180
+ const items = [];
181
+ for (const item of (_e = data.contents) !== null && _e !== void 0 ? _e : []) {
182
+ const parsedItemPrice = parseNumericValue(item === null || item === void 0 ? void 0 : item.item_price);
183
+ if (parsedItemPrice === undefined) {
184
+ console.error('checkout : content item_price should be a number');
185
+ continue;
186
+ }
187
+ const parsedItemQuantity = parseNumericValue(item === null || item === void 0 ? void 0 : item.quantity);
188
+ if (parsedItemQuantity === undefined) {
189
+ console.error('checkout : content quantity should be a number');
190
+ continue;
191
+ }
192
+ if (typeof (item === null || item === void 0 ? void 0 : item.id) !== 'string') {
193
+ console.error('checkout : content id should be a string');
194
+ continue;
195
+ }
196
+ items.push({
197
+ value: parsedItemPrice,
198
+ quantity: parsedItemQuantity,
199
+ product_id: item.id,
200
+ product_name: item.title,
201
+ product_type: item.sku,
202
+ product_vendor: item.brand,
203
+ });
204
+ }
205
+ return {
206
+ name: 'checkout',
207
+ data: {
208
+ value,
209
+ currency,
210
+ discount_code,
211
+ line_items: items,
212
+ },
213
+ };
214
+ }
215
+ case 'Purchase': {
216
+ const { isNewCustomer } = options;
217
+ if (isNewCustomer === undefined) {
218
+ console.error('purchase : isNewCustomer is not defined');
219
+ return;
220
+ }
221
+ const parsedValue = parseNumericValue(data.value);
222
+ if (parsedValue === undefined) {
223
+ console.error('purchase : data.value should be a number');
224
+ return;
225
+ }
226
+ if (typeof data.currency !== 'string') {
227
+ console.error('purchase : data.currency should be a string');
228
+ return;
229
+ }
230
+ if (typeof data.orderId !== 'string') {
231
+ console.error('purchase : data.orderId should be a string');
232
+ return;
233
+ }
234
+ const value = parsedValue;
235
+ const currency = data.currency;
236
+ const order_id = data.orderId;
237
+ const discount_code = (_g = ((_f = data.discounts) !== null && _f !== void 0 ? _f : []).map((discount) => discount.code).join(' ,')) !== null && _g !== void 0 ? _g : '';
238
+ const items = [];
239
+ for (const item of (_h = data.contents) !== null && _h !== void 0 ? _h : []) {
240
+ const parsedItemPrice = parseNumericValue(item === null || item === void 0 ? void 0 : item.item_price);
241
+ if (parsedItemPrice === undefined) {
242
+ console.error('purchase : content item_price should be a number');
243
+ continue;
244
+ }
245
+ const parsedItemQuantity = parseNumericValue(item === null || item === void 0 ? void 0 : item.quantity);
246
+ if (parsedItemQuantity === undefined) {
247
+ console.error('purchase : content quantity should be a number');
248
+ continue;
249
+ }
250
+ if (typeof (item === null || item === void 0 ? void 0 : item.id) !== 'string') {
251
+ console.error('purchase : content id should be a string');
252
+ continue;
253
+ }
254
+ items.push({
255
+ value: parsedItemPrice,
256
+ quantity: parsedItemQuantity,
257
+ product_id: item.id,
258
+ product_name: item.title,
259
+ product_type: item.type,
260
+ product_vendor: item.brand,
261
+ variant_id: item.variantId,
262
+ variant_name: item.sku,
263
+ });
264
+ }
265
+ const quantity = items.reduce((sum, item) => sum + item.quantity, 0);
266
+ return {
267
+ name: 'purchase',
268
+ data: {
269
+ value,
270
+ currency,
271
+ order_id,
272
+ discount_code,
273
+ quantity,
274
+ line_items: items,
275
+ is_new_customer: isNewCustomer,
276
+ },
277
+ };
278
+ }
279
+ case 'PageView': {
280
+ return {
281
+ name: 'view',
282
+ data: {},
283
+ };
284
+ }
285
+ }
286
+ return;
287
+ };
288
+
289
+ const isNewCustomer = async (getData) => {
290
+ const edgeData = await new Promise((resolve) => getData(['is_new_customer'], resolve));
291
+ /*
292
+ if we are getting undefined value for is_new_customer
293
+ from the custom table, we should send is_new_customer as true
294
+ to spotify.
295
+ */
296
+ return (edgeData['is_new_customer'] === undefined ||
297
+ edgeData['is_new_customer'] === 'true');
298
+ };
299
+
300
+ const handleTag = async ({ data, eventName, getEdgeData, }) => {
301
+ var _a, _b, _c;
302
+ if (!eventName || !data || !getEdgeData) {
303
+ return;
304
+ }
305
+ let options = {};
306
+ if (eventName === 'Purchase') {
307
+ const is_new_customer = await isNewCustomer(getEdgeData);
308
+ options = { isNewCustomer: is_new_customer };
309
+ }
310
+ const event = getEventData(eventName, data, options);
311
+ if (event) {
312
+ const { name, data } = event;
313
+ if (data && Array.isArray(data)) {
314
+ if (data.length === 0) {
315
+ (_a = window.spdt) === null || _a === void 0 ? void 0 : _a.call(window, name, []);
316
+ }
317
+ else {
318
+ for (const item of data) {
319
+ (_b = window.spdt) === null || _b === void 0 ? void 0 : _b.call(window, name, item);
320
+ }
321
+ }
322
+ }
323
+ else {
324
+ (_c = window.spdt) === null || _c === void 0 ? void 0 : _c.call(window, name, data);
325
+ }
326
+ }
327
+ };
328
+
329
+ const tag = ({ data, eventName, getEdgeData }) => {
330
+ const payload = {
331
+ sdkVersion: "1.17.0" ,
332
+ };
333
+ if (typeof window !== 'undefined' && typeof window.spdt === 'function') {
334
+ handleTag({ data, eventName, getEdgeData });
335
+ }
336
+ return payload;
337
+ };
338
+
339
+ // eslint-disable-next-line @nx/enforce-module-boundaries
340
+ const data = {
341
+ name: packageName,
342
+ init,
343
+ user,
344
+ tag,
345
+ };
346
+ try {
347
+ if (window) {
348
+ if (!window.edgetagProviders) {
349
+ window.edgetagProviders = [];
350
+ }
351
+ window.edgetagProviders.push(data);
352
+ }
353
+ }
354
+ catch {
355
+ // No window
356
+ }
357
+
358
+ return data;
359
+
360
+ })();
package/index.mjs ADDED
@@ -0,0 +1,355 @@
1
+ const packageName = 'spotify';
2
+
3
+ const init = ({ manifest }) => {
4
+ var _a, _b;
5
+ if (typeof window === 'undefined' ||
6
+ typeof document === 'undefined' ||
7
+ !((_a = manifest === null || manifest === void 0 ? void 0 : manifest.variables) === null || _a === void 0 ? void 0 : _a['spotifyPixelId']) ||
8
+ !(manifest === null || manifest === void 0 ? void 0 : manifest.variables['enableBrowser'])) {
9
+ return;
10
+ }
11
+ const spotifyScriptURL = 'https://pixel.byspotify.com/ping.min.js';
12
+ const scriptId = 'spdt-capture';
13
+ if (!document.getElementById(scriptId)) {
14
+ window.spdt =
15
+ window.spdt ||
16
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
17
+ function (...args) {
18
+ (window.spdt.q = window.spdt.q || []).push(args);
19
+ };
20
+ const element = document.createElement('script');
21
+ element.id = scriptId;
22
+ element.async = true;
23
+ element.src = spotifyScriptURL;
24
+ const firstScript = document.getElementsByTagName('script')[0];
25
+ (_b = firstScript === null || firstScript === void 0 ? void 0 : firstScript.parentNode) === null || _b === void 0 ? void 0 : _b.insertBefore(element, firstScript);
26
+ window.spdt('conf', { key: manifest.variables['spotifyPixelId'] });
27
+ }
28
+ };
29
+
30
+ const sha = async (algorithm, text) => {
31
+ if (!text) {
32
+ return '';
33
+ }
34
+ const encodedText = new TextEncoder().encode(text);
35
+ const hashBuffer = await crypto.subtle.digest({
36
+ name: algorithm,
37
+ }, encodedText);
38
+ const hashArray = Array.from(new Uint8Array(hashBuffer));
39
+ return hashArray.map((b) => b.toString(16).padStart(2, '0')).join('');
40
+ };
41
+ const sha256 = async (text) => {
42
+ return await sha('SHA-256', text);
43
+ };
44
+
45
+ const user = ({ userId, data }) => {
46
+ if (typeof window === 'undefined' ||
47
+ typeof window.spdt !== 'function' ||
48
+ !data) {
49
+ return;
50
+ }
51
+ const payload = {};
52
+ payload['id'] = userId;
53
+ if (data['email']) {
54
+ sha256(data['email'].toString())
55
+ .then((hashedEmail) => {
56
+ payload['email'] = hashedEmail;
57
+ window.spdt('alias', payload);
58
+ })
59
+ .catch(() => undefined);
60
+ }
61
+ else if (payload['id']) {
62
+ window.spdt('alias', { id: payload['id'] });
63
+ }
64
+ };
65
+
66
+ const parseNumericValue = (value) => {
67
+ const parsed = typeof value === 'number' ? value : parseFloat(value);
68
+ return Number.isFinite(parsed) ? parsed : undefined;
69
+ };
70
+
71
+ const getEventData = (eventName, data, options = {}) => {
72
+ var _a, _b, _c, _d, _e, _f, _g, _h;
73
+ switch (eventName) {
74
+ case 'Lead': {
75
+ return {
76
+ name: 'lead',
77
+ data: {
78
+ category: data.category,
79
+ currency: data.currency,
80
+ value: data.value,
81
+ type: data.name,
82
+ },
83
+ };
84
+ }
85
+ case 'AddToCart': {
86
+ const parsedValue = parseNumericValue(data.value);
87
+ if (parsedValue === undefined) {
88
+ console.error('addtocart : data.value should be a number');
89
+ return;
90
+ }
91
+ if (typeof data.currency !== 'string') {
92
+ console.error('addtocart : data.currecy should be a string');
93
+ return;
94
+ }
95
+ const currency = data.currency;
96
+ const items = [];
97
+ for (const item of (_a = data.contents) !== null && _a !== void 0 ? _a : []) {
98
+ const parsedItemPrice = parseNumericValue(item === null || item === void 0 ? void 0 : item.item_price);
99
+ if (parsedItemPrice === undefined) {
100
+ console.error('addtocart : content item_price should be a number');
101
+ continue;
102
+ }
103
+ const parsedItemQuantity = parseNumericValue(item === null || item === void 0 ? void 0 : item.quantity);
104
+ if (parsedItemQuantity === undefined) {
105
+ console.error('addtocart : content quantity should be a number');
106
+ continue;
107
+ }
108
+ if (typeof (item === null || item === void 0 ? void 0 : item.id) !== 'string') {
109
+ console.error('addtocart : content id should be a string');
110
+ continue;
111
+ }
112
+ items.push({
113
+ value: parsedItemPrice * parsedItemQuantity,
114
+ currency,
115
+ quantity: parsedItemQuantity,
116
+ product_id: item.id,
117
+ product_name: item.title,
118
+ product_type: item.type,
119
+ product_vendor: item.brand,
120
+ variant_id: item.variantId,
121
+ variant_name: item.sku,
122
+ });
123
+ }
124
+ return {
125
+ name: 'addtocart',
126
+ data: items,
127
+ };
128
+ }
129
+ case 'ViewContent': {
130
+ if (typeof data.currency !== 'string') {
131
+ console.error('product : data.currency should be a string');
132
+ return;
133
+ }
134
+ const items = [];
135
+ for (const item of (_b = data.contents) !== null && _b !== void 0 ? _b : []) {
136
+ const parsedItemPrice = parseNumericValue(item === null || item === void 0 ? void 0 : item.item_price);
137
+ if (parsedItemPrice === undefined) {
138
+ console.error('checkout : content item_price should be a number');
139
+ continue;
140
+ }
141
+ const parsedItemQuantity = parseNumericValue(item === null || item === void 0 ? void 0 : item.quantity);
142
+ if (parsedItemQuantity === undefined) {
143
+ console.error('checkout : content quantity should be a number');
144
+ continue;
145
+ }
146
+ if (typeof (item === null || item === void 0 ? void 0 : item.id) !== 'string') {
147
+ console.error('checkout : content id should be a string');
148
+ continue;
149
+ }
150
+ items.push({
151
+ value: parsedItemPrice * parsedItemQuantity,
152
+ currency: data.currency,
153
+ product_id: item.id,
154
+ product_name: item.title,
155
+ product_type: item.sku,
156
+ product_vendor: item.brand,
157
+ });
158
+ }
159
+ return {
160
+ name: 'product',
161
+ data: items,
162
+ };
163
+ }
164
+ case 'InitiateCheckout': {
165
+ const parsedValue = parseNumericValue(data.value);
166
+ if (parsedValue === undefined) {
167
+ console.error('checkout : data.value should be a number');
168
+ return;
169
+ }
170
+ if (typeof data.currency !== 'string') {
171
+ console.error('checkout : data.currency should be a string');
172
+ return;
173
+ }
174
+ const value = parsedValue;
175
+ const currency = data.currency;
176
+ const discount_code = (_d = (_c = data.discounts) === null || _c === void 0 ? void 0 : _c.map((discount) => discount.code).join(' ,')) !== null && _d !== void 0 ? _d : '';
177
+ const items = [];
178
+ for (const item of (_e = data.contents) !== null && _e !== void 0 ? _e : []) {
179
+ const parsedItemPrice = parseNumericValue(item === null || item === void 0 ? void 0 : item.item_price);
180
+ if (parsedItemPrice === undefined) {
181
+ console.error('checkout : content item_price should be a number');
182
+ continue;
183
+ }
184
+ const parsedItemQuantity = parseNumericValue(item === null || item === void 0 ? void 0 : item.quantity);
185
+ if (parsedItemQuantity === undefined) {
186
+ console.error('checkout : content quantity should be a number');
187
+ continue;
188
+ }
189
+ if (typeof (item === null || item === void 0 ? void 0 : item.id) !== 'string') {
190
+ console.error('checkout : content id should be a string');
191
+ continue;
192
+ }
193
+ items.push({
194
+ value: parsedItemPrice,
195
+ quantity: parsedItemQuantity,
196
+ product_id: item.id,
197
+ product_name: item.title,
198
+ product_type: item.sku,
199
+ product_vendor: item.brand,
200
+ });
201
+ }
202
+ return {
203
+ name: 'checkout',
204
+ data: {
205
+ value,
206
+ currency,
207
+ discount_code,
208
+ line_items: items,
209
+ },
210
+ };
211
+ }
212
+ case 'Purchase': {
213
+ const { isNewCustomer } = options;
214
+ if (isNewCustomer === undefined) {
215
+ console.error('purchase : isNewCustomer is not defined');
216
+ return;
217
+ }
218
+ const parsedValue = parseNumericValue(data.value);
219
+ if (parsedValue === undefined) {
220
+ console.error('purchase : data.value should be a number');
221
+ return;
222
+ }
223
+ if (typeof data.currency !== 'string') {
224
+ console.error('purchase : data.currency should be a string');
225
+ return;
226
+ }
227
+ if (typeof data.orderId !== 'string') {
228
+ console.error('purchase : data.orderId should be a string');
229
+ return;
230
+ }
231
+ const value = parsedValue;
232
+ const currency = data.currency;
233
+ const order_id = data.orderId;
234
+ const discount_code = (_g = ((_f = data.discounts) !== null && _f !== void 0 ? _f : []).map((discount) => discount.code).join(' ,')) !== null && _g !== void 0 ? _g : '';
235
+ const items = [];
236
+ for (const item of (_h = data.contents) !== null && _h !== void 0 ? _h : []) {
237
+ const parsedItemPrice = parseNumericValue(item === null || item === void 0 ? void 0 : item.item_price);
238
+ if (parsedItemPrice === undefined) {
239
+ console.error('purchase : content item_price should be a number');
240
+ continue;
241
+ }
242
+ const parsedItemQuantity = parseNumericValue(item === null || item === void 0 ? void 0 : item.quantity);
243
+ if (parsedItemQuantity === undefined) {
244
+ console.error('purchase : content quantity should be a number');
245
+ continue;
246
+ }
247
+ if (typeof (item === null || item === void 0 ? void 0 : item.id) !== 'string') {
248
+ console.error('purchase : content id should be a string');
249
+ continue;
250
+ }
251
+ items.push({
252
+ value: parsedItemPrice,
253
+ quantity: parsedItemQuantity,
254
+ product_id: item.id,
255
+ product_name: item.title,
256
+ product_type: item.type,
257
+ product_vendor: item.brand,
258
+ variant_id: item.variantId,
259
+ variant_name: item.sku,
260
+ });
261
+ }
262
+ const quantity = items.reduce((sum, item) => sum + item.quantity, 0);
263
+ return {
264
+ name: 'purchase',
265
+ data: {
266
+ value,
267
+ currency,
268
+ order_id,
269
+ discount_code,
270
+ quantity,
271
+ line_items: items,
272
+ is_new_customer: isNewCustomer,
273
+ },
274
+ };
275
+ }
276
+ case 'PageView': {
277
+ return {
278
+ name: 'view',
279
+ data: {},
280
+ };
281
+ }
282
+ }
283
+ return;
284
+ };
285
+
286
+ const isNewCustomer = async (getData) => {
287
+ const edgeData = await new Promise((resolve) => getData(['is_new_customer'], resolve));
288
+ /*
289
+ if we are getting undefined value for is_new_customer
290
+ from the custom table, we should send is_new_customer as true
291
+ to spotify.
292
+ */
293
+ return (edgeData['is_new_customer'] === undefined ||
294
+ edgeData['is_new_customer'] === 'true');
295
+ };
296
+
297
+ const handleTag = async ({ data, eventName, getEdgeData, }) => {
298
+ var _a, _b, _c;
299
+ if (!eventName || !data || !getEdgeData) {
300
+ return;
301
+ }
302
+ let options = {};
303
+ if (eventName === 'Purchase') {
304
+ const is_new_customer = await isNewCustomer(getEdgeData);
305
+ options = { isNewCustomer: is_new_customer };
306
+ }
307
+ const event = getEventData(eventName, data, options);
308
+ if (event) {
309
+ const { name, data } = event;
310
+ if (data && Array.isArray(data)) {
311
+ if (data.length === 0) {
312
+ (_a = window.spdt) === null || _a === void 0 ? void 0 : _a.call(window, name, []);
313
+ }
314
+ else {
315
+ for (const item of data) {
316
+ (_b = window.spdt) === null || _b === void 0 ? void 0 : _b.call(window, name, item);
317
+ }
318
+ }
319
+ }
320
+ else {
321
+ (_c = window.spdt) === null || _c === void 0 ? void 0 : _c.call(window, name, data);
322
+ }
323
+ }
324
+ };
325
+
326
+ const tag = ({ data, eventName, getEdgeData }) => {
327
+ const payload = {
328
+ sdkVersion: "1.17.0" ,
329
+ };
330
+ if (typeof window !== 'undefined' && typeof window.spdt === 'function') {
331
+ handleTag({ data, eventName, getEdgeData });
332
+ }
333
+ return payload;
334
+ };
335
+
336
+ // eslint-disable-next-line @nx/enforce-module-boundaries
337
+ const data = {
338
+ name: packageName,
339
+ init,
340
+ user,
341
+ tag,
342
+ };
343
+ try {
344
+ if (window) {
345
+ if (!window.edgetagProviders) {
346
+ window.edgetagProviders = [];
347
+ }
348
+ window.edgetagProviders.push(data);
349
+ }
350
+ }
351
+ catch {
352
+ // No window
353
+ }
354
+
355
+ export { data as default };
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@blotoutio/providers-spotify-sdk",
3
+ "version": "1.17.0",
4
+ "description": "Spotify Browser SDK for EdgeTag",
5
+ "author": "Blotout",
6
+ "license": "MIT",
7
+ "homepage": "https://github.com/blotoutio/edgetag-sdk",
8
+ "publishConfig": {
9
+ "access": "public"
10
+ },
11
+ "main": "./index.cjs.js",
12
+ "module": "./index.mjs",
13
+ "types": "./index.d.ts",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/blotoutio/edgetag-sdk.git"
17
+ },
18
+ "files": [
19
+ "index.js",
20
+ "index.d.ts",
21
+ "index.cjs.js",
22
+ "index.mjs",
23
+ "package.json",
24
+ "README.md"
25
+ ]
26
+ }