@blotoutio/providers-dataflywheel-sdk 1.68.2 → 1.69.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.
Files changed (4) hide show
  1. package/index.cjs.js +172 -2
  2. package/index.js +172 -2
  3. package/index.mjs +172 -2
  4. package/package.json +1 -1
package/index.cjs.js CHANGED
@@ -1,9 +1,139 @@
1
1
  'use strict';
2
2
 
3
3
  const packageName = 'dataFlywheel';
4
+ // Browser identifiers the edge persists against the EdgeTag user id, the way
5
+ // Facebook stores _fbp/_fbc. The identify request carries no providerData and
6
+ // dfw_nid is third-party to the merchant, so this is n_id's only route there.
7
+ const storedNIdKey = 'n_id';
8
+ const storedSessionIdKey = 'session_id';
9
+ const storedSessionExpiryKey = 'session_expires_at';
10
+ // The same identifiers published into the EdgeTag SDK's kv store, which rides
11
+ // on every request including identify. Namespaced the way the edge splits them
12
+ // back apart, as Facebook does with facebook::_fbp.
13
+ const kvKey = (key) => `${packageName}::${key}`;
4
14
  const sessionStateKeyPrefix = 'dfw_sdk_state';
5
15
  const sessionBootstrapPath = 'v1/session';
6
16
 
