@base44-preview/sdk 0.8.48-pr.280.dac0f98 → 0.8.48-pr.281.97e1467
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/client.js +7 -50
- package/dist/client.types.d.ts +3 -13
- package/dist/index.d.ts +0 -3
- package/dist/index.js +0 -1
- package/dist/modules/analytics.d.ts +4 -29
- package/dist/modules/analytics.js +82 -107
- package/dist/modules/auth.js +3 -34
- package/dist/modules/auth.types.d.ts +0 -13
- package/dist/utils/fetch-with-auth.js +0 -6
- package/package.json +1 -1
- package/dist/modules/experiment-exposures.d.ts +0 -19
- package/dist/modules/experiment-exposures.js +0 -65
- package/dist/modules/experiments-config.types.d.ts +0 -39
- package/dist/modules/experiments-config.types.js +0 -1
- package/dist/modules/experiments-context.d.ts +0 -10
- package/dist/modules/experiments-context.js +0 -44
- package/dist/modules/experiments-evaluator.d.ts +0 -11
- package/dist/modules/experiments-evaluator.js +0 -45
- package/dist/modules/experiments-runtime.types.d.ts +0 -19
- package/dist/modules/experiments-runtime.types.js +0 -7
- package/dist/modules/experiments.d.ts +0 -16
- package/dist/modules/experiments.js +0 -134
- package/dist/modules/experiments.types.d.ts +0 -106
- package/dist/modules/experiments.types.js +0 -1
package/dist/client.js
CHANGED
|
@@ -14,9 +14,6 @@ import { createAppModule } from "./modules/app.js";
|
|
|
14
14
|
import { createUsersModule } from "./modules/users.js";
|
|
15
15
|
import { RoomsSocket } from "./utils/socket-utils.js";
|
|
16
16
|
import { createAnalyticsModule } from "./modules/analytics.js";
|
|
17
|
-
import { createExperimentsModule } from "./modules/experiments.js";
|
|
18
|
-
import { createExposureTracker } from "./modules/experiment-exposures.js";
|
|
19
|
-
import { EXPERIMENTS_CONTEXT_HEADER, getBrowserExperimentsContext, readExperimentsContext } from "./modules/experiments-context.js";
|
|
20
17
|
import { createActorsModule, resolveActorsHost, } from "./modules/actors.js";
|
|
21
18
|
/**
|
|
22
19
|
* Creates a Base44 client.
|
|
@@ -56,11 +53,10 @@ import { createActorsModule, resolveActorsHost, } from "./modules/actors.js";
|
|
|
56
53
|
* ```
|
|
57
54
|
*/
|
|
58
55
|
export function createClient(config) {
|
|
59
|
-
var _a, _b, _c, _d
|
|
56
|
+
var _a, _b, _c, _d;
|
|
60
57
|
const { serverUrl = "https://base44.app", appId, analytics, token, serviceToken, requiresAuth = false, appBaseUrl, options, functionsVersion, headers: optionalHeaders, } = config;
|
|
61
58
|
// Normalize appBaseUrl to always be a string (empty if not provided or invalid)
|
|
62
59
|
const normalizedAppBaseUrl = typeof appBaseUrl === "string" ? appBaseUrl : "";
|
|
63
|
-
const experimentsContext = (_a = config.experiments) !== null && _a !== void 0 ? _a : getBrowserExperimentsContext(appId);
|
|
64
60
|
const socketConfig = {
|
|
65
61
|
serverUrl,
|
|
66
62
|
mountPath: "/ws-user-apps/socket.io/",
|
|
@@ -77,14 +73,9 @@ export function createClient(config) {
|
|
|
77
73
|
}
|
|
78
74
|
return socket;
|
|
79
75
|
};
|
|
80
|
-
const { [EXPERIMENTS_CONTEXT_HEADER]: inheritedExperimentsContext, ...requestHeaders } = optionalHeaders !== null && optionalHeaders !== void 0 ? optionalHeaders : {};
|
|
81
76
|
const headers = {
|
|
82
|
-
...
|
|
77
|
+
...optionalHeaders,
|
|
83
78
|
"X-App-Id": String(appId),
|
|
84
|
-
...(experimentsContext ? {
|
|
85
|
-
"Base44-Visitor-Id": experimentsContext.identity.visitorId,
|
|
86
|
-
"Base44-Experiment-Preview": JSON.stringify((_b = experimentsContext.preview) !== null && _b !== void 0 ? _b : {}),
|
|
87
|
-
} : {}),
|
|
88
79
|
};
|
|
89
80
|
const functionHeaders = functionsVersion
|
|
90
81
|
? {
|
|
@@ -130,24 +121,10 @@ export function createClient(config) {
|
|
|
130
121
|
baseURL: `${serverUrl}/api`,
|
|
131
122
|
headers,
|
|
132
123
|
});
|
|
133
|
-
const exposureTracker = createExposureTracker({
|
|
134
|
-
axiosClient,
|
|
135
|
-
appId,
|
|
136
|
-
enabled: (_c = analytics === null || analytics === void 0 ? void 0 : analytics.enabled) !== null && _c !== void 0 ? _c : true,
|
|
137
|
-
source: typeof window === "undefined" ? "backend" : "browser",
|
|
138
|
-
pageUrl: experimentsContext === null || experimentsContext === void 0 ? void 0 : experimentsContext.pageUrl,
|
|
139
|
-
});
|
|
140
|
-
const experiments = createExperimentsModule({
|
|
141
|
-
getAuth: () => userAuthModule,
|
|
142
|
-
trackExposure: exposureTracker.track,
|
|
143
|
-
flushExposures: exposureTracker.flush,
|
|
144
|
-
context: experimentsContext,
|
|
145
|
-
});
|
|
146
124
|
const userAuthModule = createAuthModule(axiosClient, functionsAxiosClient, appId, {
|
|
147
125
|
appBaseUrl: normalizedAppBaseUrl,
|
|
148
126
|
serverUrl,
|
|
149
127
|
token,
|
|
150
|
-
onAuthStateChange: experiments.onAuthStateChange,
|
|
151
128
|
});
|
|
152
129
|
// Apply the access token before any module that may issue authenticated
|
|
153
130
|
// requests during construction (notably analytics, which fires an init
|
|
@@ -159,19 +136,11 @@ export function createClient(config) {
|
|
|
159
136
|
userAuthModule.setToken(accessToken);
|
|
160
137
|
}
|
|
161
138
|
}
|
|
162
|
-
if (experimentsContext) {
|
|
163
|
-
const { userId, status } = experimentsContext.identity;
|
|
164
|
-
// The document's cookie identity may differ from this client's localStorage token.
|
|
165
|
-
const needsClientIdentity = typeof window !== "undefined" && userAuthModule.hasToken() &&
|
|
166
|
-
experimentsContext.config.experiments.some((experiment) => experiment.assign_by === "user");
|
|
167
|
-
experiments.onAuthStateChange(status === "pending" || needsClientIdentity ? { status: "pending" } :
|
|
168
|
-
userId ? { status: "authenticated", userId } : { status: "anonymous" });
|
|
169
|
-
}
|
|
170
139
|
const actorsModule = createActorsModule({
|
|
171
140
|
appId,
|
|
172
141
|
// serverUrl is often relative/empty (same-origin app); the proxy-fallback
|
|
173
142
|
// URL needs an absolute host, so fall back to the page origin.
|
|
174
|
-
host: resolveActorsHost(serverUrl, typeof window !== "undefined" ? (
|
|
143
|
+
host: resolveActorsHost(serverUrl, typeof window !== "undefined" ? (_a = window.location) === null || _a === void 0 ? void 0 : _a.origin : undefined),
|
|
175
144
|
functionsVersion,
|
|
176
145
|
getAuthToken: () => token || getAccessToken(),
|
|
177
146
|
mintConnectionToken: async (actorName, room, connectionId) => {
|
|
@@ -199,7 +168,6 @@ export function createClient(config) {
|
|
|
199
168
|
integrations: createIntegrationsModule(axiosClient, appId),
|
|
200
169
|
connectors: createUserConnectorsModule(axiosClient, appId),
|
|
201
170
|
auth: userAuthModule,
|
|
202
|
-
experiments: experiments.module,
|
|
203
171
|
functions: createFunctionsModule(functionsAxiosClient, appId, {
|
|
204
172
|
getAuthHeaders: () => {
|
|
205
173
|
const headers = {};
|
|
@@ -210,7 +178,7 @@ export function createClient(config) {
|
|
|
210
178
|
}
|
|
211
179
|
return headers;
|
|
212
180
|
},
|
|
213
|
-
baseURL: (
|
|
181
|
+
baseURL: (_b = functionsAxiosClient.defaults) === null || _b === void 0 ? void 0 : _b.baseURL,
|
|
214
182
|
}),
|
|
215
183
|
agents: createAgentsModule({
|
|
216
184
|
axios: axiosClient,
|
|
@@ -228,14 +196,11 @@ export function createClient(config) {
|
|
|
228
196
|
serverUrl,
|
|
229
197
|
appId,
|
|
230
198
|
userAuthModule,
|
|
231
|
-
enabled: (
|
|
232
|
-
getVisitorId: experiments.visitorId,
|
|
233
|
-
experimentsContext,
|
|
199
|
+
enabled: (_c = analytics === null || analytics === void 0 ? void 0 : analytics.enabled) !== null && _c !== void 0 ? _c : true,
|
|
234
200
|
}),
|
|
235
201
|
actors: actorsModule.module,
|
|
236
202
|
cleanup: () => {
|
|
237
203
|
userModules.analytics.cleanup();
|
|
238
|
-
experiments.cleanup();
|
|
239
204
|
actorsModule.closeAll();
|
|
240
205
|
if (socket) {
|
|
241
206
|
socket.disconnect();
|
|
@@ -260,7 +225,7 @@ export function createClient(config) {
|
|
|
260
225
|
}
|
|
261
226
|
return headers;
|
|
262
227
|
},
|
|
263
|
-
baseURL: (
|
|
228
|
+
baseURL: (_d = serviceRoleFunctionsAxiosClient.defaults) === null || _d === void 0 ? void 0 : _d.baseURL,
|
|
264
229
|
}),
|
|
265
230
|
agents: createAgentsModule({
|
|
266
231
|
axios: serviceRoleAxiosClient,
|
|
@@ -303,10 +268,7 @@ export function createClient(config) {
|
|
|
303
268
|
appId: String(appId),
|
|
304
269
|
serverUrl,
|
|
305
270
|
functionsVersion,
|
|
306
|
-
platformHeaders:
|
|
307
|
-
...headers,
|
|
308
|
-
...(inheritedExperimentsContext ? { [EXPERIMENTS_CONTEXT_HEADER]: inheritedExperimentsContext } : {}),
|
|
309
|
-
},
|
|
271
|
+
platformHeaders: optionalHeaders,
|
|
310
272
|
}),
|
|
311
273
|
/**
|
|
312
274
|
* Sets a new authentication token for all subsequent requests.
|
|
@@ -458,10 +420,6 @@ export function createClientFromRequest(request) {
|
|
|
458
420
|
}
|
|
459
421
|
// Prepare additional headers to propagate
|
|
460
422
|
const additionalHeaders = {};
|
|
461
|
-
const encodedExperiments = request.headers.get(EXPERIMENTS_CONTEXT_HEADER);
|
|
462
|
-
const experimentsContext = readExperimentsContext(encodedExperiments, appId);
|
|
463
|
-
if (experimentsContext && encodedExperiments)
|
|
464
|
-
additionalHeaders[EXPERIMENTS_CONTEXT_HEADER] = encodedExperiments;
|
|
465
423
|
if (stateHeader) {
|
|
466
424
|
additionalHeaders["Base44-State"] = stateHeader;
|
|
467
425
|
}
|
|
@@ -482,6 +440,5 @@ export function createClientFromRequest(request) {
|
|
|
482
440
|
serviceToken: serviceRoleToken,
|
|
483
441
|
functionsVersion: functionsVersion !== null && functionsVersion !== void 0 ? functionsVersion : undefined,
|
|
484
442
|
headers: additionalHeaders,
|
|
485
|
-
experiments: experimentsContext ? { ...experimentsContext, pageUrl: request.url ? new URL(request.url).pathname : "/" } : undefined,
|
|
486
443
|
});
|
|
487
444
|
}
|
package/dist/client.types.d.ts
CHANGED
|
@@ -9,8 +9,6 @@ import type { AiGatewayModule } from "./modules/ai-gateway.types.js";
|
|
|
9
9
|
import type { AppLogsModule } from "./modules/app-logs.types.js";
|
|
10
10
|
import type { AppModule } from "./modules/app.types.js";
|
|
11
11
|
import type { AnalyticsModule } from "./modules/analytics.types.js";
|
|
12
|
-
import type { ExperimentsModule } from "./modules/experiments.types.js";
|
|
13
|
-
import type { ExperimentsContext } from "./modules/experiments-config.types.js";
|
|
14
12
|
import type { ActorsModule } from "./modules/actors.types.js";
|
|
15
13
|
import type { FetchWithAuthInit } from "./utils/fetch-with-auth.js";
|
|
16
14
|
/**
|
|
@@ -41,9 +39,9 @@ export interface CreateClientAnalyticsConfig {
|
|
|
41
39
|
/**
|
|
42
40
|
* Whether app analytics is enabled for this client.
|
|
43
41
|
*
|
|
44
|
-
* When disabled, automatic analytics
|
|
45
|
-
*
|
|
46
|
-
*
|
|
42
|
+
* When disabled, automatic analytics and calls to `analytics.track()` are
|
|
43
|
+
* no-ops. The SDK does not create an analytics session identifier, start
|
|
44
|
+
* heartbeat timers, or send analytics requests.
|
|
47
45
|
*
|
|
48
46
|
* @defaultValue `true`
|
|
49
47
|
*/
|
|
@@ -81,12 +79,6 @@ export interface CreateClientConfig {
|
|
|
81
79
|
* Omit this option to preserve the default analytics behavior.
|
|
82
80
|
*/
|
|
83
81
|
analytics?: CreateClientAnalyticsConfig;
|
|
84
|
-
/**
|
|
85
|
-
* Platform-validated context for local flag evaluation. Request-scoped on servers.
|
|
86
|
-
* Automatically read from the platform bootstrap in browsers and trusted headers
|
|
87
|
-
* by createClientFromRequest(). Not an authorization credential.
|
|
88
|
-
*/
|
|
89
|
-
experiments?: ExperimentsContext;
|
|
90
82
|
/**
|
|
91
83
|
* User authentication token. Used to authenticate as a specific user.
|
|
92
84
|
*
|
|
@@ -142,8 +134,6 @@ export interface Base44Client {
|
|
|
142
134
|
connectors: UserConnectorsModule;
|
|
143
135
|
/** {@link EntitiesModule | Entities module} for CRUD operations on your data models. */
|
|
144
136
|
entities: EntitiesModule;
|
|
145
|
-
/** {@link ExperimentsModule | Experiments module} for local feature flags and exposures. */
|
|
146
|
-
experiments: ExperimentsModule;
|
|
147
137
|
/** {@link FunctionsModule | Functions module} for invoking custom backend functions. */
|
|
148
138
|
functions: FunctionsModule;
|
|
149
139
|
/** {@link IntegrationsModule | Integrations module} for calling pre-built integration endpoints. */
|
package/dist/index.d.ts
CHANGED
|
@@ -4,9 +4,6 @@ import { getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl } from
|
|
|
4
4
|
export { createClient, createClientFromRequest, Base44Error, getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl, };
|
|
5
5
|
export type { Base44Client, CreateClientAnalyticsConfig, CreateClientConfig, CreateClientOptions, Base44ErrorJSON, };
|
|
6
6
|
export * from "./types.js";
|
|
7
|
-
export { evaluateExperiments } from "./modules/experiments-evaluator.js";
|
|
8
|
-
export type { ExperimentsConfig, ExperimentsContext, ExperimentsIdentity } from "./modules/experiments-config.types.js";
|
|
9
|
-
export type { ExperimentsModule, ExperimentsSnapshot, } from "./modules/experiments.types.js";
|
|
10
7
|
export type { DeleteManyResult, DeleteResult, EntitiesModule, EntityFilterOperators, EntityFilterQuery, EntityFilterValue, EntityHandler, EntityRecord, EntityTypeRegistry, ImportResult, RealtimeEventType, RealtimeEvent, RealtimeCallback, SortField, UpdateManyResult, } from "./modules/entities.types.js";
|
|
11
8
|
export type { AuthModule, LoginResponse, RegisterParams, VerifyOtpParams, ChangePasswordParams, ResetPasswordParams, User, } from "./modules/auth.types.js";
|
|
12
9
|
export type { IntegrationsModule, IntegrationEndpointFunction, CoreIntegrations, InvokeLLMParams, GenerateImageParams, GenerateImageResult, UploadFileParams, UploadFileResult, SendEmailParams, SendEmailResult, ExtractDataFromUploadedFileParams, ExtractDataFromUploadedFileResult, UploadPrivateFileParams, UploadPrivateFileResult, CreateFileSignedUrlParams, CreateFileSignedUrlResult, } from "./modules/integrations.types.js";
|
package/dist/index.js
CHANGED
|
@@ -3,5 +3,4 @@ import { Base44Error } from "./utils/axios-client.js";
|
|
|
3
3
|
import { getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl, } from "./utils/auth-utils.js";
|
|
4
4
|
export { createClient, createClientFromRequest, Base44Error, getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl, };
|
|
5
5
|
export * from "./types.js";
|
|
6
|
-
export { evaluateExperiments } from "./modules/experiments-evaluator.js";
|
|
7
6
|
export { Actor } from "./actor.js";
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { AxiosInstance } from "axios";
|
|
2
|
-
import { TrackEventParams,
|
|
2
|
+
import { TrackEventParams, AnalyticsModuleOptions } from "./analytics.types";
|
|
3
3
|
import type { InternalAuthModule } from "./auth.types";
|
|
4
|
-
import type { ExperimentsContext } from "./experiments-config.types.js";
|
|
5
4
|
export declare const USER_HEARTBEAT_EVENT_NAME = "__user_heartbeat_event__";
|
|
6
5
|
export declare const ANALYTICS_INITIALIZATION_EVENT_NAME = "__initialization_event__";
|
|
7
6
|
export declare const ANALYTICS_SESSION_DURATION_EVENT_NAME = "__session_duration_event__";
|
|
@@ -13,22 +12,8 @@ export interface AnalyticsModuleArgs {
|
|
|
13
12
|
appId: string;
|
|
14
13
|
userAuthModule: InternalAuthModule;
|
|
15
14
|
enabled: boolean;
|
|
16
|
-
getVisitorId?: () => string | undefined;
|
|
17
|
-
experimentsContext?: ExperimentsContext;
|
|
18
15
|
}
|
|
19
|
-
|
|
20
|
-
export declare function isAnalyticsEnabled(enabled: boolean, state?: {
|
|
21
|
-
requestsQueue: TrackEventData[];
|
|
22
|
-
isProcessing: boolean;
|
|
23
|
-
isHeartBeatProcessing: boolean;
|
|
24
|
-
wasInitializationTracked: boolean;
|
|
25
|
-
sessionContext: SessionContext | null;
|
|
26
|
-
sessionContextPromise: Promise<SessionContext> | null;
|
|
27
|
-
sessionStartTime: string | null;
|
|
28
|
-
fallbackSessionId: string | null;
|
|
29
|
-
config: Required<AnalyticsModuleOptions>;
|
|
30
|
-
}): boolean;
|
|
31
|
-
export declare const createAnalyticsModule: ({ axiosClient, serverUrl, appId, userAuthModule, enabled, getVisitorId, experimentsContext, }: AnalyticsModuleArgs) => {
|
|
16
|
+
export declare const createAnalyticsModule: ({ axiosClient, serverUrl, appId, userAuthModule, enabled, }: AnalyticsModuleArgs) => {
|
|
32
17
|
track: (params: TrackEventParams) => void;
|
|
33
18
|
cleanup: () => void;
|
|
34
19
|
};
|
|
@@ -42,16 +27,6 @@ export declare const createAnalyticsModule: ({ axiosClient, serverUrl, appId, us
|
|
|
42
27
|
*
|
|
43
28
|
* @internal
|
|
44
29
|
*/
|
|
45
|
-
export declare function resetAnalyticsSessionContext(
|
|
30
|
+
export declare function resetAnalyticsSessionContext(): void;
|
|
46
31
|
export declare function getAnalyticsConfigFromUrlParams(): AnalyticsModuleOptions | undefined;
|
|
47
|
-
export declare function getAnalyticsSessionId(
|
|
48
|
-
requestsQueue: TrackEventData[];
|
|
49
|
-
isProcessing: boolean;
|
|
50
|
-
isHeartBeatProcessing: boolean;
|
|
51
|
-
wasInitializationTracked: boolean;
|
|
52
|
-
sessionContext: SessionContext | null;
|
|
53
|
-
sessionContextPromise: Promise<SessionContext> | null;
|
|
54
|
-
sessionStartTime: string | null;
|
|
55
|
-
fallbackSessionId: string | null;
|
|
56
|
-
config: Required<AnalyticsModuleOptions>;
|
|
57
|
-
}): string;
|
|
32
|
+
export declare function getAnalyticsSessionId(): string;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { getSharedInstance } from "../utils/sharedInstance.js";
|
|
2
2
|
import { generateUuid, isReactNative } from "../utils/common.js";
|
|
3
|
-
import { getExperimentsRuntime } from "./experiments-runtime.types.js";
|
|
4
3
|
export const USER_HEARTBEAT_EVENT_NAME = "__user_heartbeat_event__";
|
|
5
4
|
export const ANALYTICS_INITIALIZATION_EVENT_NAME = "__initialization_event__";
|
|
6
5
|
export const ANALYTICS_SESSION_DURATION_EVENT_NAME = "__session_duration_event__";
|
|
@@ -18,41 +17,31 @@ const defaultConfiguration = {
|
|
|
18
17
|
//// shared queue for analytics events ////
|
|
19
18
|
///////////////////////////////////////////////
|
|
20
19
|
const ANALYTICS_SHARED_STATE_NAME = "analytics";
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const analyticsSharedState = getSharedInstance(ANALYTICS_SHARED_STATE_NAME, createAnalyticsState);
|
|
40
|
-
const serverAnalyticsStates = new WeakMap();
|
|
41
|
-
/** @internal */
|
|
42
|
-
export function isAnalyticsEnabled(enabled, state = analyticsSharedState) {
|
|
43
|
-
return enabled && state.config.enabled && !isReactNative;
|
|
44
|
-
}
|
|
45
|
-
export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthModule, enabled, getVisitorId, experimentsContext, }) => {
|
|
46
|
-
const state = typeof window === "undefined" ? createAnalyticsState() : analyticsSharedState;
|
|
47
|
-
if (typeof window === "undefined")
|
|
48
|
-
serverAnalyticsStates.set(axiosClient, state);
|
|
20
|
+
// shared state//
|
|
21
|
+
const analyticsSharedState = getSharedInstance(ANALYTICS_SHARED_STATE_NAME, () => ({
|
|
22
|
+
requestsQueue: [],
|
|
23
|
+
isProcessing: false,
|
|
24
|
+
isHeartBeatProcessing: false,
|
|
25
|
+
wasInitializationTracked: false,
|
|
26
|
+
sessionContext: null,
|
|
27
|
+
sessionStartTime: null,
|
|
28
|
+
// Memoized session id for when `localStorage` can't persist one — see
|
|
29
|
+
// getAnalyticsSessionId.
|
|
30
|
+
fallbackSessionId: null,
|
|
31
|
+
config: {
|
|
32
|
+
...defaultConfiguration,
|
|
33
|
+
...getAnalyticsConfigFromUrlParams(),
|
|
34
|
+
},
|
|
35
|
+
}));
|
|
36
|
+
export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthModule, enabled, }) => {
|
|
37
|
+
var _a;
|
|
49
38
|
// prevent overflow of events //
|
|
50
|
-
const { maxQueueSize, throttleTime, batchSize } =
|
|
39
|
+
const { maxQueueSize, throttleTime, batchSize } = analyticsSharedState.config;
|
|
51
40
|
// Disable analytics on React Native. It defines `window` but not `document`,
|
|
52
41
|
// so the per-callsite `typeof window` guards below aren't enough to keep it
|
|
53
42
|
// from touching `document` (e.g. `document.referrer` on init). Node/SSR is
|
|
54
43
|
// still handled by those `window` guards, so this doesn't affect it.
|
|
55
|
-
if (!
|
|
44
|
+
if (!enabled || !((_a = analyticsSharedState.config) === null || _a === void 0 ? void 0 : _a.enabled) || isReactNative) {
|
|
56
45
|
return {
|
|
57
46
|
track: () => { },
|
|
58
47
|
cleanup: () => { },
|
|
@@ -81,17 +70,16 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
|
|
|
81
70
|
}
|
|
82
71
|
};
|
|
83
72
|
const flush = async (eventsData, options = {}) => {
|
|
84
|
-
var _a;
|
|
85
73
|
if (eventsData.length === 0)
|
|
86
74
|
return;
|
|
87
|
-
const sessionContext_ = await getSessionContext(userAuthModule
|
|
88
|
-
const events = eventsData.map(transformEventDataToApiRequestData(
|
|
75
|
+
const sessionContext_ = await getSessionContext(userAuthModule);
|
|
76
|
+
const events = eventsData.map(transformEventDataToApiRequestData(sessionContext_));
|
|
89
77
|
try {
|
|
90
78
|
if (!options.isBeacon || !beaconRequest(events)) {
|
|
91
79
|
await batchRequestFallback(events);
|
|
92
80
|
}
|
|
93
81
|
}
|
|
94
|
-
catch (
|
|
82
|
+
catch (_a) {
|
|
95
83
|
// do nothing
|
|
96
84
|
}
|
|
97
85
|
};
|
|
@@ -99,25 +87,16 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
|
|
|
99
87
|
startAnalyticsProcessor(flush, {
|
|
100
88
|
throttleTime,
|
|
101
89
|
batchSize,
|
|
102
|
-
}
|
|
90
|
+
});
|
|
103
91
|
};
|
|
104
92
|
const track = (params) => {
|
|
105
|
-
|
|
106
|
-
if (state.requestsQueue.length >= maxQueueSize) {
|
|
93
|
+
if (analyticsSharedState.requestsQueue.length >= maxQueueSize) {
|
|
107
94
|
return;
|
|
108
95
|
}
|
|
109
96
|
const intrinsicData = getEventIntrinsicData();
|
|
110
|
-
|
|
111
|
-
const properties = { ...params.properties };
|
|
112
|
-
delete properties.__b44_experiment_preview;
|
|
113
|
-
if (Object.keys(preview).length) {
|
|
114
|
-
// Capture now: a queued event must retain its occurrence-time preview.
|
|
115
|
-
properties.__b44_experiment_preview = JSON.stringify(preview);
|
|
116
|
-
}
|
|
117
|
-
state.requestsQueue.push({
|
|
97
|
+
analyticsSharedState.requestsQueue.push({
|
|
118
98
|
...params,
|
|
119
99
|
...intrinsicData,
|
|
120
|
-
properties: params.properties || Object.keys(properties).length ? properties : undefined,
|
|
121
100
|
});
|
|
122
101
|
startProcessing();
|
|
123
102
|
};
|
|
@@ -125,16 +104,16 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
|
|
|
125
104
|
startAnalyticsProcessor(flush, {
|
|
126
105
|
throttleTime,
|
|
127
106
|
batchSize,
|
|
128
|
-
}
|
|
129
|
-
clearHeartBeatProcessor = startHeartBeatProcessor(track
|
|
130
|
-
setSessionDurationTimerStart(
|
|
107
|
+
});
|
|
108
|
+
clearHeartBeatProcessor = startHeartBeatProcessor(track);
|
|
109
|
+
setSessionDurationTimerStart();
|
|
131
110
|
};
|
|
132
111
|
const onDocHidden = () => {
|
|
133
|
-
stopAnalyticsProcessor(
|
|
112
|
+
stopAnalyticsProcessor();
|
|
134
113
|
clearHeartBeatProcessor === null || clearHeartBeatProcessor === void 0 ? void 0 : clearHeartBeatProcessor();
|
|
135
|
-
trackSessionDurationEvent(track
|
|
114
|
+
trackSessionDurationEvent(track);
|
|
136
115
|
// flush entire queue on visibility change and hope for the best //
|
|
137
|
-
const eventsData =
|
|
116
|
+
const eventsData = analyticsSharedState.requestsQueue.splice(0);
|
|
138
117
|
flush(eventsData, { isBeacon: true });
|
|
139
118
|
};
|
|
140
119
|
const onVisibilityChange = () => {
|
|
@@ -148,7 +127,7 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
|
|
|
148
127
|
}
|
|
149
128
|
};
|
|
150
129
|
const cleanup = () => {
|
|
151
|
-
stopAnalyticsProcessor(
|
|
130
|
+
stopAnalyticsProcessor();
|
|
152
131
|
clearHeartBeatProcessor === null || clearHeartBeatProcessor === void 0 ? void 0 : clearHeartBeatProcessor();
|
|
153
132
|
if (typeof window !== "undefined") {
|
|
154
133
|
window.removeEventListener("visibilitychange", onVisibilityChange);
|
|
@@ -157,9 +136,9 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
|
|
|
157
136
|
// start the flusing process ///
|
|
158
137
|
startProcessing();
|
|
159
138
|
// start the heart beat processor //
|
|
160
|
-
clearHeartBeatProcessor = startHeartBeatProcessor(track
|
|
139
|
+
clearHeartBeatProcessor = startHeartBeatProcessor(track);
|
|
161
140
|
// track the referrer event //
|
|
162
|
-
trackInitializationEvent(track
|
|
141
|
+
trackInitializationEvent(track);
|
|
163
142
|
// start the visibility change listener //
|
|
164
143
|
if (typeof window !== "undefined") {
|
|
165
144
|
window.addEventListener("visibilitychange", onVisibilityChange);
|
|
@@ -169,50 +148,50 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
|
|
|
169
148
|
cleanup,
|
|
170
149
|
};
|
|
171
150
|
};
|
|
172
|
-
function stopAnalyticsProcessor(
|
|
173
|
-
|
|
151
|
+
function stopAnalyticsProcessor() {
|
|
152
|
+
analyticsSharedState.isProcessing = false;
|
|
174
153
|
}
|
|
175
|
-
async function startAnalyticsProcessor(handleTrack, options
|
|
176
|
-
if (
|
|
154
|
+
async function startAnalyticsProcessor(handleTrack, options) {
|
|
155
|
+
if (analyticsSharedState.isProcessing) {
|
|
177
156
|
// only one instance of the analytics processor can be running at a time //
|
|
178
157
|
return;
|
|
179
158
|
}
|
|
180
|
-
|
|
159
|
+
analyticsSharedState.isProcessing = true;
|
|
181
160
|
const { throttleTime = 1000, batchSize = 30 } = options !== null && options !== void 0 ? options : {};
|
|
182
|
-
while (
|
|
183
|
-
|
|
184
|
-
const requests =
|
|
161
|
+
while (analyticsSharedState.isProcessing &&
|
|
162
|
+
analyticsSharedState.requestsQueue.length > 0) {
|
|
163
|
+
const requests = analyticsSharedState.requestsQueue.splice(0, batchSize);
|
|
185
164
|
requests.length && (await handleTrack(requests));
|
|
186
165
|
await new Promise((resolve) => setTimeout(resolve, throttleTime));
|
|
187
166
|
}
|
|
188
|
-
|
|
167
|
+
analyticsSharedState.isProcessing = false;
|
|
189
168
|
}
|
|
190
|
-
function startHeartBeatProcessor(track
|
|
169
|
+
function startHeartBeatProcessor(track) {
|
|
191
170
|
var _a;
|
|
192
171
|
// Browser-only, like the other automatic events here (initialization, session
|
|
193
172
|
// duration, visibility). Outside a browser this timer fired a `me()` every
|
|
194
173
|
// interval for the lifetime of a long-lived server-side client, and kept the
|
|
195
174
|
// Node event loop alive. Explicit `analytics.track()` calls still work.
|
|
196
175
|
if (typeof window === "undefined" ||
|
|
197
|
-
|
|
198
|
-
((_a =
|
|
176
|
+
analyticsSharedState.isHeartBeatProcessing ||
|
|
177
|
+
((_a = analyticsSharedState.config.heartBeatInterval) !== null && _a !== void 0 ? _a : 0) < 10) {
|
|
199
178
|
return () => { };
|
|
200
179
|
}
|
|
201
|
-
|
|
180
|
+
analyticsSharedState.isHeartBeatProcessing = true;
|
|
202
181
|
const interval = setInterval(() => {
|
|
203
182
|
track({ eventName: USER_HEARTBEAT_EVENT_NAME });
|
|
204
|
-
},
|
|
183
|
+
}, analyticsSharedState.config.heartBeatInterval);
|
|
205
184
|
return () => {
|
|
206
185
|
clearInterval(interval);
|
|
207
|
-
|
|
186
|
+
analyticsSharedState.isHeartBeatProcessing = false;
|
|
208
187
|
};
|
|
209
188
|
}
|
|
210
|
-
function trackInitializationEvent(track
|
|
189
|
+
function trackInitializationEvent(track) {
|
|
211
190
|
if (typeof window === "undefined" ||
|
|
212
|
-
|
|
191
|
+
analyticsSharedState.wasInitializationTracked) {
|
|
213
192
|
return;
|
|
214
193
|
}
|
|
215
|
-
|
|
194
|
+
analyticsSharedState.wasInitializationTracked = true;
|
|
216
195
|
track({
|
|
217
196
|
eventName: ANALYTICS_INITIALIZATION_EVENT_NAME,
|
|
218
197
|
properties: {
|
|
@@ -220,20 +199,20 @@ function trackInitializationEvent(track, state) {
|
|
|
220
199
|
},
|
|
221
200
|
});
|
|
222
201
|
}
|
|
223
|
-
function setSessionDurationTimerStart(
|
|
202
|
+
function setSessionDurationTimerStart() {
|
|
224
203
|
if (typeof window === "undefined" ||
|
|
225
|
-
|
|
204
|
+
analyticsSharedState.sessionStartTime !== null) {
|
|
226
205
|
return;
|
|
227
206
|
}
|
|
228
|
-
|
|
207
|
+
analyticsSharedState.sessionStartTime = new Date().toISOString();
|
|
229
208
|
}
|
|
230
|
-
function trackSessionDurationEvent(track
|
|
209
|
+
function trackSessionDurationEvent(track) {
|
|
231
210
|
if (typeof window === "undefined" ||
|
|
232
|
-
|
|
211
|
+
analyticsSharedState.sessionStartTime === null)
|
|
233
212
|
return;
|
|
234
213
|
const sessionDuration = new Date().getTime() -
|
|
235
|
-
new Date(
|
|
236
|
-
|
|
214
|
+
new Date(analyticsSharedState.sessionStartTime).getTime();
|
|
215
|
+
analyticsSharedState.sessionStartTime = null;
|
|
237
216
|
track({
|
|
238
217
|
eventName: ANALYTICS_SESSION_DURATION_EVENT_NAME,
|
|
239
218
|
properties: { sessionDuration },
|
|
@@ -256,6 +235,7 @@ function transformEventDataToApiRequestData(sessionContext) {
|
|
|
256
235
|
...sessionContext,
|
|
257
236
|
});
|
|
258
237
|
}
|
|
238
|
+
let sessionContextPromise = null;
|
|
259
239
|
/**
|
|
260
240
|
* Clears the memoized analytics session context.
|
|
261
241
|
*
|
|
@@ -266,24 +246,22 @@ function transformEventDataToApiRequestData(sessionContext) {
|
|
|
266
246
|
*
|
|
267
247
|
* @internal
|
|
268
248
|
*/
|
|
269
|
-
export function resetAnalyticsSessionContext(
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
state.sessionContext = null;
|
|
273
|
-
state.sessionContextPromise = null;
|
|
249
|
+
export function resetAnalyticsSessionContext() {
|
|
250
|
+
analyticsSharedState.sessionContext = null;
|
|
251
|
+
sessionContextPromise = null;
|
|
274
252
|
}
|
|
275
|
-
async function getSessionContext(userAuthModule
|
|
276
|
-
if (!
|
|
253
|
+
async function getSessionContext(userAuthModule) {
|
|
254
|
+
if (!analyticsSharedState.sessionContext) {
|
|
277
255
|
// With no token there is no identity to resolve: `me()` can only answer 401,
|
|
278
256
|
// which the browser logs to the console before any handler here sees it. On
|
|
279
257
|
// a public page that request is the sole reason an error appears, so skip
|
|
280
258
|
// it. This is not memoized — a visitor who logs in later must still resolve.
|
|
281
259
|
if (!userAuthModule.hasToken()) {
|
|
282
|
-
return { user_id: null, session_id: getAnalyticsSessionId(
|
|
260
|
+
return { user_id: null, session_id: getAnalyticsSessionId() };
|
|
283
261
|
}
|
|
284
|
-
if (!
|
|
285
|
-
const sessionId = getAnalyticsSessionId(
|
|
286
|
-
|
|
262
|
+
if (!sessionContextPromise) {
|
|
263
|
+
const sessionId = getAnalyticsSessionId();
|
|
264
|
+
sessionContextPromise = userAuthModule
|
|
287
265
|
.me()
|
|
288
266
|
.then((user) => ({
|
|
289
267
|
user_id: user.id,
|
|
@@ -294,7 +272,7 @@ async function getSessionContext(userAuthModule, state) {
|
|
|
294
272
|
session_id: sessionId,
|
|
295
273
|
}));
|
|
296
274
|
}
|
|
297
|
-
const pending =
|
|
275
|
+
const pending = sessionContextPromise;
|
|
298
276
|
const context = await pending;
|
|
299
277
|
// Publish only if this lookup is still the current one. A reset that lands
|
|
300
278
|
// while the request is in flight nulls `sessionContextPromise`, and an
|
|
@@ -302,12 +280,12 @@ async function getSessionContext(userAuthModule, state) {
|
|
|
302
280
|
// for the rest of the session. The awaited value is still returned: these
|
|
303
281
|
// events were queued before the identity changed, so that is who they
|
|
304
282
|
// belong to.
|
|
305
|
-
if (
|
|
306
|
-
|
|
283
|
+
if (sessionContextPromise === pending) {
|
|
284
|
+
analyticsSharedState.sessionContext = context;
|
|
307
285
|
}
|
|
308
286
|
return context;
|
|
309
287
|
}
|
|
310
|
-
return
|
|
288
|
+
return analyticsSharedState.sessionContext;
|
|
311
289
|
}
|
|
312
290
|
export function getAnalyticsConfigFromUrlParams() {
|
|
313
291
|
// `window.location` is absent on React Native. This runs at module load (via
|
|
@@ -329,18 +307,15 @@ export function getAnalyticsConfigFromUrlParams() {
|
|
|
329
307
|
// return the config object //
|
|
330
308
|
return { enabled: analyticsEnable === "true" };
|
|
331
309
|
}
|
|
332
|
-
//
|
|
333
|
-
|
|
310
|
+
// When the id can't be persisted (React Native has no `localStorage`), keep
|
|
311
|
+
// it stable for the process instead of minting a fresh one per call.
|
|
312
|
+
function getFallbackSessionId() {
|
|
334
313
|
var _a;
|
|
335
|
-
return ((_a =
|
|
314
|
+
return ((_a = analyticsSharedState.fallbackSessionId) !== null && _a !== void 0 ? _a : (analyticsSharedState.fallbackSessionId = generateUuid()));
|
|
336
315
|
}
|
|
337
|
-
export function getAnalyticsSessionId(
|
|
338
|
-
var _a;
|
|
339
|
-
const visitorId = (_a = getExperimentsRuntime()) === null || _a === void 0 ? void 0 : _a.visitorId;
|
|
340
|
-
if (visitorId && visitorId !== "anon")
|
|
341
|
-
return visitorId;
|
|
316
|
+
export function getAnalyticsSessionId() {
|
|
342
317
|
if (typeof window === "undefined") {
|
|
343
|
-
return getFallbackSessionId(
|
|
318
|
+
return getFallbackSessionId();
|
|
344
319
|
}
|
|
345
320
|
try {
|
|
346
321
|
const sessionId = localStorage.getItem(ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY);
|
|
@@ -351,7 +326,7 @@ export function getAnalyticsSessionId(state = analyticsSharedState) {
|
|
|
351
326
|
}
|
|
352
327
|
return sessionId;
|
|
353
328
|
}
|
|
354
|
-
catch (
|
|
355
|
-
return getFallbackSessionId(
|
|
329
|
+
catch (_a) {
|
|
330
|
+
return getFallbackSessionId();
|
|
356
331
|
}
|
|
357
332
|
}
|