@jitsu/js 1.0.0-canary-20230211030946 → 1.0.0-canary-20230219230011

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/dist/jitsu.es.js CHANGED
@@ -65,7 +65,151 @@ function analyticsLib() {
65
65
  return ke(_objectSpread2(_objectSpread2({}, defaultSettings), opts));
66
66
  }
67
67
 
68
+ var __awaiter$1 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
69
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
70
+ return new (P || (P = Promise))(function (resolve, reject) {
71
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
72
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
73
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
74
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
75
+ });
76
+ };
77
+ function satisfyFilter(filter, subject) {
78
+ return filter === "*" || filter.toLowerCase().trim() === (subject || "").trim().toLowerCase();
79
+ }
80
+ function applyFilters(event, creds) {
81
+ const { hosts = ["*"], events = ["*"] } = creds;
82
+ return (!!hosts.find(hostFilter => { var _a; return satisfyFilter(hostFilter, (_a = event.context) === null || _a === void 0 ? void 0 : _a.host); }) &&
83
+ !!events.find(eventFilter => satisfyFilter(eventFilter, event.type)));
84
+ }
85
+ const tagPlugin = {
86
+ id: "tag",
87
+ handle(config, payload) {
88
+ return __awaiter$1(this, void 0, void 0, function* () {
89
+ if (!applyFilters(payload, config)) {
90
+ return;
91
+ }
92
+ insertTags(config.code, payload);
93
+ });
94
+ },
95
+ };
96
+ function insertTags(code, event, opts = {}) {
97
+ let tag;
98
+ try {
99
+ tag = JSON.parse(code);
100
+ }
101
+ catch (e) {
102
+ tag = { code, lang: "javascript" };
103
+ }
104
+ const debug = opts.debug || false;
105
+ if (isInBrowser()) {
106
+ if (tag.lang === "javascript") {
107
+ execJs(tag.code, event);
108
+ }
109
+ else {
110
+ const codeHolder = document.createElement("span");
111
+ codeHolder.innerHTML = replaceMacro(tag.code, event);
112
+ document.body.insertAdjacentElement("beforeend", codeHolder);
113
+ const scripts = codeHolder.querySelectorAll("script");
114
+ scripts.forEach(script => {
115
+ const scriptClone = document.createElement("script");
116
+ scriptClone.type = scriptClone.type || "text/javascript";
117
+ if (script.hasAttribute("src")) {
118
+ scriptClone.src = script.src;
119
+ }
120
+ scriptClone.text = script.text;
121
+ if (debug) {
122
+ console.log(`[JITSU] Executing script${script.hasAttribute("src") ? ` ${script.src}` : ""}`, scriptClone.text);
123
+ }
124
+ document.head.appendChild(scriptClone);
125
+ document.head.removeChild(scriptClone);
126
+ });
127
+ }
128
+ }
129
+ else {
130
+ if (debug) {
131
+ console.log(`[JITSU] insertTags(): cannot insert tags in non-browser environment`);
132
+ }
133
+ }
134
+ }
135
+ function execJs(code, event) {
136
+ const varName = `jitsu_event_${randomId()}`;
137
+ window[varName] = event;
138
+ const iif = `(function(){
139
+ const event = ${varName};
140
+ ${code}
141
+ })()`;
142
+ try {
143
+ eval(iif);
144
+ }
145
+ catch (e) {
146
+ console.error(`[JITSU] Error executing JS code: ${e.message}. Code: `, iif);
147
+ }
148
+ finally {
149
+ delete window[varName];
150
+ }
151
+ return iif;
152
+ }
153
+ function replaceMacro(code, event) {
154
+ return code.replace(/{{\s*event\s*}}/g, JSON.stringify(event));
155
+ }
156
+ const internalDestinationPlugins = {
157
+ [tagPlugin.id]: tagPlugin,
158
+ };
159
+
160
+ function findScript(src) {
161
+ const scripts = Array.prototype.slice.call(window.document.querySelectorAll("script"));
162
+ return scripts.find(s => s.src === src);
163
+ }
164
+ function loadScript(src, attributes) {
165
+ const found = findScript(src);
166
+ if (found !== undefined) {
167
+ const status = found === null || found === void 0 ? void 0 : found.getAttribute("status");
168
+ if (status === "loaded") {
169
+ return Promise.resolve(found);
170
+ }
171
+ if (status === "loading") {
172
+ return new Promise((resolve, reject) => {
173
+ found.addEventListener("load", () => resolve(found));
174
+ found.addEventListener("error", err => reject(err));
175
+ });
176
+ }
177
+ }
178
+ return new Promise((resolve, reject) => {
179
+ var _a;
180
+ const script = window.document.createElement("script");
181
+ script.type = "text/javascript";
182
+ script.src = src;
183
+ script.async = true;
184
+ script.setAttribute("status", "loading");
185
+ for (const [k, v] of Object.entries(attributes !== null && attributes !== void 0 ? attributes : {})) {
186
+ script.setAttribute(k, v);
187
+ }
188
+ script.onload = () => {
189
+ script.onerror = script.onload = null;
190
+ script.setAttribute("status", "loaded");
191
+ resolve(script);
192
+ };
193
+ script.onerror = () => {
194
+ script.onerror = script.onload = null;
195
+ script.setAttribute("status", "error");
196
+ reject(new Error(`Failed to load ${src}`));
197
+ };
198
+ const tag = window.document.getElementsByTagName("script")[0];
199
+ (_a = tag.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(script, tag);
200
+ });
201
+ }
202
+
68
203
  /* global analytics */
204
+ var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
205
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
206
+ return new (P || (P = Promise))(function (resolve, reject) {
207
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
208
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
209
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
210
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
211
+ });
212
+ };
69
213
  const config = {
70
214
  /* Your segment writeKey */
71
215
  writeKey: null,
@@ -277,7 +421,7 @@ function deepMerge(target, source) {
277
421
  }, target);