17
+ const keyPrefix = `_worker`;
18
+
19
+ const canLog = () => {
20
+ try {
21
+ return localStorage.getItem('edgeTagDebug') === '1';
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ };
27
+ const prefix = `[EdgeTag]`;
28
+ const logger = {
29
+ log: (...args) => {
30
+ if (canLog()) {
31
+ console.log(prefix, ...args);
32
+ }
33
+ },
34
+ error: (...args) => {
35
+ if (canLog()) {
36
+ console.error(prefix, ...args);
37
+ }
38
+ },
39
+ info: (...args) => {
40
+ if (canLog()) {
41
+ console.info(prefix, ...args);
42
+ }
43
+ },
44
+ trace: (...args) => {
45
+ if (canLog()) {
46
+ console.trace(prefix, ...args);
47
+ }
48
+ },
49
+ };
50
+
51
+ const initKey = `${keyPrefix}StoreMultiple`;
52
+ const saveKV = (destination, data) => {
53
+ const currentSession = getData(destination, 'session');
54
+ if (!currentSession['kv']) {
55
+ currentSession['kv'] = {};
56
+ }
57
+ currentSession['kv'] = {
58
+ ...currentSession['kv'],
59
+ ...data,
60
+ };
61
+ saveData(destination, 'session', currentSession);
62
+ };
63
+ const saveData = (destination, persistType, value, key = initKey) => {
64
+ if (persistType === 'session') {
65
+ const data = getSession(key);
66
+ data[destination] = value;
67
+ saveSession(data, key);
68
+ return;
69
+ }
70
+ const data = getLocal(key);
71
+ data[destination] = value;
72
+ saveLocal(data, key);
73
+ };
74
+ const getData = (destination, persistType, key = initKey) => {
75
+ let data;
76
+ if (persistType === 'session') {
77
+ data = getSession(key);
78
+ }
79
+ else {
80
+ data = getLocal(key);
81
+ }
82
+ return (data === null || data === void 0 ? void 0 : data[destination]) || {};
83
+ };
84
+ const saveLocal = (value, key) => {
85
+ try {
86
+ if (!localStorage) {
87
+ return;
88
+ }
89
+ localStorage.setItem(key, JSON.stringify(value));
90
+ }
91
+ catch {
92
+ logger.log('Local storage not supported.');
93
+ }
94
+ };
95
+ const getLocal = (key) => {
96
+ try {
97
+ if (!localStorage) {
98
+ return {};
99
+ }
100
+ const data = localStorage.getItem(key);
101
+ if (!data) {
102
+ return {};
103
+ }
104
+ return JSON.parse(data) || {};
105
+ }
106
+ catch {
107
+ return {};
108
+ }
109
+ };
110
+ const saveSession = (value, key) => {
111
+ try {
112
+ if (!sessionStorage) {
113
+ return;
114
+ }
115
+ sessionStorage.setItem(key, JSON.stringify(value));
116
+ }
117
+ catch {
118
+ logger.log('Session storage not supported.');
119
+ }
120
+ };
121
+ const getSession = (key) => {
122
+ try {
123
+ if (!sessionStorage) {
124
+ return {};
125
+ }
126
+ const data = sessionStorage.getItem(key);
127
+ if (!data) {
128
+ return {};
129
+ }
130
+ return JSON.parse(data) || {};
131
+ }
132
+ catch {
133
+ return {};
134
+ }
135
+ };
136
+
7
137
  // eslint-disable-next-line @nx/enforce-module-boundaries
8
138
  // Coalesces concurrent cold bootstraps per merchant: events firing in the same
9
139
  // tick share one in-flight /v1/session call instead of racing N handshakes.
@@ -92,6 +222,38 @@ function expiresAtMs(state) {
92
222
  const expiresAt = Date.parse(state.expires_at);
93
223
  return Number.isFinite(expiresAt) ? expiresAt : null;
94
224
  }
225
+ // The dfw_nid cookie belongs to the DataFlywheel identity host, so the merchant's
226
+ // edge never receives it. Publishing into the SDK's kv store puts the same values
227
+ // on every request body instead -- identify included, which providerData is not.
228
+ const published = new Map();
229
+ function publishToKv(destination, state) {
230
+ if (!destination || !state)
231
+ return;
232
+ // saveKV rewrites the whole multi-destination blob synchronously, and the
233
+ // cached path runs on every event, so skip when nothing moved.
234
+ const last = published.get(destination);
235
+ if (last &&
236
+ last.n_id === state.n_id &&
237
+ last.session_id === state.session_id &&
238
+ last.expires_at === state.expires_at) {
239
+ return;
240
+ }
241
+ published.set(destination, {
242
+ n_id: state.n_id,
243
+ session_id: state.session_id,
244
+ expires_at: state.expires_at,
245
+ });
246
+ try {
247
+ saveKV(destination, {
248
+ [kvKey(storedNIdKey)]: state.n_id,
249
+ [kvKey(storedSessionIdKey)]: state.session_id,
250
+ [kvKey(storedSessionExpiryKey)]: state.expires_at,
251
+ });
252
+ }
253
+ catch {
254
+ // Storage can be unavailable; the providerData and provider-key routes remain.
255
+ }
256
+ }
95
257
  function bootstrapUrl(input) {
96
258
  const base = input.dataFlywheelUrl.endsWith('/')
97
259
  ? input.dataFlywheelUrl
@@ -151,6 +313,7 @@ function ensureSession(input) {
151
313
  const now = (_c = (_b = input.now) === null || _b === void 0 ? void 0 : _b.call(input)) !== null && _c !== void 0 ? _c : Date.now();
152
314
  const existing = readSessionState(storage, merchantId);
153
315
  if (!shouldBootstrap(now, expiresAtMs(existing))) {
316
+ publishToKv(input.destination, existing);
154
317
  return Promise.resolve(existing);
155
318
  }
156
319
  // Opaque origins (sandboxed iframes like Shopify pixels) serialize to the
@@ -174,7 +337,12 @@ function ensureSession(input) {
174
337
  storage,
175
338
  fetcher,
176
339
  now,
177
- }).finally(() => {
340
+ })
341
+ .then((state) => {
342
+ publishToKv(input.destination, state);
343
+ return state;
344
+ })
345
+ .finally(() => {
178
346
  inFlight.delete(key);
179
347
  });
180
348
  inFlight.set(key, bootstrap);
@@ -194,13 +362,15 @@ const init = (params) => {
194
362
  void ensureSession({
195
363
  variables: params.manifest.variables,
196
364
  pageUrl: params.pageUrl,
365
+ destination: params.destination,
197
366
  });
198
367
  };
199
368
 
200
- const tag = async ({ manifestVariables, pageUrl, }) => {
369
+ const tag = async ({ manifestVariables, pageUrl, destination, }) => {
201
370
  const state = await ensureSession({
202
371
  variables: manifestVariables,
203
372
  pageUrl,
373
+ destination,
204
374
  });
205
375
  return toProviderData(state);
206
376
  };
package/index.js CHANGED
@@ -2,9 +2,139 @@ var ProvidersDataflywheelSdk = (function () {
2
2
  'use strict';
3
3
 
4
4
  const packageName = 'dataFlywheel';
5
+ // Browser identifiers the edge persists against the EdgeTag user id, the way
6
+ // Facebook stores _fbp/_fbc. The identify request carries no providerData and
7
+ // dfw_nid is third-party to the merchant, so this is n_id's only route there.
8
+ const storedNIdKey = 'n_id';
9
+ const storedSessionIdKey = 'session_id';
10
+ const storedSessionExpiryKey = 'session_expires_at';
11
+ // The same identifiers published into the EdgeTag SDK's kv store, which rides
12
+ // on every request including identify. Namespaced the way the edge splits them
13
+ // back apart, as Facebook does with facebook::_fbp.
14
+ const kvKey = (key) => `${packageName}::${key}`;
5
15
  const sessionStateKeyPrefix = 'dfw_sdk_state';
6
16
  const sessionBootstrapPath = 'v1/session';
7
17
 
18
+ const keyPrefix = `_worker`;
19
+
20
+ const canLog = () => {
21
+ try {
22
+ return localStorage.getItem('edgeTagDebug') === '1';
23
+ }
24
+ catch {
25
+ return false;
26
+ }
27
+ };
28
+ const prefix = `[EdgeTag]`;
29
+ const logger = {
30
+ log: (...args) => {
31
+ if (canLog()) {
32
+ console.log(prefix, ...args);
33
+ }
34
+ },
35
+ error: (...args) => {
36
+ if (canLog()) {
37
+ console.error(prefix, ...args);
38
+ }
39
+ },
40
+ info: (...args) => {
41
+ if (canLog()) {
42
+ console.info(prefix, ...args);
43
+ }
44
+ },
45
+ trace: (...args) => {
46
+ if (canLog()) {
47
+ console.trace(prefix, ...args);
48
+ }
49
+ },
50
+ };
51
+
52
+ const initKey = `${keyPrefix}StoreMultiple`;
53
+ const saveKV = (destination, data) => {
54
+ const currentSession = getData(destination, 'session');
55
+ if (!currentSession['kv']) {
56
+ currentSession['kv'] = {};
57
+ }
58
+ currentSession['kv'] = {
59
+ ...currentSession['kv'],
60
+ ...data,
61
+ };
62
+ saveData(destination, 'session', currentSession);
63
+ };
64
+ const saveData = (destination, persistType, value, key = initKey) => {
65
+ if (persistType === 'session') {
66
+ const data = getSession(key);
67
+ data[destination] = value;
68
+ saveSession(data, key);
69
+ return;
70
+ }
71
+ const data = getLocal(key);
72
+ data[destination] = value;
73
+ saveLocal(data, key);
74
+ };
75
+ const getData = (destination, persistType, key = initKey) => {
76
+ let data;
77
+ if (persistType === 'session') {
78
+ data = getSession(key);
79
+ }
80
+ else {
81
+ data = getLocal(key);
82
+ }
83
+ return (data === null || data === void 0 ? void 0 : data[destination]) || {};
84
+ };
85
+ const saveLocal = (value, key) => {
86
+ try {
87
+ if (!localStorage) {
88
+ return;
89
+ }
90
+ localStorage.setItem(key, JSON.stringify(value));
91
+ }
92
+ catch {
93
+ logger.log('Local storage not supported.');
94
+ }
95
+ };
96
+ const getLocal = (key) => {
97
+ try {
98
+ if (!localStorage) {
99
+ return {};
100
+ }
101
+ const data = localStorage.getItem(key);
102
+ if (!data) {
103
+ return {};
104
+ }
105
+ return JSON.parse(data) || {};
106
+ }
107
+ catch {
108
+ return {};
109
+ }
110
+ };
111
+ const saveSession = (value, key) => {
112
+ try {
113
+ if (!sessionStorage) {
114
+ return;
115
+ }
116
+ sessionStorage.setItem(key, JSON.stringify(value));
117
+ }
118
+ catch {
119
+ logger.log('Session storage not supported.');
120
+ }
121
+ };
122
+ const getSession = (key) => {
123
+ try {
124
+ if (!sessionStorage) {
125
+ return {};
126
+ }
127
+ const data = sessionStorage.getItem(key);
128
+ if (!data) {
129
+ return {};
130
+ }
131
+ return JSON.parse(data) || {};
132
+ }
133
+ catch {
134
+ return {};
135
+ }
136
+ };
137
+
8
138
  // eslint-disable-next-line @nx/enforce-module-boundaries
9
139
  // Coalesces concurrent cold bootstraps per merchant: events firing in the same
10
140
  // tick share one in-flight /v1/session call instead of racing N handshakes.
@@ -93,6 +223,38 @@ var ProvidersDataflywheelSdk = (function () {
93
223
  const expiresAt = Date.parse(state.expires_at);
94
224
  return Number.isFinite(expiresAt) ? expiresAt : null;
95
225
  }
226
+ // The dfw_nid cookie belongs to the DataFlywheel identity host, so the merchant's
227
+ // edge never receives it. Publishing into the SDK's kv store puts the same values
228
+ // on every request body instead -- identify included, which providerData is not.
229
+ const published = new Map();
230
+ function publishToKv(destination, state) {
231
+ if (!destination || !state)
232
+ return;
233
+ // saveKV rewrites the whole multi-destination blob synchronously, and the
234
+ // cached path runs on every event, so skip when nothing moved.
235
+ const last = published.get(destination);
236
+ if (last &&
237
+ last.n_id === state.n_id &&
238
+ last.session_id === state.session_id &&
239
+ last.expires_at === state.expires_at) {
240
+ return;
241
+ }
242
+ published.set(destination, {
243
+ n_id: state.n_id,
244
+ session_id: state.session_id,
245
+ expires_at: state.expires_at,
246
+ });
247
+ try {
248
+ saveKV(destination, {
249
+ [kvKey(storedNIdKey)]: state.n_id,
250
+ [kvKey(storedSessionIdKey)]: state.session_id,
251
+ [kvKey(storedSessionExpiryKey)]: state.expires_at,
252
+ });
253
+ }
254
+ catch {
255
+ // Storage can be unavailable; the providerData and provider-key routes remain.
256
+ }
257
+ }
96
258
  function bootstrapUrl(input) {
97
259
  const base = input.dataFlywheelUrl.endsWith('/')
98
260
  ? input.dataFlywheelUrl
@@ -152,6 +314,7 @@ var ProvidersDataflywheelSdk = (function () {
152
314
  const now = (_c = (_b = input.now) === null || _b === void 0 ? void 0 : _b.call(input)) !== null && _c !== void 0 ? _c : Date.now();
153
315
  const existing = readSessionState(storage, merchantId);
154
316
  if (!shouldBootstrap(now, expiresAtMs(existing))) {
317
+ publishToKv(input.destination, existing);
155
318
  return Promise.resolve(existing);
156
319
  }
157
320
  // Opaque origins (sandboxed iframes like Shopify pixels) serialize to the
@@ -175,7 +338,12 @@ var ProvidersDataflywheelSdk = (function () {
175
338
  storage,
176
339
  fetcher,
177
340
  now,
178
- }).finally(() => {
341
+ })
342
+ .then((state) => {
343
+ publishToKv(input.destination, state);
344
+ return state;
345
+ })
346
+ .finally(() => {
179
347
  inFlight.delete(key);
180
348
  });
181
349
  inFlight.set(key, bootstrap);
@@ -195,13 +363,15 @@ var ProvidersDataflywheelSdk = (function () {
195
363
  void ensureSession({
196
364
  variables: params.manifest.variables,
197
365
  pageUrl: params.pageUrl,
366
+ destination: params.destination,
198
367
  });
199
368
  };
200
369
 
201
- const tag = async ({ manifestVariables, pageUrl, }) => {
370
+ const tag = async ({ manifestVariables, pageUrl, destination, }) => {
202
371
  const state = await ensureSession({
203
372
  variables: manifestVariables,
204
373
  pageUrl,
374
+ destination,
205
375
  });
206
376
  return toProviderData(state);
207
377
  };
package/index.mjs CHANGED
@@ -1,7 +1,137 @@
1
1
  const packageName = 'dataFlywheel';
2
+ // Browser identifiers the edge persists against the EdgeTag user id, the way
3
+ // Facebook stores _fbp/_fbc. The identify request carries no providerData and
4
+ // dfw_nid is third-party to the merchant, so this is n_id's only route there.
5
+ const storedNIdKey = 'n_id';
6
+ const storedSessionIdKey = 'session_id';
7
+ const storedSessionExpiryKey = 'session_expires_at';
8
+ // The same identifiers published into the EdgeTag SDK's kv store, which rides
9
+ // on every request including identify. Namespaced the way the edge splits them
10
+ // back apart, as Facebook does with facebook::_fbp.
11
+ const kvKey = (key) => `${packageName}::${key}`;
2
12
  const sessionStateKeyPrefix = 'dfw_sdk_state';
3
13
  const sessionBootstrapPath = 'v1/session';
4
14
 
15
+ const keyPrefix = `_worker`;
16
+
17
+ const canLog = () => {
18
+ try {
19
+ return localStorage.getItem('edgeTagDebug') === '1';
20
+ }
21
+ catch {
22
+ return false;
23
+ }
24
+ };
25
+ const prefix = `[EdgeTag]`;
26
+ const logger = {
27
+ log: (...args) => {
28
+ if (canLog()) {
29
+ console.log(prefix, ...args);
30
+ }
31
+ },
32
+ error: (...args) => {
33
+ if (canLog()) {
34
+ console.error(prefix, ...args);
35
+ }
36
+ },
37
+ info: (...args) => {
38
+ if (canLog()) {
39
+ console.info(prefix, ...args);
40
+ }
41
+ },
42
+ trace: (...args) => {
43
+ if (canLog()) {
44
+ console.trace(prefix, ...args);
45
+ }
46
+ },
47
+ };
48
+
49
+ const initKey = `${keyPrefix}StoreMultiple`;
50
+ const saveKV = (destination, data) => {
51
+ const currentSession = getData(destination, 'session');
52
+ if (!currentSession['kv']) {
53
+ currentSession['kv'] = {};
54
+ }
55
+ currentSession['kv'] = {
56
+ ...currentSession['kv'],
57
+ ...data,
58
+ };
59
+ saveData(destination, 'session', currentSession);
60
+ };
61
+ const saveData = (destination, persistType, value, key = initKey) => {
62
+ if (persistType === 'session') {
63
+ const data = getSession(key);
64
+ data[destination] = value;
65
+ saveSession(data, key);
66
+ return;
67
+ }
68
+ const data = getLocal(key);
69
+ data[destination] = value;
70
+ saveLocal(data, key);
71
+ };
72
+ const getData = (destination, persistType, key = initKey) => {
73
+ let data;
74
+ if (persistType === 'session') {
75
+ data = getSession(key);
76
+ }
77
+ else {
78
+ data = getLocal(key);
79
+ }
80
+ return (data === null || data === void 0 ? void 0 : data[destination]) || {};
81
+ };
82
+ const saveLocal = (value, key) => {
83
+ try {
84
+ if (!localStorage) {
85
+ return;
86
+ }
87
+ localStorage.setItem(key, JSON.stringify(value));
88
+ }
89
+ catch {
90
+ logger.log('Local storage not supported.');
91
+ }
92
+ };
93
+ const getLocal = (key) => {
94
+ try {
95
+ if (!localStorage) {
96
+ return {};
97
+ }
98
+ const data = localStorage.getItem(key);
99
+ if (!data) {
100
+ return {};
101
+ }
102
+ return JSON.parse(data) || {};
103
+ }
104
+ catch {
105
+ return {};
106
+ }
107
+ };
108
+ const saveSession = (value, key) => {
109
+ try {
110
+ if (!sessionStorage) {
111
+ return;
112
+ }
113
+ sessionStorage.setItem(key, JSON.stringify(value));
114
+ }
115
+ catch {
116
+ logger.log('Session storage not supported.');
117
+ }
118
+ };
119
+ const getSession = (key) => {
120
+ try {
121
+ if (!sessionStorage) {
122
+ return {};
123
+ }
124
+ const data = sessionStorage.getItem(key);
125
+ if (!data) {
126
+ return {};
127
+ }
128
+ return JSON.parse(data) || {};
129
+ }
130
+ catch {
131
+ return {};
132
+ }
133
+ };
134
+
5
135
  // eslint-disable-next-line @nx/enforce-module-boundaries
6
136
  // Coalesces concurrent cold bootstraps per merchant: events firing in the same
7
137
  // tick share one in-flight /v1/session call instead of racing N handshakes.
@@ -90,6 +220,38 @@ function expiresAtMs(state) {
90
220
  const expiresAt = Date.parse(state.expires_at);
91
221
  return Number.isFinite(expiresAt) ? expiresAt : null;
92
222
  }
223
+ // The dfw_nid cookie belongs to the DataFlywheel identity host, so the merchant's
224
+ // edge never receives it. Publishing into the SDK's kv store puts the same values
225
+ // on every request body instead -- identify included, which providerData is not.
226
+ const published = new Map();
227
+ function publishToKv(destination, state) {
228
+ if (!destination || !state)
229
+ return;
230
+ // saveKV rewrites the whole multi-destination blob synchronously, and the
231
+ // cached path runs on every event, so skip when nothing moved.
232
+ const last = published.get(destination);
233
+ if (last &&
234
+ last.n_id === state.n_id &&
235
+ last.session_id === state.session_id &&
236
+ last.expires_at === state.expires_at) {
237
+ return;
238
+ }
239
+ published.set(destination, {
240
+ n_id: state.n_id,
241
+ session_id: state.session_id,
242
+ expires_at: state.expires_at,
243
+ });
244
+ try {
245
+ saveKV(destination, {
246
+ [kvKey(storedNIdKey)]: state.n_id,
247
+ [kvKey(storedSessionIdKey)]: state.session_id,
248
+ [kvKey(storedSessionExpiryKey)]: state.expires_at,
249
+ });
250
+ }
251
+ catch {
252
+ // Storage can be unavailable; the providerData and provider-key routes remain.
253
+ }
254
+ }
93
255
  function bootstrapUrl(input) {
94
256
  const base = input.dataFlywheelUrl.endsWith('/')
95
257
  ? input.dataFlywheelUrl
@@ -149,6 +311,7 @@ function ensureSession(input) {
149
311
  const now = (_c = (_b = input.now) === null || _b === void 0 ? void 0 : _b.call(input)) !== null && _c !== void 0 ? _c : Date.now();
150
312
  const existing = readSessionState(storage, merchantId);
151
313
  if (!shouldBootstrap(now, expiresAtMs(existing))) {
314
+ publishToKv(input.destination, existing);
152
315
  return Promise.resolve(existing);
153
316
  }
154
317
  // Opaque origins (sandboxed iframes like Shopify pixels) serialize to the
@@ -172,7 +335,12 @@ function ensureSession(input) {
172
335
  storage,
173
336
  fetcher,
174
337
  now,
175
- }).finally(() => {
338
+ })
339
+ .then((state) => {
340
+ publishToKv(input.destination, state);
341
+ return state;
342
+ })
343
+ .finally(() => {
176
344
  inFlight.delete(key);
177
345
  });
178
346
  inFlight.set(key, bootstrap);
@@ -192,13 +360,15 @@ const init = (params) => {
192
360
  void ensureSession({
193
361
  variables: params.manifest.variables,
194
362
  pageUrl: params.pageUrl,
363
+ destination: params.destination,
195
364
  });
196
365
  };
197
366
 
198
- const tag = async ({ manifestVariables, pageUrl, }) => {
367
+ const tag = async ({ manifestVariables, pageUrl, destination, }) => {
199
368
  const state = await ensureSession({
200
369
  variables: manifestVariables,
201
370
  pageUrl,
371
+ destination,
202
372
  });
203
373
  return toProviderData(state);
204
374
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blotoutio/providers-dataflywheel-sdk",
3
- "version": "1.68.2",
3
+ "version": "1.69.1",
4
4
  "description": "DataFlywheel browser SDK for EdgeTag",
5
5
  "author": "Blotout",
6
6
  "license": "MIT",