@mparticle/web-sdk 2.56.0 → 2.58.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/dist/mparticle.common.js +39 -39
- package/dist/mparticle.esm.js +39 -39
- package/dist/mparticle.js +292 -62
- package/package.json +1 -1
- package/src/constants.ts +4 -0
- package/src/identityApiClient.ts +24 -11
- package/src/logger.ts +14 -5
- package/src/logging/reportingLogger.ts +192 -0
- package/src/logging/types.ts +32 -0
- package/src/mp-instance.ts +58 -11
- package/src/roktManager.ts +38 -6
- package/src/sdkRuntimeModels.ts +46 -17
- package/src/store.ts +31 -10
- package/src/types.ts +1 -0
- package/src/uploaders.ts +1 -0
package/package.json
CHANGED
package/src/constants.ts
CHANGED
|
@@ -139,6 +139,8 @@ const Constants = {
|
|
|
139
139
|
identityUrl: 'identity.mparticle.com/v1/',
|
|
140
140
|
aliasUrl: 'jssdks.mparticle.com/v1/identity/',
|
|
141
141
|
userAudienceUrl: 'nativesdks.mparticle.com/v1/',
|
|
142
|
+
loggingUrl: 'apps.rokt-api.com/v1/log',
|
|
143
|
+
errorUrl: 'apps.rokt-api.com/v1/errors',
|
|
142
144
|
},
|
|
143
145
|
// These are the paths that are used to construct the CNAME urls
|
|
144
146
|
CNAMEUrlPaths: {
|
|
@@ -148,6 +150,8 @@ const Constants = {
|
|
|
148
150
|
configUrl: '/tags/JS/v2/',
|
|
149
151
|
identityUrl: '/identity/v1/',
|
|
150
152
|
aliasUrl: '/webevents/v1/identity/',
|
|
153
|
+
loggingUrl: '/v1/log',
|
|
154
|
+
errorUrl: '/v1/errors',
|
|
151
155
|
},
|
|
152
156
|
Base64CookieKeys: {
|
|
153
157
|
csm: 1,
|
package/src/identityApiClient.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import Constants, { HTTP_ACCEPTED, HTTP_BAD_REQUEST, HTTP_OK } from './constants';
|
|
1
|
+
import Constants, { HTTP_ACCEPTED, HTTP_BAD_REQUEST, HTTP_OK, HTTP_SERVER_ERROR } from './constants';
|
|
2
2
|
import {
|
|
3
3
|
AsyncUploader,
|
|
4
4
|
FetchUploader,
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
IIdentityResponse,
|
|
26
26
|
} from './identity-user-interfaces';
|
|
27
27
|
import { IMParticleWebSDKInstance } from './mp-instance';
|
|
28
|
+
import { ErrorCodes } from './logging/types';
|
|
28
29
|
|
|
29
30
|
const { HTTPCodes, Messages, IdentityMethods } = Constants;
|
|
30
31
|
|
|
@@ -284,15 +285,26 @@ export default function IdentityAPIClient(
|
|
|
284
285
|
break;
|
|
285
286
|
|
|
286
287
|
// Our Identity API will return:
|
|
287
|
-
//
|
|
288
|
-
//
|
|
288
|
+
// 401 if the `x-mp-key` is incorrect or missing
|
|
289
|
+
// 403 if the there is a permission or account issue related to the `x-mp-key`
|
|
289
290
|
// 401 and 403 have no response bodies and should be rejected outright
|
|
291
|
+
// 5xx server error throws error but RoktManager continues
|
|
290
292
|
default: {
|
|
291
|
-
|
|
293
|
+
if (response.status >= HTTP_SERVER_ERROR) {
|
|
294
|
+
throw new Error('Received HTTP Code of ' + response.status);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
mpInstance._Store.identityCallInFlight = false;
|
|
298
|
+
mpInstance._Store.identityCallFailed = false;
|
|
299
|
+
const errorMessage = 'Received HTTP Code of ' + response.status;
|
|
300
|
+
Logger.error('Error sending identity request to servers - ' + errorMessage);
|
|
301
|
+
invokeCallback(callback, HTTPCodes.noHttpCoverage, errorMessage);
|
|
302
|
+
return;
|
|
292
303
|
}
|
|
293
304
|
}
|
|
294
305
|
|
|
295
306
|
mpInstance._Store.identityCallInFlight = false;
|
|
307
|
+
mpInstance._Store.identityCallFailed = false;
|
|
296
308
|
|
|
297
309
|
Logger.verbose(message);
|
|
298
310
|
if (mpInstance._RoktManager?.isInitialized) {
|
|
@@ -310,19 +322,20 @@ export default function IdentityAPIClient(
|
|
|
310
322
|
);
|
|
311
323
|
} catch (err) {
|
|
312
324
|
mpInstance._Store.identityCallInFlight = false;
|
|
325
|
+
mpInstance._Store.identityCallFailed = true;
|
|
313
326
|
if (mpInstance._RoktManager?.isInitialized) {
|
|
314
327
|
const requestCount = mpInstance._Store.identifyRequestCount;
|
|
315
328
|
mpInstance.captureTiming(`${requestCount}-identityRequestEnd`);
|
|
316
329
|
}
|
|
317
|
-
|
|
318
|
-
const errorMessage = (err as Error).message || err.toString();
|
|
319
330
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
errorMessage,
|
|
331
|
+
const errorMessage = (err as Error).message || err.toString();
|
|
332
|
+
Logger.error(
|
|
333
|
+
'Error sending identity request to servers' + ' - ' + errorMessage,
|
|
334
|
+
ErrorCodes.IDENTITY_REQUEST
|
|
325
335
|
);
|
|
336
|
+
|
|
337
|
+
mpInstance.processQueueOnIdentityFailure?.();
|
|
338
|
+
invokeCallback(callback, HTTPCodes.noHttpCoverage, errorMessage);
|
|
326
339
|
}
|
|
327
340
|
};
|
|
328
341
|
|
package/src/logger.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { LogLevelType, SDKInitConfig, SDKLoggerApi } from './sdkRuntimeModels';
|
|
2
|
+
import { ReportingLogger } from './logging/reportingLogger';
|
|
3
|
+
import { ErrorCodes } from './logging/types';
|
|
2
4
|
|
|
3
5
|
export type ILoggerConfig = Pick<SDKInitConfig, 'logLevel' | 'logger'>;
|
|
4
6
|
export type IConsoleLogger = Partial<Pick<SDKLoggerApi, 'error' | 'warning' | 'verbose'>>;
|
|
@@ -6,10 +8,14 @@ export type IConsoleLogger = Partial<Pick<SDKLoggerApi, 'error' | 'warning' | 'v
|
|
|
6
8
|
export class Logger {
|
|
7
9
|
private logLevel: LogLevelType;
|
|
8
10
|
private logger: IConsoleLogger;
|
|
11
|
+
private reportingLogger: ReportingLogger;
|
|
9
12
|
|
|
10
|
-
constructor(config: ILoggerConfig
|
|
13
|
+
constructor(config: ILoggerConfig,
|
|
14
|
+
reportingLogger?: ReportingLogger,
|
|
15
|
+
) {
|
|
11
16
|
this.logLevel = config.logLevel ?? LogLevelType.Warning;
|
|
12
17
|
this.logger = config.logger ?? new ConsoleLogger();
|
|
18
|
+
this.reportingLogger = reportingLogger;
|
|
13
19
|
}
|
|
14
20
|
|
|
15
21
|
public verbose(msg: string): void {
|
|
@@ -22,21 +28,24 @@ export class Logger {
|
|
|
22
28
|
}
|
|
23
29
|
|
|
24
30
|
public warning(msg: string): void {
|
|
25
|
-
if(this.logLevel === LogLevelType.None)
|
|
31
|
+
if(this.logLevel === LogLevelType.None)
|
|
26
32
|
return;
|
|
27
33
|
|
|
28
|
-
if (this.logger.warning &&
|
|
34
|
+
if (this.logger.warning &&
|
|
29
35
|
(this.logLevel === LogLevelType.Verbose || this.logLevel === LogLevelType.Warning)) {
|
|
30
36
|
this.logger.warning(msg);
|
|
31
37
|
}
|
|
32
38
|
}
|
|
33
39
|
|
|
34
|
-
public error(msg: string): void {
|
|
35
|
-
if(this.logLevel === LogLevelType.None)
|
|
40
|
+
public error(msg: string, codeForReporting?: ErrorCodes): void {
|
|
41
|
+
if(this.logLevel === LogLevelType.None)
|
|
36
42
|
return;
|
|
37
43
|
|
|
38
44
|
if (this.logger.error) {
|
|
39
45
|
this.logger.error(msg);
|
|
46
|
+
if (codeForReporting) {
|
|
47
|
+
this.reportingLogger?.error(msg, codeForReporting);
|
|
48
|
+
}
|
|
40
49
|
}
|
|
41
50
|
}
|
|
42
51
|
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { ErrorCodes, LogRequestBody, WSDKErrorSeverity } from "./types";
|
|
2
|
+
import { FetchUploader, IFetchPayload } from "../uploaders";
|
|
3
|
+
import { IStore, SDKConfig } from "../store";
|
|
4
|
+
import { SDKInitConfig } from "../sdkRuntimeModels";
|
|
5
|
+
import Constants from "../constants";
|
|
6
|
+
|
|
7
|
+
// Header key constants
|
|
8
|
+
const HEADER_ACCEPT = 'Accept' as const;
|
|
9
|
+
const HEADER_CONTENT_TYPE = 'Content-Type' as const;
|
|
10
|
+
const HEADER_ROKT_LAUNCHER_VERSION = 'rokt-launcher-version' as const;
|
|
11
|
+
const HEADER_ROKT_LAUNCHER_INSTANCE_GUID = 'rokt-launcher-instance-guid' as const;
|
|
12
|
+
const HEADER_ROKT_WSDK_VERSION = 'rokt-wsdk-version' as const;
|
|
13
|
+
|
|
14
|
+
interface IReportingLoggerPayload extends IFetchPayload {
|
|
15
|
+
headers: IFetchPayload['headers'] & {
|
|
16
|
+
[HEADER_ROKT_LAUNCHER_INSTANCE_GUID]?: string;
|
|
17
|
+
[HEADER_ROKT_LAUNCHER_VERSION]: string;
|
|
18
|
+
[HEADER_ROKT_WSDK_VERSION]: string;
|
|
19
|
+
};
|
|
20
|
+
body: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class ReportingLogger {
|
|
24
|
+
private readonly isEnabled: boolean;
|
|
25
|
+
private readonly reporter: string = 'mp-wsdk';
|
|
26
|
+
private readonly rateLimiter: IRateLimiter;
|
|
27
|
+
private store: IStore | null;
|
|
28
|
+
private readonly loggingUrl: string;
|
|
29
|
+
private readonly errorUrl: string;
|
|
30
|
+
private readonly isLoggingEnabled: boolean;
|
|
31
|
+
|
|
32
|
+
constructor(
|
|
33
|
+
config: SDKConfig | SDKInitConfig | any,
|
|
34
|
+
private readonly sdkVersion: string,
|
|
35
|
+
store?: IStore,
|
|
36
|
+
private readonly launcherInstanceGuid?: string,
|
|
37
|
+
rateLimiter?: IRateLimiter,
|
|
38
|
+
) {
|
|
39
|
+
this.loggingUrl = `https://${config.loggingUrl || Constants.DefaultBaseUrls.loggingUrl}`;
|
|
40
|
+
this.errorUrl = `https://${config.errorUrl || Constants.DefaultBaseUrls.errorUrl}`;
|
|
41
|
+
this.isLoggingEnabled = config.isLoggingEnabled || false;
|
|
42
|
+
this.store = store ?? null;
|
|
43
|
+
this.isEnabled = this.isReportingEnabled();
|
|
44
|
+
this.rateLimiter = rateLimiter ?? new RateLimiter();
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
public setStore(store: IStore): void {
|
|
48
|
+
this.store = store;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
public info(msg: string, code?: ErrorCodes) {
|
|
52
|
+
this.sendLog(WSDKErrorSeverity.INFO, msg, code);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public error(msg: string, code?: ErrorCodes, stackTrace?: string) {
|
|
56
|
+
this.sendError(WSDKErrorSeverity.ERROR, msg, code, stackTrace);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
public warning(msg: string, code?: ErrorCodes) {
|
|
60
|
+
this.sendError(WSDKErrorSeverity.WARNING, msg, code);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
private sendToServer(url: string, severity: WSDKErrorSeverity, msg: string, code?: ErrorCodes, stackTrace?: string): void {
|
|
64
|
+
if (!this.canSendLog(severity))
|
|
65
|
+
return;
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const logRequest = this.buildLogRequest(severity, msg, code, stackTrace);
|
|
69
|
+
const uploader = new FetchUploader(url);
|
|
70
|
+
const payload: IReportingLoggerPayload = {
|
|
71
|
+
method: 'POST',
|
|
72
|
+
headers: this.getHeaders(),
|
|
73
|
+
body: JSON.stringify(logRequest),
|
|
74
|
+
};
|
|
75
|
+
uploader.upload(payload).catch((error) => {
|
|
76
|
+
console.error('ReportingLogger: Failed to send log', error);
|
|
77
|
+
});
|
|
78
|
+
} catch (error) {
|
|
79
|
+
console.error('ReportingLogger: Failed to send log', error);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
private sendLog(severity: WSDKErrorSeverity, msg: string, code?: ErrorCodes, stackTrace?: string): void {
|
|
84
|
+
this.sendToServer(this.loggingUrl, severity, msg, code, stackTrace);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private sendError(severity: WSDKErrorSeverity, msg: string, code?: ErrorCodes, stackTrace?: string): void {
|
|
88
|
+
this.sendToServer(this.errorUrl, severity, msg, code, stackTrace);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
private buildLogRequest(severity: WSDKErrorSeverity, msg: string, code?: ErrorCodes, stackTrace?: string): LogRequestBody {
|
|
92
|
+
return {
|
|
93
|
+
additionalInformation: {
|
|
94
|
+
message: msg,
|
|
95
|
+
version: this.getVersion(),
|
|
96
|
+
},
|
|
97
|
+
severity: severity,
|
|
98
|
+
code: code ?? ErrorCodes.UNKNOWN_ERROR,
|
|
99
|
+
url: this.getUrl(),
|
|
100
|
+
deviceInfo: this.getUserAgent(),
|
|
101
|
+
stackTrace: stackTrace,
|
|
102
|
+
reporter: this.reporter,
|
|
103
|
+
// Integration will be set to integrationName once the kit connects via RoktManager.attachKit()
|
|
104
|
+
integration: this.store?.getIntegrationName() ?? 'mp-wsdk'
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
private getVersion(): string {
|
|
109
|
+
return this.store?.getIntegrationName?.() ?? `mParticle_wsdkv_${this.sdkVersion}`;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private isReportingEnabled(): boolean {
|
|
113
|
+
return this.isDebugModeEnabled() ||
|
|
114
|
+
(this.isRoktDomainPresent() && this.isFeatureFlagEnabled());
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private isRoktDomainPresent(): boolean {
|
|
118
|
+
return typeof window !== 'undefined' && Boolean(window['ROKT_DOMAIN']);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
private isFeatureFlagEnabled = (): boolean => this.isLoggingEnabled;
|
|
122
|
+
|
|
123
|
+
private isDebugModeEnabled(): boolean {
|
|
124
|
+
return (
|
|
125
|
+
typeof window !== 'undefined' &&
|
|
126
|
+
(window.
|
|
127
|
+
location?.
|
|
128
|
+
search?.
|
|
129
|
+
toLowerCase()?.
|
|
130
|
+
includes('mp_enable_logging=true') ?? false)
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
private canSendLog(severity: WSDKErrorSeverity): boolean {
|
|
135
|
+
return this.isEnabled && !this.isRateLimited(severity);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
private isRateLimited(severity: WSDKErrorSeverity): boolean {
|
|
139
|
+
return this.rateLimiter.incrementAndCheck(severity);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
private getUrl(): string | undefined {
|
|
143
|
+
return typeof window !== 'undefined' ? window.location?.href : undefined;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private getUserAgent(): string | undefined {
|
|
147
|
+
return typeof window !== 'undefined' ? window.navigator?.userAgent : undefined;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
private getHeaders(): IReportingLoggerPayload['headers'] {
|
|
151
|
+
const headers: IReportingLoggerPayload['headers'] = {
|
|
152
|
+
[HEADER_ACCEPT]: 'text/plain;charset=UTF-8',
|
|
153
|
+
[HEADER_CONTENT_TYPE]: 'application/json',
|
|
154
|
+
[HEADER_ROKT_LAUNCHER_VERSION]: this.getVersion(),
|
|
155
|
+
[HEADER_ROKT_WSDK_VERSION]: 'joint',
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
if (this.launcherInstanceGuid) {
|
|
159
|
+
headers[HEADER_ROKT_LAUNCHER_INSTANCE_GUID] = this.launcherInstanceGuid;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const accountId = this.store?.getRoktAccountId?.();
|
|
163
|
+
if (accountId) {
|
|
164
|
+
headers['rokt-account-id'] = accountId;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return headers;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export interface IRateLimiter {
|
|
172
|
+
incrementAndCheck(severity: WSDKErrorSeverity): boolean;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export class RateLimiter implements IRateLimiter {
|
|
176
|
+
private readonly rateLimits: Map<WSDKErrorSeverity, number> = new Map([
|
|
177
|
+
[WSDKErrorSeverity.ERROR, 10],
|
|
178
|
+
[WSDKErrorSeverity.WARNING, 10],
|
|
179
|
+
[WSDKErrorSeverity.INFO, 10],
|
|
180
|
+
]);
|
|
181
|
+
private logCount: Map<WSDKErrorSeverity, number> = new Map();
|
|
182
|
+
|
|
183
|
+
public incrementAndCheck(severity: WSDKErrorSeverity): boolean {
|
|
184
|
+
const count = this.logCount.get(severity) || 0;
|
|
185
|
+
const limit = this.rateLimits.get(severity) || 10;
|
|
186
|
+
|
|
187
|
+
const newCount = count + 1;
|
|
188
|
+
this.logCount.set(severity, newCount);
|
|
189
|
+
|
|
190
|
+
return newCount > limit;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { valueof } from '../utils';
|
|
2
|
+
|
|
3
|
+
export const ErrorCodes = {
|
|
4
|
+
UNKNOWN_ERROR: 'UNKNOWN_ERROR',
|
|
5
|
+
UNHANDLED_EXCEPTION: 'UNHANDLED_EXCEPTION',
|
|
6
|
+
IDENTITY_REQUEST: 'IDENTITY_REQUEST',
|
|
7
|
+
} as const;
|
|
8
|
+
|
|
9
|
+
export type ErrorCodes = valueof<typeof ErrorCodes>;
|
|
10
|
+
|
|
11
|
+
export type ErrorCode = ErrorCodes | string;
|
|
12
|
+
|
|
13
|
+
export const WSDKErrorSeverity = {
|
|
14
|
+
ERROR: 'ERROR',
|
|
15
|
+
INFO: 'INFO',
|
|
16
|
+
WARNING: 'WARNING',
|
|
17
|
+
} as const;
|
|
18
|
+
|
|
19
|
+
export type WSDKErrorSeverity = (typeof WSDKErrorSeverity)[keyof typeof WSDKErrorSeverity];
|
|
20
|
+
|
|
21
|
+
export type ErrorsRequestBody = {
|
|
22
|
+
additionalInformation?: Record<string, string>;
|
|
23
|
+
code: ErrorCode;
|
|
24
|
+
severity: WSDKErrorSeverity;
|
|
25
|
+
stackTrace?: string;
|
|
26
|
+
deviceInfo?: string;
|
|
27
|
+
integration?: string;
|
|
28
|
+
reporter?: string;
|
|
29
|
+
url?: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type LogRequestBody = ErrorsRequestBody;
|
package/src/mp-instance.ts
CHANGED
|
@@ -52,6 +52,7 @@ import ForegroundTimer from './foregroundTimeTracker';
|
|
|
52
52
|
import RoktManager, { IRoktOptions } from './roktManager';
|
|
53
53
|
import filteredMparticleUser from './filteredMparticleUser';
|
|
54
54
|
import CookieConsentManager, { ICookieConsentManager } from './cookieConsentManager';
|
|
55
|
+
import { ReportingLogger } from './logging/reportingLogger';
|
|
55
56
|
|
|
56
57
|
export interface IErrorLogMessage {
|
|
57
58
|
message?: string;
|
|
@@ -84,15 +85,18 @@ export interface IMParticleWebSDKInstance extends MParticleWebSDK {
|
|
|
84
85
|
_NativeSdkHelpers: INativeSdkHelpers;
|
|
85
86
|
_Persistence: IPersistence;
|
|
86
87
|
_CookieConsentManager: ICookieConsentManager;
|
|
88
|
+
_ReportingLogger: ReportingLogger;
|
|
87
89
|
_RoktManager: RoktManager;
|
|
88
90
|
_SessionManager: ISessionManager;
|
|
89
91
|
_ServerModel: IServerModel;
|
|
90
92
|
_Store: IStore;
|
|
91
93
|
_instanceName: string;
|
|
92
94
|
_preInit: IPreInit;
|
|
93
|
-
_timeOnSiteTimer: ForegroundTimer;
|
|
95
|
+
_timeOnSiteTimer: ForegroundTimer;
|
|
94
96
|
setLauncherInstanceGuid: () => void;
|
|
97
|
+
getLauncherInstanceGuid: () => string;
|
|
95
98
|
captureTiming(metricName: string);
|
|
99
|
+
processQueueOnIdentityFailure?: () => void;
|
|
96
100
|
}
|
|
97
101
|
|
|
98
102
|
const { Messages, HTTPCodes, FeatureFlags, CaptureIntegrationSpecificIdsV2Modes } = Constants;
|
|
@@ -132,7 +136,26 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan
|
|
|
132
136
|
integrationDelays: {},
|
|
133
137
|
forwarderConstructors: [],
|
|
134
138
|
};
|
|
139
|
+
|
|
135
140
|
this._RoktManager = new RoktManager();
|
|
141
|
+
|
|
142
|
+
this._RoktManager.setOnReadyCallback(() => {
|
|
143
|
+
self.processQueueOnIdentityFailure();
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Processes message and ready queue when identity requests fails but Rokt is ready.
|
|
148
|
+
*/
|
|
149
|
+
this.processQueueOnIdentityFailure = function() {
|
|
150
|
+
if (self._Store?.isInitialized) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (self._Store?.identityCallFailed && self._RoktManager?.isReady()) {
|
|
155
|
+
self._RoktManager.processMessageQueue();
|
|
156
|
+
self._preInit.readyQueue = processReadyQueue(self._preInit.readyQueue);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
136
159
|
|
|
137
160
|
// required for forwarders once they reference the mparticle instance
|
|
138
161
|
this.IdentityType = IdentityType;
|
|
@@ -225,12 +248,14 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan
|
|
|
225
248
|
}
|
|
226
249
|
};
|
|
227
250
|
|
|
228
|
-
this._resetForTests = function(config, keepPersistence, instance) {
|
|
251
|
+
this._resetForTests = function(config, keepPersistence, instance, reportingLogger?: ReportingLogger) {
|
|
229
252
|
if (instance._Store) {
|
|
230
253
|
delete instance._Store;
|
|
231
254
|
}
|
|
232
|
-
instance.Logger = new Logger(config);
|
|
255
|
+
instance.Logger = new Logger(config, reportingLogger);
|
|
233
256
|
instance._Store = new Store(config, instance);
|
|
257
|
+
// Update ReportingLogger with the new Store reference to avoid stale data
|
|
258
|
+
reportingLogger?.setStore(instance._Store);
|
|
234
259
|
instance._Store.isLocalStorageAvailable = instance._Persistence.determineLocalStorageAvailability(
|
|
235
260
|
window.localStorage
|
|
236
261
|
);
|
|
@@ -249,12 +274,18 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan
|
|
|
249
274
|
};
|
|
250
275
|
};
|
|
251
276
|
/**
|
|
252
|
-
*
|
|
277
|
+
* Executes callback when the SDK is ready, or Rokt is ready but identify requests fail due to server errors.
|
|
278
|
+
* This ensures Rokt methods like selectPlacements continue to work during backend outages.
|
|
253
279
|
* @method ready
|
|
254
|
-
* @param {Function}
|
|
280
|
+
* @param {Function} f Callback to execute
|
|
255
281
|
*/
|
|
256
282
|
this.ready = function(f) {
|
|
257
|
-
|
|
283
|
+
const shouldExecute = isFunction(f) && (
|
|
284
|
+
self._Store?.isInitialized ||
|
|
285
|
+
(self._Store?.identityCallFailed && self._RoktManager.isReady())
|
|
286
|
+
);
|
|
287
|
+
|
|
288
|
+
if (shouldExecute) {
|
|
258
289
|
f();
|
|
259
290
|
} else {
|
|
260
291
|
self._preInit.readyQueue.push(f);
|
|
@@ -1346,7 +1377,7 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan
|
|
|
1346
1377
|
};
|
|
1347
1378
|
}
|
|
1348
1379
|
};
|
|
1349
|
-
|
|
1380
|
+
|
|
1350
1381
|
const launcherInstanceGuidKey = Constants.Rokt.LauncherInstanceGuidKey;
|
|
1351
1382
|
this.setLauncherInstanceGuid = function() {
|
|
1352
1383
|
if (!window[launcherInstanceGuidKey]
|
|
@@ -1355,6 +1386,10 @@ export default function mParticleInstance(this: IMParticleWebSDKInstance, instan
|
|
|
1355
1386
|
}
|
|
1356
1387
|
};
|
|
1357
1388
|
|
|
1389
|
+
this.getLauncherInstanceGuid = function() {
|
|
1390
|
+
return window[launcherInstanceGuidKey];
|
|
1391
|
+
};
|
|
1392
|
+
|
|
1358
1393
|
this.captureTiming = function(metricsName) {
|
|
1359
1394
|
if (typeof window !== 'undefined' && window.performance?.mark) {
|
|
1360
1395
|
window.performance.mark(metricsName);
|
|
@@ -1420,6 +1455,8 @@ function completeSDKInitialization(apiKey, config, mpInstance) {
|
|
|
1420
1455
|
// Configure Rokt Manager with user and filtered user
|
|
1421
1456
|
const roktConfig: IKitConfigs = parseConfig(config, 'Rokt', 181);
|
|
1422
1457
|
if (roktConfig) {
|
|
1458
|
+
const accountId = roktConfig.settings?.accountId;
|
|
1459
|
+
mpInstance._Store.setRoktAccountId(accountId);
|
|
1423
1460
|
const { userAttributeFilters } = roktConfig;
|
|
1424
1461
|
const roktFilteredUser = filteredMparticleUser(
|
|
1425
1462
|
currentUserMPID,
|
|
@@ -1553,9 +1590,16 @@ function createIdentityCache(mpInstance) {
|
|
|
1553
1590
|
}
|
|
1554
1591
|
|
|
1555
1592
|
function runPreConfigFetchInitialization(mpInstance, apiKey, config) {
|
|
1556
|
-
mpInstance.
|
|
1593
|
+
mpInstance._ReportingLogger = new ReportingLogger(
|
|
1594
|
+
config,
|
|
1595
|
+
Constants.sdkVersion,
|
|
1596
|
+
undefined,
|
|
1597
|
+
mpInstance.getLauncherInstanceGuid(),
|
|
1598
|
+
);
|
|
1599
|
+
mpInstance.Logger = new Logger(config, mpInstance._ReportingLogger);
|
|
1557
1600
|
mpInstance._Store = new Store(config, mpInstance, apiKey);
|
|
1558
1601
|
window.mParticle.Store = mpInstance._Store;
|
|
1602
|
+
mpInstance._ReportingLogger.setStore(mpInstance._Store);
|
|
1559
1603
|
mpInstance.Logger.verbose(StartingInitialization);
|
|
1560
1604
|
|
|
1561
1605
|
// Initialize CookieConsentManager with privacy flags from launcherOptions
|
|
@@ -1620,9 +1664,12 @@ function processIdentityCallback(
|
|
|
1620
1664
|
}
|
|
1621
1665
|
|
|
1622
1666
|
function queueIfNotInitialized(func, self) {
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1667
|
+
// Core SDK methods must wait for Store initialization
|
|
1668
|
+
if (!self._Store?.isInitialized) {
|
|
1669
|
+
self._preInit.readyQueue.push(function() {
|
|
1670
|
+
if (self._Store?.isInitialized) {
|
|
1671
|
+
func();
|
|
1672
|
+
}
|
|
1626
1673
|
});
|
|
1627
1674
|
return true;
|
|
1628
1675
|
}
|
package/src/roktManager.ts
CHANGED
|
@@ -59,6 +59,12 @@ export interface RoktKitFilterSettings {
|
|
|
59
59
|
filteredUser?: IMParticleUser | null;
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
export interface IRoktKitSettings {
|
|
63
|
+
accountId?: string;
|
|
64
|
+
placementAttributesMapping?: string;
|
|
65
|
+
hashedEmailUserIdentityType?: string;
|
|
66
|
+
}
|
|
67
|
+
|
|
62
68
|
export interface IRoktKit {
|
|
63
69
|
filters: RoktKitFilterSettings;
|
|
64
70
|
filteredUser: IMParticleUser | null;
|
|
@@ -69,6 +75,8 @@ export interface IRoktKit {
|
|
|
69
75
|
setExtensionData<T>(extensionData: IRoktPartnerExtensionData<T>): void;
|
|
70
76
|
use: <T>(name: string) => Promise<T>;
|
|
71
77
|
launcherOptions?: Dictionary<any>;
|
|
78
|
+
settings?: IRoktKitSettings;
|
|
79
|
+
integrationName?: string;
|
|
72
80
|
}
|
|
73
81
|
|
|
74
82
|
export interface IRoktOptions {
|
|
@@ -102,7 +110,16 @@ export default class RoktManager {
|
|
|
102
110
|
private domain?: string;
|
|
103
111
|
private mappedEmailShaIdentityType?: string | null;
|
|
104
112
|
private captureTiming?: (metricsName: string) => void;
|
|
113
|
+
private onReadyCallback: (() => void) | null = null;
|
|
105
114
|
private initialized: boolean = false;
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Sets a callback to be invoked when RoktManager becomes ready
|
|
118
|
+
*/
|
|
119
|
+
public setOnReadyCallback(callback: () => void): void {
|
|
120
|
+
this.onReadyCallback = callback;
|
|
121
|
+
}
|
|
122
|
+
|
|
106
123
|
/**
|
|
107
124
|
* Initializes the RoktManager with configuration settings and user data.
|
|
108
125
|
*
|
|
@@ -133,6 +150,8 @@ export default class RoktManager {
|
|
|
133
150
|
this.logger = logger;
|
|
134
151
|
this.captureTiming = captureTiming;
|
|
135
152
|
|
|
153
|
+
this.captureTiming?.(PerformanceMarkType.JointSdkRoktKitInit);
|
|
154
|
+
|
|
136
155
|
this.filters = {
|
|
137
156
|
userAttributeFilters,
|
|
138
157
|
filterUserAttributes: KitFilterHelper.filterUserAttributes,
|
|
@@ -170,7 +189,22 @@ export default class RoktManager {
|
|
|
170
189
|
|
|
171
190
|
public attachKit(kit: IRoktKit): void {
|
|
172
191
|
this.kit = kit;
|
|
192
|
+
|
|
193
|
+
if (kit.settings?.accountId) {
|
|
194
|
+
this.store.setRoktAccountId(kit.settings.accountId);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
if (kit.integrationName) {
|
|
198
|
+
this.store?.setIntegrationName(kit.integrationName);
|
|
199
|
+
}
|
|
200
|
+
|
|
173
201
|
this.processMessageQueue();
|
|
202
|
+
|
|
203
|
+
try {
|
|
204
|
+
this.onReadyCallback?.();
|
|
205
|
+
} catch (e) {
|
|
206
|
+
this.logger?.error('RoktManager: Error in onReadyCallback: ' + e);
|
|
207
|
+
}
|
|
174
208
|
}
|
|
175
209
|
|
|
176
210
|
/**
|
|
@@ -189,9 +223,7 @@ export default class RoktManager {
|
|
|
189
223
|
* });
|
|
190
224
|
*/
|
|
191
225
|
public async selectPlacements(options: IRoktSelectPlacementsOptions): Promise<IRoktSelection> {
|
|
192
|
-
|
|
193
|
-
this.captureTiming(PerformanceMarkType.JointSdkSelectPlacements);
|
|
194
|
-
}
|
|
226
|
+
this.captureTiming?.(PerformanceMarkType.JointSdkSelectPlacements);
|
|
195
227
|
|
|
196
228
|
// Queue if kit isn't ready OR if identity is in flight
|
|
197
229
|
if (!this.isReady() || this.store?.identityCallInFlight) {
|
|
@@ -406,7 +438,7 @@ export default class RoktManager {
|
|
|
406
438
|
this.store.setLocalSessionAttribute(key, value);
|
|
407
439
|
}
|
|
408
440
|
|
|
409
|
-
|
|
441
|
+
public isReady(): boolean {
|
|
410
442
|
// The Rokt Manager is ready when a kit is attached and has a launcher
|
|
411
443
|
return Boolean(this.kit && this.kit.launcher);
|
|
412
444
|
}
|
|
@@ -453,7 +485,7 @@ export default class RoktManager {
|
|
|
453
485
|
}
|
|
454
486
|
}
|
|
455
487
|
|
|
456
|
-
|
|
488
|
+
public processMessageQueue(): void {
|
|
457
489
|
if (!this.isReady() || this.messageQueue.size === 0) {
|
|
458
490
|
return;
|
|
459
491
|
}
|
|
@@ -573,4 +605,4 @@ export default class RoktManager {
|
|
|
573
605
|
|
|
574
606
|
return false; // Values are the same
|
|
575
607
|
}
|
|
576
|
-
}
|
|
608
|
+
}
|