278
422
  }
279
423
  function isInBrowser() {
280
- return typeof document !== "undefined";
424
+ return typeof document !== "undefined" && typeof window !== "undefined";
281
425
  }
282
426
  function adjustPayload(payload, config, storage) {
283
427
  var _a, _b;
@@ -315,62 +459,62 @@ function adjustPayload(payload, config, storage) {
315
459
  delete withContext.options;
316
460
  return withContext;
317
461
  }
318
- function execJs(code, event) {
319
- const varName = `jitsu_event_${randomId()}`;
320
- window[varName] = event;
321
- const iif = `(function(){
322
- ${code}
323
- onEvent(${varName});
324
- })()`;
325
- try {
326
- eval(iif);
327
- }
328
- catch (e) {
329
- console.error(`[JITSU] Error executing JS code: ${e.message}`);
330
- }
331
- finally {
332
- delete window[varName];
333
- }
334
- return iif;
335
- }
336
- function replaceMacro(code, event) {
337
- return code.replace(/{{\s*event\s*}}/g, JSON.stringify(event));
338
- }
339
- function insertTags(tags, event, opts = {}) {
340
- const debug = opts.debug || false;
341
- if (isInBrowser()) {
342
- Object.values(tags).forEach(tag => {
343
- if (tag.mode === "javascript") {
344
- execJs(tag.code, event);
462
+ function processDestinations(destinations, method, event, debug, analyticsInstance) {
463
+ return __awaiter(this, void 0, void 0, function* () {
464
+ const promises = [];
465
+ for (const destination of destinations) {
466
+ if (destination.deviceOptions.type === "internal-plugin") {
467
+ const plugin = internalDestinationPlugins[destination.deviceOptions.name];
468
+ if (plugin) {
469
+ try {
470
+ promises.push(plugin.handle(destination.credentials, event));
471
+ }
472
+ catch (e) {
473
+ console.warn(`[JITSU] Error processing event with internal plugin '${destination.deviceOptions.name}': ${e === null || e === void 0 ? void 0 : e.message}`, e);
474
+ }
475
+ }
476
+ else {
477
+ console.warn(`[JITSU] Unknown internal plugin '${destination.deviceOptions.name}' for destination '${destination.id}'`);
478
+ }
345
479
  }
346
- else {
347
- const codeHolder = document.createElement("span");
348
- codeHolder.innerHTML = replaceMacro(tag.code, event);
349
- document.body.insertAdjacentElement("beforeend", codeHolder);
350
- const scripts = codeHolder.querySelectorAll("script");
351
- scripts.forEach(script => {
352
- const scriptClone = document.createElement("script");
353
- scriptClone.type = scriptClone.type || "text/javascript";
354
- if (script.hasAttribute("src")) {
355
- scriptClone.src = script.src;
480
+ else if (destination.deviceOptions.type === "analytics-plugin") {
481
+ yield loadScript(destination.deviceOptions.packageCdn);
482
+ const plugin = window[destination.deviceOptions.moduleVarName];
483
+ if (!plugin) {
484
+ console.warn(`[JITSU] Broken plugin '${destination.deviceOptions.packageCdn}' for destination '${destination.id}' - it doesn't export '${destination.deviceOptions.moduleVarName}' variable`);
485
+ }
486
+ else {
487
+ let pluginInstance;
488
+ try {
489
+ pluginInstance = (typeof plugin === "function" ? plugin : plugin.init)(destination.credentials);
490
+ }
491
+ catch (e) {
492
+ console.warn(`[JITSU] Error creating plugin '${destination.deviceOptions.moduleVarName}@${destination.deviceOptions.packageCdn}' for destination '${destination.id}': ${e === null || e === void 0 ? void 0 : e.message}`, e);
493
+ }
494
+ try {
495
+ if (debug) {
496
+ console.log(`[JITSU] Plugin '${destination.deviceOptions.moduleVarName}@${destination.deviceOptions.packageCdn}' for destination '${destination.id}' initialized with config:`, pluginInstance.config);
497
+ }
498
+ pluginInstance.initialize({ config: pluginInstance.config, instance: analyticsInstance });
356
499
  }
357
- scriptClone.text = script.text;
358
- if (debug) {
359
- console.log(`Executing script${script.hasAttribute("src") ? ` ${script.src}` : ""}`, scriptClone.text);
500
+ catch (e) {
501
+ console.warn(`[JITSU] Error initializing plugin '${destination.deviceOptions.moduleVarName}@${destination.deviceOptions.packageCdn}' for destination '${destination.id}': ${e === null || e === void 0 ? void 0 : e.message}. Config: ${JSON.stringify(pluginInstance.config)}`, e);
502
+ continue;
360
503
  }
361
- document.head.appendChild(scriptClone);
362
- document.head.removeChild(scriptClone);
363
- });
504
+ if (pluginInstance[method]) {
505
+ try {
506
+ pluginInstance[method]({ payload: event, config: pluginInstance.config, instance: analyticsInstance });
507
+ }
508
+ catch (e) {
509
+ console.warn(`[JITSU] Error processing ${method}() with plugin '${destination.deviceOptions.moduleVarName}@${destination.deviceOptions.packageCdn}' for destination '${destination.id}': ${e === null || e === void 0 ? void 0 : e.message}`, e);
510
+ }
511
+ }
512
+ }
364
513
  }
365
- });
366
- }
367
- else {
368
- if (debug) {
369
- console.log(`insertTags: cannot insert tags in non-browser environment`);
370
514
  }
371
- }
515
+ });
372
516
  }
373
- function send(method, payload, jitsuConfig, store) {
517
+ function send(method, payload, jitsuConfig, instance, store) {
374
518
  if (jitsuConfig.echoEvents) {
375
519
  console.log(`[JITSU] sending '${method}' event:`, payload);
376
520
  return;
@@ -403,18 +547,19 @@ function send(method, payload, jitsuConfig, store) {
403
547
  }
404
548
  })
405
549
  .then(responseText => {
550
+ let response;
406
551
  try {
407
- const response = JSON.parse(responseText);
408
- if (response.tags) {
409
- if (jitsuConfig.debug) {
410
- console.log(`[JITSU] Response Tags: `, JSON.stringify(response.tags, null, 2));
411
- }
412
- insertTags(response.tags, payload, { debug: jitsuConfig.debug });
413
- }
552
+ response = JSON.parse(responseText);
414
553
  }
415
554
  catch (e) {
416
555
  return Promise.reject(`Can't parse JSON: ${responseText}: ${e === null || e === void 0 ? void 0 : e.message}`);
417
556
  }
557
+ if (response.destinations) {
558
+ if (jitsuConfig.debug) {
559
+ console.log(`[JITSU] Processing device destianations: `, JSON.stringify(response.destinations, null, 2));
560
+ }
561
+ return processDestinations(response.destinations, method, adjustedPayload, !!jitsuConfig.debug, instance);
562
+ }
418
563
  })
419
564
  .catch(err => {
420
565
  if (jitsuConfig.debug) {
@@ -444,9 +589,9 @@ const jitsuAnalyticsPlugin = (pluginConfig = {}) => {
444
589
  name: "jitsu",
445
590
  config: Object.assign(Object.assign({}, config), pluginConfig),
446
591
  initialize: args => {
447
- const { config, instance } = args;
592
+ const { config } = args;
448
593
  if (config.debug) {
449
- console.debug("Initializing Jitsu plugin with config: ", JSON.stringify(config));
594
+ console.debug("[JITSU] Initializing Jitsu plugin with config: ", JSON.stringify(config));
450
595
  }
451
596
  if (!config.host && !config.echoEvents) {
452
597
  throw new Error("Please specify host variable in jitsu plugin initialization, or set echoEvents to true");
@@ -454,17 +599,17 @@ const jitsuAnalyticsPlugin = (pluginConfig = {}) => {
454
599
  },
455
600
  page: args => {
456
601
  const { payload, config, instance } = args;
457
- return send("page", payload, config, cachingStorageWrapper(instance.storage));
602
+ return send("page", payload, config, instance, cachingStorageWrapper(instance.storage));
458
603
  },
459
604
  track: args => {
460
605
  const { payload, config, instance } = args;
461
- return send("track", payload, config, cachingStorageWrapper(instance.storage));
606
+ return send("track", payload, config, instance, cachingStorageWrapper(instance.storage));
462
607
  },
463
608
  identify: args => {
464
609
  const { payload, config, instance } = args;
465
610
  // Store traits in cache to be able to use them in page and track events that run asynchronously with current identify.
466
611
  storageCache["__user_traits"] = payload.traits;
467
- return send("identify", payload, config, cachingStorageWrapper(instance.storage));
612
+ return send("identify", payload, config, instance, cachingStorageWrapper(instance.storage));
468
613
  },
469
614
  reset: args => {
470
615
  //clear storage cache
@@ -517,13 +662,12 @@ function parse(input) {
517
662
  }
518
663
  return value;
519
664
  }
520
- function jitsuAnalytics(opts) {
521
- const rt = opts.runtime || (typeof window === "undefined" ? emptyRuntime(opts) : windowRuntime(opts));
665
+ function createUnderlyingAnalyticsInstance(opts, rt, plugins = []) {
522
666
  const analytics = analyticsLib({
523
667
  app: "test",
524
668
  debug: !!opts.debug,
525
669
  storage: rt.store(),
526
- plugins: [jitsuAnalyticsPlugin(opts)],
670
+ plugins: [jitsuAnalyticsPlugin(opts), ...plugins],
527
671
  });
528
672
  const originalPage = analytics.page;
529
673
  analytics.page = (...args) => {
@@ -536,5 +680,32 @@ function jitsuAnalytics(opts) {
536
680
  };
537
681
  return analytics;
538
682
  }
683
+ function jitsuAnalytics(opts) {
684
+ const inBrowser = isInBrowser();
685
+ const rt = opts.runtime || (inBrowser ? windowRuntime(opts) : emptyRuntime(opts));
686
+ return createUnderlyingAnalyticsInstance(opts, rt);
687
+ // if (inBrowser) {
688
+ // const fetch = opts.fetch || globalThis.fetch;
689
+ // if (!fetch) {
690
+ // throw new Error(
691
+ // "Please specify fetch function in jitsu plugin initialization, fetch isn't available in global scope"
692
+ // );
693
+ // }
694
+ // const url = `${opts.host}/api/s/cfg`;
695
+ // const authHeader = {};
696
+ // const debugHeader = opts.debug ? { "X-Enable-Debug": "true" } : {};
697
+ // fetch(url)
698
+ // .then(res => res.json())
699
+ // .then(res => {
700
+ // result.loaded(createUnderlyingAnalyticsInstance(opts, rt, []));
701
+ // })
702
+ // .catch(e => {
703
+ // console.warn(`[JITSU] error getting device-destinations from ${url}`, e);
704
+ // result.loaded(createUnderlyingAnalyticsInstance(opts, rt));
705
+ // });
706
+ // } else {
707
+ // result.loaded(createUnderlyingAnalyticsInstance(opts, rt));
708
+ // }
709
+ }
539
710
 
540
- export { emptyRuntime, getTopLevelDomain, jitsuAnalytics, parseQuery, randomId, windowRuntime };
711
+ export { emptyRuntime, getTopLevelDomain, isInBrowser, jitsuAnalytics, parseQuery, randomId, windowRuntime };
@@ -0,0 +1,17 @@
1
+ export type InterfaceWrapper<T> = {
2
+ get(): WithAsyncMethods<T>;
3
+ loaded(instance: T): any;
4
+ };
5
+ type WithAsyncMethods<T> = {
6
+ [K in keyof T]: T[K] extends (...args: infer A) => infer R ? (...args: A) => R extends Promise<any> ? R : Promise<R> : T[K];
7
+ };
8
+ /**
9
+ * This function creates a wrapper around an interface that allows to call methods on it, but all methods will go to queue. Once actual instance
10
+ * implementation becomes available, all queued methods will be called on it.
11
+ *
12
+ *
13
+ * @param methods of methods that should be wrapped. Per each method of you should specify if it should be wrapped. You'll need to mark all
14
+ * methods for type safety. If method is not wrapped, it will throw an error when called.
15
+ */
16
+ export declare function delayMethodExec<T>(methods: Record<keyof T, boolean>): InterfaceWrapper<T>;
17
+ export {};
@@ -0,0 +1 @@
1
+ export declare function loadScript(src: string, attributes?: Record<string, string>): Promise<HTMLScriptElement>;