1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
|
import { reflect, string, storage } from '@amp-metrics/mt-metricskit-utils-private';
/*
* src/helpers/constants.js
* ae-client-kit-core
*
* Copyright © 2019 Apple Inc. All rights reserved.
*
*/
var _allBaseFieldNames;
var _environmentBaseFieldNames;
function requiredEnvironmentBaseFieldNames() {
return [
'app',
'appVersion',
'hardwareFamily',
'hardwareModel',
'os',
'osBuildNumber',
'osLanguages',
'osVersion',
'resourceRevNum',
'screenHeight',
'screenWidth',
'userAgent'
];
}
function optionalEnvironmentBaseFieldNames() {
return ['delegateApp', 'hardwareBrand', 'storeFrontCountryCode', 'storeFrontHeader', 'storeFrontLanguage'];
}
function otherBaseFieldNames() {
return [
'baseVersion',
'clientEventId',
'connection',
'eventTime',
'eventType',
'eventVersion',
'timezoneOffset',
'xpPostFrequency',
'xpSendMethod'
];
}
function environmentBaseFieldNames() {
if (!_environmentBaseFieldNames) {
_environmentBaseFieldNames = requiredEnvironmentBaseFieldNames().concat(optionalEnvironmentBaseFieldNames());
}
return _environmentBaseFieldNames;
}
function allBaseFieldNames() {
if (!_allBaseFieldNames) {
_allBaseFieldNames = environmentBaseFieldNames().concat(otherBaseFieldNames());
}
return _allBaseFieldNames;
}
/*
* src/event_handlers/Base.js
* ae-client-kit-core
*
* Copyright © 2018 Apple Inc. All rights reserved.
*
*/
var attachDelegate = reflect.attachDelegate;
var cryptoRandomBase62String = string.cryptoRandomBase62String;
var exceptionString = string.exceptionString;
var _prototypeInitialized;
/**
* Creates and returns an object (key/value data map (dictionary)) containing all of the "base" fields common to all metrics events.
* To override any functionality in this class, use the "setDelegate() method in order to override the specific functions that need customization.
* Kits can also extend this class and additional methods specific to their event model.
* @example
* // extend kit-core Base class
* var MetricsKitBase = function MetricsKitBase() {
* kitCore.eventHandlers.Base.apply(this, arguments); // invoke Base constructor
* };
* MetricsKitBase.prototype = new kitCore.eventHandlers.Base();
* MetricsKitBase.prototype.constructor = MetricsKitBase;
*
* // set Kit-specific methods
* MetricsKitBase.prototype.environment = function() { return metricsKit.system.environment; }
* MetricsKitBase.prototype.eventRecorder = function() { return metricsKit.system.eventRecorder; }
* MetricsKitBase.prototype.metricsData = function(pageId, pageType, pageContext, callerSuppliedFieldsMapsN) { ... }
* MetricsKitBase.prototype.processMetricsData = function( ... ) { ... }
*
* // extend kit-core known fields
* MetricsKitBase.prototype.knownFields = function knownFields() {
* var parentKnownFields = Object.getPrototypeOf(MetricsKitBase.prototype).knownFields();
* return parentKnownFields.concat(['dsId', 'anotherUserExperienceOnlyField']);
* };
*
* // add Kit-specific accessor functions
* MetricsKitBase.prototype.dsId = function dsId() { return this.environment().dsId(); };
* MetricsKitBase.prototype.anotherUserExperienceOnlyField = function() { ... };
*
* // create a Kit-specific class instance
* metricsKit.eventHandlers.base = new MetricsKitBase(metricsKit);
* @param {MetricsKit/PerfKit/VPAFKit} kit
* @delegatable
* @constructor
*/
function Base(processor) {
if (!reflect.isDefinedNonNull(processor)) {
throw new Error('A processor instance is required for creating BaseEventHandler.');
}
// @private
this._processor = processor;
if (!_prototypeInitialized) {
_prototypeInitialized = true;
environmentBaseFieldNames().forEach(function (fieldName) {
Base.prototype[fieldName] = function (callerSuppliedEventFields) {
var returnValue;
if (callerSuppliedEventFields && callerSuppliedEventFields.hasOwnProperty(fieldName)) {
returnValue = callerSuppliedEventFields[fieldName];
} else {
returnValue = this.environment()[fieldName]();
}
return returnValue;
};
});
}
}
Base._className = 'eventHandlers.base';
/**
* Allows replacement of one or more of this class instance's functions
* Any method on the passed-in object which matches a method that this class has will be called instead of the built-in class method.
* To replace *all* methods of his class, simply have your delegate implement all the methods of this class
* Your delegate can be a true object instance, an anonymous object, or a class object.
* Your delegate is free to have as many additional non-matching methods as it likes (these methods will not be copied to the target object).
* It can even act as a delegate for multiple MetricsKit objects, though that is not recommended.
*
* "setDelegate()" may be called repeatedly, with the functions in the most-recently set delegates replacing any functions matching those in the earlier delegates, as well as any as-yet unreplaced functions.
* This allows callers to replace some number of methods that need custom implementations.
* If, for example, a client wants to use the standard logger implementation with the exception of, say, the "debug" method, they can
* call "setDelegate()" with their own delegate containing only a single method of "debug" as the delegate, which would leave all the other methods intact.
*
* NOTE: The delegate function will have a property called origFunction representing the original function that it replaced.
* This allows the delegate to, essentially, call "super" before or after it does some work.
* If a replaced method is overridden again with a subsequent "setDelegate()" call, the "origFunction" property will be the previous delegate's function.
* @example:
* To override one or more methods, in place:
* base.setDelegate({ app: function() { return 'myApp'; });
* To override one or more methods with a separate object:
* base.setDelegate(customBaseDelegate);
* (where "customBaseDelegate" might be defined elsewhere as, e.g.:
* var customBaseDelegate = { app: function() { return Device.appIdentifier; };
* appVersion: function() { return Device.appVersion; } };
* To override one or more methods with an instantiated object from a class definition:
* base.setDelegate(new CustomBaseDelegate());
* (where "CustomBaseDelegate" might be defined elsewhere as, e.g.:
* function CustomBaseDelegate() {}
* CustomBaseDelegate.prototype.app = function app() { return Device.appIdentifier; };
* CustomBaseDelegate.prototype.appVersion = function appVersion() { return Device.appVersion; };
* To override one or more methods with a class object (with "static" methods):
* base.setDelegate(CustomBaseDelegate);
* (where "CustomBaseDelegate" might be defined elsewhere as, e.g.:
* function CustomBaseDelegate() {}
* CustomBaseDelegate.app = function app() { return Device.appIdentifier; };
* CustomBaseDelegate.appVersion = function appVersion() { return Device.appVersion; };
* @param {Object} delegate Object or Class with delegate method(s) to be called instead of default (built-in) methods.
* @returns {Boolean} true if one or more methods on the delegate object match one or more methods on the default object,
* otherwise returns false.
*/
Base.prototype.setDelegate = function setDelegate(delegate) {
return attachDelegate(this, delegate);
};
/**
* The active environment class
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @see src/system/Environment
* @return {Environment}
* @overridable
*/
Base.prototype.environment = function environment() {
// Don't wrap the throw in a helper function or the backtrace won't be as nice.
throw exceptionString(Base._className, 'environment');
};
/**
* The active eventRecorder
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @return {Object} an event recorder that implements a sendMethod() function
* @overridable
*/
Base.prototype.eventRecorder = function eventRecorder() {
// Don't wrap the throw in a helper function or the backtrace won't be as nice.
throw exceptionString(Base._className, 'eventRecorder');
};
/**
* Creates a simple map object (dictionary) with all the "base" fields required by AMP Analytics
* Some fields can be derived by this class itself.
* Some fields need to be provided by callers.
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @returns key/value pairs of all "base" fields required by AMP Analytics.
* WARNING: May return "null" if metrics are disabled via the metrics.disabled config source value, or on error.
* @overridable
*
* TODO: consider adding default implementation for shared Kit use
*/
Base.prototype.metricsData = function metricsData() {
// Don't wrap the throw in a helper function or the backtrace won't be as nice.
throw exceptionString(Base._className, 'metricsData');
};
/**
* All of the various eventHandlers invoke this method to generate their metrics data
* The data is a simple map object (dictionary) with all the fields required by AMP Analytics for that event
* Some fields can be derived by this class itself.
* This function typically expects to be called with the correct context
* (e.g. base.processMetricsData.apply(this, arguments))
* @returns {Object} key/value pairs of all fields required by AMP Analytics.
* WARNING: May return "null" if metrics and/or the specific eventType for this handler is disabled, or on error.
*
* TODO: consider adding default implementation for shared Kit use
*/
Base.prototype.processMetricsData = function processMetricsData() {
// Don't wrap the throw in a helper function or the backtrace won't be as nice.
throw exceptionString(Base._className, 'processMetricsData');
};
/**
* @return {Array} all the fields that base eventHandlers know about
*/
Base.prototype.knownFields = function knownFields() {
return allBaseFieldNames();
};
/**
* ********************* ACCESSOR FUNCTIONS *********************
* We create accessor functions for every data field because:
* 1. Cleans/simplifies all methods that use it.
* 2. Facilitates writing test case shims
* 3. Allows specific feature suppliers to be overridden (via setDelegate()))
*/
/**
* The app identifier of the binary app
* @param {Map} callerSuppliedEventFields
* @returns {String} The app identifier of the binary app
* @example "com.apple.appstore" or "com.apple.gamecenter"
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Base.prototype.app = function app(callerSuppliedEventFields) { };
/**
* The version number of this application
* @example "1.0", "5.43", etc.
* @param {Map} callerSuppliedEventFields
* @returns {String} the version number of this application
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Base.prototype.appVersion = function appVersion(callerSuppliedEventFields) { };
/**
* The version of the set of base data to be sent up
* @returns {number} the version of the set of base data to be sent up
* @overridable
*/
Base.prototype.baseVersion = function baseVersion() {
return 1;
};
/**
* A unique identifier for each event
* @return {String}
* @overridable
*/
Base.prototype.clientEventId = function clientEventId(callerSuppliedEventFields) {
return (callerSuppliedEventFields && callerSuppliedEventFields.clientEventId) || cryptoRandomBase62String(true);
};
/**
* Type of internet connection.
* Only applicable to devices
* Beware that users on WiFi may actually be receiving 3G speeds (i.e. if device is tethered to a portable hotspot.)
* @example "WiFi, "3G, etc.
* @param {Map} callerSuppliedEventFields
* @returns {String} type of internet connection
* @overridable
*/
Base.prototype.connection = function connection(callerSuppliedEventFields) {
return (callerSuppliedEventFields && callerSuppliedEventFields.connection) || this.environment().connectionType();
};
/**
* The identifier of the process generating the event, if different from “app”, or blank otherwise.
* @example 'web-experience-app'
* @returns {String}
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Base.prototype.delegateApp = function delegateApp(callerSuppliedEventFields) { };
/**
* The id of this user ("directory service id").
* This id will get mapped to a consumerId on the server.
* @example 659261189
* @param {Map} callerSuppliedEventFields
* @returns {String}
* @overridable
*/
Base.prototype.dsId = function dsId(callerSuppliedEventFields) {
return (callerSuppliedEventFields && callerSuppliedEventFields.dsId) || this.environment().dsId();
};
/**
* The time (UTC) in milliseconds at which this event happened.
* This field is central to determining the sequence of user events
* Use online epoch converter to test your values.
* @example 1437356433388 (http://www.epochconverter.com converts that to: July 19, 2015 at 6:40:33 PM PDT GMT-7:00 DST)
* @param {Map} callerSuppliedEventFields
* @returns {number} the time (UTC) in milliseconds at which this event happened
* @overridable
*/
Base.prototype.eventTime = function eventTime(callerSuppliedEventFields) {
return (callerSuppliedEventFields && callerSuppliedEventFields.eventTime) || Date.now();
};
/**
* The version of the set of data to be sent up
* @return {Number}
* @overridable
*/
Base.prototype.eventVersion = function eventVersion(callerSuppliedEventFields) {
return (callerSuppliedEventFields && callerSuppliedEventFields.eventVersion) || null;
};
/**
* The hardware brand of the device. Not required for Apple devices.
* @example "Samsung", "LG", "Google"
* @param {Map} callerSuppliedEventFields
* @returns {String}
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Base.prototype.hardwareBrand = function hardwareBrand(callerSuppliedEventFields) { };
/**
* The hardware family of the device
* @example "iPhone", "Macbook Pro"
* @param {Map} callerSuppliedEventFields
* @returns {String}
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Base.prototype.hardwareFamily = function hardwareFamily(callerSuppliedEventFields) { };
/**
* The model of the device
* @example "iPhone10,2", "MacbookPro11,5"
* @returns {String}
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Base.prototype.hardwareModel = function hardwareModel(callerSuppliedEventFields) { };
/**
* The name of the OS
* @example "ios", "macos", "windows"
* @param {Map} callerSuppliedEventFields
* @returns {String}
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Base.prototype.os = function os(callerSuppliedEventFields) { };
/**
* The build number of the OS
* @example "15D60", "17E192"
* @param {Map} callerSuppliedEventFields
* @returns {String}
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Base.prototype.osBuildNumber = function osBuildNumber(callerSuppliedEventFields) { };
/**
* A string array of language IDs, ordered in descending preference
* @example ["en-US", "fr-CA"]
* @param {Map} callerSuppliedEventFields
* @returns {Array}
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Base.prototype.osLanguages = function osLanguages(callerSuppliedEventFields) { };
/**
* The full OS version number
* In ITML, the value can be retrieved via Device.systemVersion
* @example "8.2.1" (iOS) "10.10.3" (Desktop)
* @param {Map} callerSuppliedEventFields
* @returns {String} the full OS version number
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Base.prototype.osVersion = function osVersion(callerSuppliedEventFields) { };
/**
* The HTML resources revision number
* @example 2C97 or 8.4.0.0.103
* @param {Map} callerSuppliedEventFields
* @returns {String} the HTML resources revision number
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Base.prototype.resourceRevNum = function resourceRevNum(callerSuppliedEventFields) { };
/**
* The client screen height in pixels
* @example 568
* @param {Map} callerSuppliedEventFields
* @returns {number} the client screen height in pixels
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Base.prototype.screenHeight = function screenHeight(callerSuppliedEventFields) { };
/**
* The client screen width in pixels
* @example 320
* @param {Map} callerSuppliedEventFields
* @returns {number} the client screen width in pixels
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Base.prototype.screenWidth = function screenWidth(callerSuppliedEventFields) { };
/**
* ISO 3166 Country Code. Apps that cannot provide a storeFrontHeader should provide a storeFrontCountryCode instead
* @example US
* @param {Map} callerSuppliedEventFields
* @returns {String} the store front country code
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Base.prototype.storeFrontCountryCode = function storeFrontCountryCode(callerSuppliedEventFields) { };
/**
* The value contained in the X-Apple-Store-Front header value at the time the event is being created.
* @example K143441-1,29 ab:rSwnYxS0
* @param {Map} callerSuppliedEventFields
* @returns {String} the value contained in the X-Apple-Store-Front header value at the time the event is being created
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Base.prototype.storeFrontHeader = function storeFrontHeader(callerSuppliedEventFields) { };
/**
* The difference, in minutes, between GMT (UTC) and timezone of event origin ("local time).
* This means that the offset is positive if the local timezone is behind UTC and negative if it is ahead.
* Daylight saving time prevents this value from being a constant, even for a given locale
* @example 420 (PST, not -420) or -600 (Australian Eastern Standard Time, UTC+10)
* @param {Map} callerSuppliedEventFields
* @returns {number} the difference, in minutes, between GMT (UTC) and timezone of event origin ("local time).
* @overridable
*/
Base.prototype.timezoneOffset = function timezoneOffset(callerSuppliedEventFields) {
return (callerSuppliedEventFields && callerSuppliedEventFields.timezoneOffset) || new Date().getTimezoneOffset();
};
/**
* The client’s user agent string. If the "app field is not provided, "userAgent may be used to derive the value of the "app field
* @example AppStore/2.0 iOS/8.3 model/iPhone7,2 build/12F70 (6; dt:106)
* @param {Map} callerSuppliedEventFields
* @returns {String} the client’s user agent string. If the "app field is not provided, "userAgent may be used to derive the value of the "app field
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Base.prototype.userAgent = function userAgent(callerSuppliedEventFields) { };
/**
* How often, in milliseconds, batches of events should get sent to the server.
* This field should be based on the client's most recent config value of "postFrequency".
* This is valuable for problem analysis because it indicates if and how clients are honoring the "postFrequency" value
* they were supplied with.
* This cannot be a "passthrough" field, because it can change (via new config) during program execution, so the value
* in effect at event creation time is what is needed.
* @example 60000
* @param {Map} callerSuppliedEventFields
* @returns {number} how often, in milliseconds, batches of events should get sent to the server
* @overridable
*/
Base.prototype.xpPostFrequency = function xpPostFrequency(callerSuppliedEventFields) {
return (
(callerSuppliedEventFields && callerSuppliedEventFields.xpPostFrequency) ||
this._processor.config.value('postFrequency')
);
};
/**
* The methodology being used by the eventRecorder to send batches of events to the server
* This field should be hardcoded in the client based on what method it is using to encode and send its events to Figaro.
* The three typical values are:
* "itms" - use this value when/if JavaScript code enqueues events for sending via the "itms.recordEvent()" method in ITML.
* "itunes" - use this value when/if JavaScript code enqueues events by calling the "iTunes.recordEvent()" method in Desktop Store apps.
* "javascript" - use this value when/if JavaScript code enqueues events for sending via the JavaScript eventQueue management. This is typically only used by older clients which don't have the built-in functionality of itms or iTunes available to them.
* @example "itms", "itunes", "javascript"
* @param {Map} callerSuppliedEventFields
* @returns {String} the methodology being used by the eventRecorder to send batches of events to the server
* @overridable
*/
Base.prototype.xpSendMethod = function (callerSuppliedEventFields) {
return (callerSuppliedEventFields && callerSuppliedEventFields.xpSendMethod) || this.eventRecorder().sendMethod();
};
/*
* src/event_handlers/index.js
* ae-client-kit-core
*
* Copyright © 2018 Apple Inc. All rights reserved.
*
*/
var eventHandlers = {
Base: Base
};
/*
* src/system/Environment.js
* ae-client-kit-core
*
* Copyright © 2018 Apple Inc. All rights reserved.
*
*/
var attachDelegate$1 = reflect.attachDelegate;
var exceptionString$1 = string.exceptionString;
var localStorageObject = storage.localStorageObject;
var sessionStorageObject = storage.sessionStorageObject;
var _prototypeInitialized$1;
/**
* Provides a set of environment-specific (platform-specific) functions which can be individually overridden for the needs
* of the particular environment, or replaced en masse by providing a single replacement environment delegate object.
* Kits can extend this class and additional methods specific to their event model.
* @example
* // MetricsKit code
*
* // extend kit-core Environment class
* var MetricsKitEnvironment = function MetricsKitEnvironment() {
* kitCore.system.Environment.apply(this, arguments); // invoke Environment constructor
* };
* MetricsKitEnvironment.prototype = new kitCore.system.Environment();
* MetricsKitEnvironment.prototype.constructor = MetricsKitEnvironment;
*
* // add Kit-specific functions
* MetricsKitEnvironment.prototype.dsId = function dsId() {
* throw this._exceptionString(_utils.reflect.functionName());
* };
* MetricsKitEnvironment.prototype.anotherUserExperienceOnlyField = function() { ... };
*
* // create a Kit-specific class instance
* metricsKit.system.environment = new MetricsKitEnvironment();
*
* // client app code remains unchanged:
* var customEnvironmentDelegate = {
* app: function() { return 'myAppName'; },
* appVersion: function() { ... } // etc.
* };
*
* metricsKit.system.environment.setDelegate(customEnvironmentDelegate);
*
* @constructor
*/
function Environment() {
// consider moving this code into a separate init method
if (!_prototypeInitialized$1) {
_prototypeInitialized$1 = true;
requiredEnvironmentBaseFieldNames().forEach(function (fieldName) {
Environment.prototype[fieldName] = function () {
throw exceptionString$1(Environment._className, fieldName);
};
});
optionalEnvironmentBaseFieldNames().forEach(function (fieldName) {
Environment.prototype[fieldName] = function () {};
});
}
}
Environment._className = 'system.environment';
/**
* Allows replacement of one or more of this class instance's functions
* Any method on the passed-in object which matches a method that this class has will be called instead of the built-in class method.
* To replace *all* methods of his class, simply have your delegate implement all the methods of this class
* Your delegate can be a true object instance, an anonymous object, or a class object.
* Your delegate is free to have as many additional non-matching methods as it likes (these methods will not be copied to the target object).
* It can even act as a delegate for multiple MetricsKit objects, though that is not recommended.
*
* "setDelegate()" may be called repeatedly, with the functions in the most-recently set delegates replacing any functions matching those in the earlier delegates, as well as any as-yet unreplaced functions.
* This allows callers to replace some number of methods that need custom implementations.
* If, for example, a client wants to use the standard logger implementation with the exception of, say, the "debug" method, they can
* call "setDelegate()" with their own delegate containing only a single method of "debug" as the delegate, which would leave all the other methods intact.
*
* NOTE: The delegate function will have a property called origFunction representing the original function that it replaced.
* This allows the delegate to, essentially, call "super" before or after it does some work.
* If a replaced method is overridden again with a subsequent "setDelegate()" call, the "origFunction" property will be the previous delegate's function.
* @example:
* To override one or more methods, in place:
* environment.setDelegate({ app: function() { return 'myApp'; });
* To override one or more methods with a separate object:
* environment.setDelegate(customEnvironmentDelegate);
* (where "customEnvironmentDelegate" might be defined elsewhere as, e.g.:
* var customEnvironmentDelegate = { app: function() { return Device.appIdentifier; },
* appVersion: function() { return Device.appVersion; } };
* To override one or more methods with an instantiated object from a class definition:
* environment.setDelegate(new CustomEnvironmentDelegate());
* (where "CustomEnvironmentDelegate" might be defined elsewhere as, e.g.:
* function CustomEnvironmentDelegate() {}
* CustomEnvironmentDelegate.prototype.app = function app() { return Device.appIdentifier; };
* CustomEnvironmentDelegate.prototype.appVersion = function appVersion() { return Device.appVersion; };
* To override one or more methods with a class object (with "static" methods):
* environment.setDelegate(CustomEnvironmentDelegate);
* (where "CustomEnvironmentDelegate" might be defined elsewhere as, e.g.:
* function CustomEnvironmentDelegate() {}
* CustomEnvironmentDelegate.app = function app() { return Device.appIdentifier; };
* CustomEnvironmentDelegate.appVersion = function appVersion() { return Device.appVersion; };
* @param {Object} delegate Object or Class with delegate method(s) to be called instead of default (built-in) methods.
* @returns {Boolean} true if one or more methods on the delegate object match one or more methods on the default object,
* otherwise returns false.
*/
Environment.prototype.setDelegate = function setDelegate(delegate) {
return attachDelegate$1(this, delegate);
};
/**
* The app identifier of the binary app
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @example "com.apple.appstore" or "com.apple.gamecenter"
* @returns {String}
*/
// This prototype method is created dynamically upon instance initialization
// Environment.prototype.app = function app() { };
/**
* The version number of this application
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @example "1.0", "5.43", etc.
* @returns {String}
*/
// This prototype method is created dynamically upon instance initialization
// Environment.prototype.appVersion = function appVersion() { };
/**
* Type of internet connection.
* Only applicable to devices
* Beware that users on WiFi may actually be receiving 3G speeds (i.e. if device is tethered to a portable hotspot.)
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @example "WiFi, "3G, etc.
* @returns {String}
*/
Environment.prototype.connectionType = function connectionType() {
// Don't wrap the throw in a helper function or the backtrace won't be as nice.
// TODO: use a constant instead of a hardcoded string
throw exceptionString$1(Environment._className, 'connectionType');
};
/**
* The identifier of the process generating the event, if different from “app”, or blank otherwise.
* NO DEFAULT IMPLEMENTATION... HOWEVER: these fields are not required, so an exception will not be thrown if they
* are omitted.
* @example 'web-experience-app'
* @returns {String}
*/
// This prototype method is created dynamically upon instance initialization
// Environment.prototype.delegateApp = function delegateApp(callerSuppliedEventFields) { };
/**
* The id of this user ("directory service id").
* This id will get mapped to a consumerId on the server.
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @example 659261189
* @returns {String}
*/
// This prototype method is created dynamically upon instance initialization
Environment.prototype.dsId = function dsId() {
// Don't throw an exception to avoid breaking minor version backwards compatibility.
// Consider adding an exception in the next major version.
};
/**
* The hardware brand of the device. Not required for Apple devices.
* NO DEFAULT IMPLEMENTATION... HOWEVER: these fields are not required, so an exception will not be thrown if they
* are omitted.
* @example "Samsung", "LG", "Google"
* @returns {String}
*/
// This prototype method is created dynamically upon instance initialization
// Environment.prototype.hardwareBrand = function hardwareBrand() { };
/**
* The hardware family of the device
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @example "iPhone", "Macbook Pro"
* @returns {String}
*/
// This prototype method is created dynamically upon instance initialization
// Environment.prototype.hardwareFamily = function hardwareFamily() { };
/**
* The model of the device
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @example "iPhone10,2", "MacbookPro11,5"
* @returns {String}
*/
// This prototype method is created dynamically upon instance initialization
// Environment.prototype.hardwareModel = function hardwareModel() { };
/**
* The name of the OS
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @example "ios", "macos", "windows"
* @returns {String}
*/
// This prototype method is created dynamically upon instance initialization
// Environment.prototype.os = function os() { };
/**
* The build number of the OS
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @example "15D60", "17E192"
* @returns {String}
*/
// This prototype method is created dynamically upon instance initialization
// Environment.prototype.osBuildNumber = function osBuildNumber() { };
/**
* A string array of language IDs, ordered in descending preference
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @example ["en-US", "fr-CA"]
* @returns {Array}
*/
// This prototype method is created dynamically upon instance initialization
// Environment.prototype.osLanguages = function osLanguages() { };
/**
* The full OS version number
* In ITML, the value can be retrieved via Device.systemVersion
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @example "8.2.1" (iOS) "10.10.3" (Desktop)
* @returns {String}
*/
// This prototype method is created dynamically upon instance initialization
// Environment.prototype.osVersion = function osVersion() { };
/**
* HTML resources revision number
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @example 2C97 or 8.4.0.0.103
* @returns {String}
*/
// This prototype method is created dynamically upon instance initialization
// Environment.prototype.resourceRevNum = function resourceRevNum() { };
/**
* Client screen height in pixels
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @example 568
* @returns {number}
*/
// This prototype method is created dynamically upon instance initialization
// Environment.prototype.screenHeight = function screenHeight() { };
/**
* Client screen width in pixels
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @example 320
* @returns {number}
*/
// This prototype method is created dynamically upon instance initialization
// Environment.prototype.screenWidth = function screenWidth() { };
/**
* ISO 3166 Country Code. Apps that cannot provide a storeFrontHeader should provide a storeFrontCountryCode instead
* NO DEFAULT IMPLEMENTATION... Either this method or storeFrontHeader must be replaced.
* are omitted.
* @example US
* @param {Map} callerSuppliedEventFields
* @returns {String} the store front country code
* @overridable
*/
// This prototype method is created dynamically upon instance initialization
// Environment.prototype.storeFrontCountryCode = function storeFrontCountryCode(callerSuppliedEventFields) { };
/**
* The value contained in the X-Apple-Store-Front header value at the time the event is being created.
* NO DEFAULT IMPLEMENTATION... Either this method or storeFrontHeader must be replaced.
* @example K143441-1,29 ab:rSwnYxS0
* @returns {String}
*/
// This prototype method is created dynamically upon instance initialization
// Environment.prototype.storeFrontHeader = function storeFrontHeader() { };
/**
* Client’s user agent string. If the "app field is not provided, "userAgent may be used to derive the value of the "app field
* NO DEFAULT IMPLEMENTATION... THIS METHOD MUST BE REPLACED
* @example AppStore/2.0 iOS/8.3 model/iPhone7,2 build/12F70 (6; dt:106)
* @returns {String}
*/
// This prototype method is created dynamically upon instance initialization
// Environment.prototype.userAgent = function userAgent() { };
/**
* Some clients have platform-specific implementations of these objects (e.g. iTunes.sessionStorage),
* so we cover them in case they need to be overridden.
*/
Environment.prototype.localStorageObject = localStorageObject;
Environment.prototype.sessionStorageObject = sessionStorageObject;
/**
* Fetching identifier entity from AMS Metrics Identifier API
* @param {String} idNamespace - The id namespace that is defined under 'metricsIdentifier' in the bag
* @param {'userid' | 'clientid'} idType - The identifier type (userid or clientid)
* @param {Boolean} crossDeviceSync - The boolean flag to indicate whether the identifier is synced across devices
* @returns {Promise}
* @overridable
*/
Environment.prototype.platformIdentifier = function platformIdentifier() {};
/*
* src/system/index.js
* ae-client-kit-core
*
* Copyright © 2018 Apple Inc. All rights reserved.
*
*/
var system = {
Environment: Environment
};
/*
* src/helpers/MetricsData.js
* ae-client-kit-core
*
* Copyright © 2018 Apple Inc. All rights reserved.
*
*/
/**
* Creates and returns a MetricsData instance with APIs to store event data and create and send events to AMP Analytics
* @delegatable
* @constructor
* @return {MetricsData}
*/
function MetricsData() {
// @private
this._eventData = {}; // this data may be unclean; it should be cleaned before being enqueued as an event
}
/**
************************************ PUBLIC METHODS/IVARS ************************************
*/
/**
* Add event data to this metricsData object
* This data may be unclean; it should be cleaned before being enqueued as an event
* @param {Object<varargs>} callerSuppliedEventFieldsMapN a variable number of Object arguments from 0-N,
* each containing key/value pairs representing event fields to include when sending the event.
* Later objects take precedence over earlier ones, overriding any field value that may have already been there.
* @overridable
*/
MetricsData.prototype.updateData = function updateData(/* callerSuppliedEventFieldsMapN(varargs) */) {
reflect.extend.apply(null, [this._eventData].concat(Array.prototype.slice.call(arguments)));
};
/*
* src/helpers/index.js
* ae-client-kit-core
*
* Copyright © 2018 Apple Inc. All rights reserved.
*
*/
var helpers = {
MetricsData: MetricsData
};
export { eventHandlers, helpers, system };
|