@base44-preview/sdk 0.8.48-pr.280.7eec9ba → 0.8.48-pr.280.b5c6133

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 CHANGED
@@ -230,7 +230,6 @@ export function createClient(config) {
230
230
  userAuthModule,
231
231
  enabled: (_f = analytics === null || analytics === void 0 ? void 0 : analytics.enabled) !== null && _f !== void 0 ? _f : true,
232
232
  getVisitorId: experiments.visitorId,
233
- experimentsContext,
234
233
  }),
235
234
  actors: actorsModule.module,
236
235
  cleanup: () => {
@@ -1,7 +1,6 @@
1
1
  import { AxiosInstance } from "axios";
2
- import { TrackEventParams, TrackEventData, AnalyticsModuleOptions, SessionContext } from "./analytics.types";
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__";
@@ -14,21 +13,10 @@ export interface AnalyticsModuleArgs {
14
13
  userAuthModule: InternalAuthModule;
15
14
  enabled: boolean;
16
15
  getVisitorId?: () => string | undefined;
17
- experimentsContext?: ExperimentsContext;
18
16
  }
19
17
  /** @internal */
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) => {
18
+ export declare function isAnalyticsEnabled(enabled: boolean): boolean;
19
+ export declare const createAnalyticsModule: ({ axiosClient, serverUrl, appId, userAuthModule, enabled, getVisitorId, }: AnalyticsModuleArgs) => {
32
20
  track: (params: TrackEventParams) => void;
33
21
  cleanup: () => void;
34
22
  };
@@ -42,16 +30,6 @@ export declare const createAnalyticsModule: ({ axiosClient, serverUrl, appId, us
42
30
  *
43
31
  * @internal
44
32
  */
45
- export declare function resetAnalyticsSessionContext(axiosClient?: AxiosInstance): void;
33
+ export declare function resetAnalyticsSessionContext(): void;
46
34
  export declare function getAnalyticsConfigFromUrlParams(): AnalyticsModuleOptions | undefined;
47
- export declare function getAnalyticsSessionId(state?: {
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;
35
+ export declare function getAnalyticsSessionId(): string;
@@ -18,41 +18,34 @@ const defaultConfiguration = {
18
18
  //// shared queue for analytics events ////
19
19
  ///////////////////////////////////////////////
20
20
  const ANALYTICS_SHARED_STATE_NAME = "analytics";
21
- function createAnalyticsState() {
22
- return {
23
- requestsQueue: [],
24
- isProcessing: false,
25
- isHeartBeatProcessing: false,
26
- wasInitializationTracked: false,
27
- sessionContext: null,
28
- sessionContextPromise: null,
29
- sessionStartTime: null,
30
- // Memoized session id for when `localStorage` can't persist one — see
31
- // getAnalyticsSessionId.
32
- fallbackSessionId: null,
33
- config: {
34
- ...defaultConfiguration,
35
- ...getAnalyticsConfigFromUrlParams(),
36
- },
37
- };
38
- }
39
- const analyticsSharedState = getSharedInstance(ANALYTICS_SHARED_STATE_NAME, createAnalyticsState);
40
- const serverAnalyticsStates = new WeakMap();
21
+ // shared state//
22
+ const analyticsSharedState = getSharedInstance(ANALYTICS_SHARED_STATE_NAME, () => ({
23
+ requestsQueue: [],
24
+ isProcessing: false,
25
+ isHeartBeatProcessing: false,
26
+ wasInitializationTracked: false,
27
+ sessionContext: null,
28
+ sessionStartTime: null,
29
+ // Memoized session id for when `localStorage` can't persist one — see
30
+ // getAnalyticsSessionId.
31
+ fallbackSessionId: null,
32
+ config: {
33
+ ...defaultConfiguration,
34
+ ...getAnalyticsConfigFromUrlParams(),
35
+ },
36
+ }));
41
37
  /** @internal */
42
- export function isAnalyticsEnabled(enabled, state = analyticsSharedState) {
43
- return enabled && state.config.enabled && !isReactNative;
38
+ export function isAnalyticsEnabled(enabled) {
39
+ return enabled && analyticsSharedState.config.enabled && !isReactNative;
44
40
  }
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);
41
+ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthModule, enabled, getVisitorId, }) => {
49
42
  // prevent overflow of events //
50
- const { maxQueueSize, throttleTime, batchSize } = state.config;
43
+ const { maxQueueSize, throttleTime, batchSize } = analyticsSharedState.config;
51
44
  // Disable analytics on React Native. It defines `window` but not `document`,
52
45
  // so the per-callsite `typeof window` guards below aren't enough to keep it
53
46
  // from touching `document` (e.g. `document.referrer` on init). Node/SSR is
54
47
  // still handled by those `window` guards, so this doesn't affect it.
55
- if (!isAnalyticsEnabled(enabled, state)) {
48
+ if (!isAnalyticsEnabled(enabled)) {
56
49
  return {
57
50
  track: () => { },
58
51
  cleanup: () => { },
@@ -84,7 +77,7 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
84
77
  var _a;
85
78
  if (eventsData.length === 0)
86
79
  return;
87
- const sessionContext_ = await getSessionContext(userAuthModule, state);
80
+ const sessionContext_ = await getSessionContext(userAuthModule);
88
81
  const events = eventsData.map(transformEventDataToApiRequestData({ ...sessionContext_, session_id: (_a = getVisitorId === null || getVisitorId === void 0 ? void 0 : getVisitorId()) !== null && _a !== void 0 ? _a : sessionContext_.session_id }));
89
82
  try {
90
83
  if (!options.isBeacon || !beaconRequest(events)) {
@@ -99,25 +92,16 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
99
92
  startAnalyticsProcessor(flush, {
100
93
  throttleTime,
101
94
  batchSize,
102
- }, state);
95
+ });
103
96
  };
104
97
  const track = (params) => {
105
- var _a;
106
- if (state.requestsQueue.length >= maxQueueSize) {
98
+ if (analyticsSharedState.requestsQueue.length >= maxQueueSize) {
107
99
  return;
108
100
  }
109
101
  const intrinsicData = getEventIntrinsicData();
110
- const preview = Object.fromEntries(Object.entries((_a = experimentsContext === null || experimentsContext === void 0 ? void 0 : experimentsContext.preview) !== null && _a !== void 0 ? _a : {}).filter(([, value]) => typeof value === "boolean"));
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({
102
+ analyticsSharedState.requestsQueue.push({
118
103
  ...params,
119
104
  ...intrinsicData,
120
- properties: params.properties || Object.keys(properties).length ? properties : undefined,
121
105
  });
122
106
  startProcessing();
123
107
  };
@@ -125,16 +109,16 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
125
109
  startAnalyticsProcessor(flush, {
126
110
  throttleTime,
127
111
  batchSize,
128
- }, state);
129
- clearHeartBeatProcessor = startHeartBeatProcessor(track, state);
130
- setSessionDurationTimerStart(state);
112
+ });
113
+ clearHeartBeatProcessor = startHeartBeatProcessor(track);
114
+ setSessionDurationTimerStart();
131
115
  };
132
116
  const onDocHidden = () => {
133
- stopAnalyticsProcessor(state);
117
+ stopAnalyticsProcessor();
134
118
  clearHeartBeatProcessor === null || clearHeartBeatProcessor === void 0 ? void 0 : clearHeartBeatProcessor();
135
- trackSessionDurationEvent(track, state);
119
+ trackSessionDurationEvent(track);
136
120
  // flush entire queue on visibility change and hope for the best //
137
- const eventsData = state.requestsQueue.splice(0);
121
+ const eventsData = analyticsSharedState.requestsQueue.splice(0);
138
122
  flush(eventsData, { isBeacon: true });
139
123
  };
140
124
  const onVisibilityChange = () => {
@@ -148,7 +132,7 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
148
132
  }
149
133
  };
150
134
  const cleanup = () => {
151
- stopAnalyticsProcessor(state);
135
+ stopAnalyticsProcessor();
152
136
  clearHeartBeatProcessor === null || clearHeartBeatProcessor === void 0 ? void 0 : clearHeartBeatProcessor();
153
137
  if (typeof window !== "undefined") {
154
138
  window.removeEventListener("visibilitychange", onVisibilityChange);
@@ -157,9 +141,9 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
157
141
  // start the flusing process ///
158
142
  startProcessing();
159
143
  // start the heart beat processor //
160
- clearHeartBeatProcessor = startHeartBeatProcessor(track, state);
144
+ clearHeartBeatProcessor = startHeartBeatProcessor(track);
161
145
  // track the referrer event //
162
- trackInitializationEvent(track, state);
146
+ trackInitializationEvent(track);
163
147
  // start the visibility change listener //
164
148
  if (typeof window !== "undefined") {
165
149
  window.addEventListener("visibilitychange", onVisibilityChange);
@@ -169,50 +153,50 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
169
153
  cleanup,
170
154
  };
171
155
  };
172
- function stopAnalyticsProcessor(state) {
173
- state.isProcessing = false;
156
+ function stopAnalyticsProcessor() {
157
+ analyticsSharedState.isProcessing = false;
174
158
  }
175
- async function startAnalyticsProcessor(handleTrack, options, state) {
176
- if (state.isProcessing) {
159
+ async function startAnalyticsProcessor(handleTrack, options) {
160
+ if (analyticsSharedState.isProcessing) {
177
161
  // only one instance of the analytics processor can be running at a time //
178
162
  return;
179
163
  }
180
- state.isProcessing = true;
164
+ analyticsSharedState.isProcessing = true;
181
165
  const { throttleTime = 1000, batchSize = 30 } = options !== null && options !== void 0 ? options : {};
182
- while (state.isProcessing &&
183
- state.requestsQueue.length > 0) {
184
- const requests = state.requestsQueue.splice(0, batchSize);
166
+ while (analyticsSharedState.isProcessing &&
167
+ analyticsSharedState.requestsQueue.length > 0) {
168
+ const requests = analyticsSharedState.requestsQueue.splice(0, batchSize);
185
169
  requests.length && (await handleTrack(requests));
186
170
  await new Promise((resolve) => setTimeout(resolve, throttleTime));
187
171
  }
188
- state.isProcessing = false;
172
+ analyticsSharedState.isProcessing = false;
189
173
  }
190
- function startHeartBeatProcessor(track, state) {
174
+ function startHeartBeatProcessor(track) {
191
175
  var _a;
192
176
  // Browser-only, like the other automatic events here (initialization, session
193
177
  // duration, visibility). Outside a browser this timer fired a `me()` every
194
178
  // interval for the lifetime of a long-lived server-side client, and kept the
195
179
  // Node event loop alive. Explicit `analytics.track()` calls still work.
196
180
  if (typeof window === "undefined" ||
197
- state.isHeartBeatProcessing ||
198
- ((_a = state.config.heartBeatInterval) !== null && _a !== void 0 ? _a : 0) < 10) {
181
+ analyticsSharedState.isHeartBeatProcessing ||
182
+ ((_a = analyticsSharedState.config.heartBeatInterval) !== null && _a !== void 0 ? _a : 0) < 10) {
199
183
  return () => { };
200
184
  }
201
- state.isHeartBeatProcessing = true;
185
+ analyticsSharedState.isHeartBeatProcessing = true;
202
186
  const interval = setInterval(() => {
203
187
  track({ eventName: USER_HEARTBEAT_EVENT_NAME });
204
- }, state.config.heartBeatInterval);
188
+ }, analyticsSharedState.config.heartBeatInterval);
205
189
  return () => {
206
190
  clearInterval(interval);
207
- state.isHeartBeatProcessing = false;
191
+ analyticsSharedState.isHeartBeatProcessing = false;
208
192
  };
209
193
  }
210
- function trackInitializationEvent(track, state) {
194
+ function trackInitializationEvent(track) {
211
195
  if (typeof window === "undefined" ||
212
- state.wasInitializationTracked) {
196
+ analyticsSharedState.wasInitializationTracked) {
213
197
  return;
214
198
  }
215
- state.wasInitializationTracked = true;
199
+ analyticsSharedState.wasInitializationTracked = true;
216
200
  track({
217
201
  eventName: ANALYTICS_INITIALIZATION_EVENT_NAME,
218
202
  properties: {
@@ -220,20 +204,20 @@ function trackInitializationEvent(track, state) {
220
204
  },
221
205
  });
222
206
  }
223
- function setSessionDurationTimerStart(state) {
207
+ function setSessionDurationTimerStart() {
224
208
  if (typeof window === "undefined" ||
225
- state.sessionStartTime !== null) {
209
+ analyticsSharedState.sessionStartTime !== null) {
226
210
  return;
227
211
  }
228
- state.sessionStartTime = new Date().toISOString();
212
+ analyticsSharedState.sessionStartTime = new Date().toISOString();
229
213
  }
230
- function trackSessionDurationEvent(track, state) {
214
+ function trackSessionDurationEvent(track) {
231
215
  if (typeof window === "undefined" ||
232
- state.sessionStartTime === null)
216
+ analyticsSharedState.sessionStartTime === null)
233
217
  return;
234
218
  const sessionDuration = new Date().getTime() -
235
- new Date(state.sessionStartTime).getTime();
236
- state.sessionStartTime = null;
219
+ new Date(analyticsSharedState.sessionStartTime).getTime();
220
+ analyticsSharedState.sessionStartTime = null;
237
221
  track({
238
222
  eventName: ANALYTICS_SESSION_DURATION_EVENT_NAME,
239
223
  properties: { sessionDuration },
@@ -256,6 +240,7 @@ function transformEventDataToApiRequestData(sessionContext) {
256
240
  ...sessionContext,
257
241
  });
258
242
  }
243
+ let sessionContextPromise = null;
259
244
  /**
260
245
  * Clears the memoized analytics session context.
261
246
  *
@@ -266,24 +251,22 @@ function transformEventDataToApiRequestData(sessionContext) {
266
251
  *
267
252
  * @internal
268
253
  */
269
- export function resetAnalyticsSessionContext(axiosClient) {
270
- var _a;
271
- const state = axiosClient ? (_a = serverAnalyticsStates.get(axiosClient)) !== null && _a !== void 0 ? _a : analyticsSharedState : analyticsSharedState;
272
- state.sessionContext = null;
273
- state.sessionContextPromise = null;
254
+ export function resetAnalyticsSessionContext() {
255
+ analyticsSharedState.sessionContext = null;
256
+ sessionContextPromise = null;
274
257
  }
275
- async function getSessionContext(userAuthModule, state) {
276
- if (!state.sessionContext) {
258
+ async function getSessionContext(userAuthModule) {
259
+ if (!analyticsSharedState.sessionContext) {
277
260
  // With no token there is no identity to resolve: `me()` can only answer 401,
278
261
  // which the browser logs to the console before any handler here sees it. On
279
262
  // a public page that request is the sole reason an error appears, so skip
280
263
  // it. This is not memoized — a visitor who logs in later must still resolve.
281
264
  if (!userAuthModule.hasToken()) {
282
- return { user_id: null, session_id: getAnalyticsSessionId(state) };
265
+ return { user_id: null, session_id: getAnalyticsSessionId() };
283
266
  }
284
- if (!state.sessionContextPromise) {
285
- const sessionId = getAnalyticsSessionId(state);
286
- state.sessionContextPromise = userAuthModule
267
+ if (!sessionContextPromise) {
268
+ const sessionId = getAnalyticsSessionId();
269
+ sessionContextPromise = userAuthModule
287
270
  .me()
288
271
  .then((user) => ({
289
272
  user_id: user.id,
@@ -294,7 +277,7 @@ async function getSessionContext(userAuthModule, state) {
294
277
  session_id: sessionId,
295
278
  }));
296
279
  }
297
- const pending = state.sessionContextPromise;
280
+ const pending = sessionContextPromise;
298
281
  const context = await pending;
299
282
  // Publish only if this lookup is still the current one. A reset that lands
300
283
  // while the request is in flight nulls `sessionContextPromise`, and an
@@ -302,12 +285,12 @@ async function getSessionContext(userAuthModule, state) {
302
285
  // for the rest of the session. The awaited value is still returned: these
303
286
  // events were queued before the identity changed, so that is who they
304
287
  // belong to.
305
- if (state.sessionContextPromise === pending) {
306
- state.sessionContext = context;
288
+ if (sessionContextPromise === pending) {
289
+ analyticsSharedState.sessionContext = context;
307
290
  }
308
291
  return context;
309
292
  }
310
- return state.sessionContext;
293
+ return analyticsSharedState.sessionContext;
311
294
  }
312
295
  export function getAnalyticsConfigFromUrlParams() {
313
296
  // `window.location` is absent on React Native. This runs at module load (via
@@ -329,18 +312,19 @@ export function getAnalyticsConfigFromUrlParams() {
329
312
  // return the config object //
330
313
  return { enabled: analyticsEnable === "true" };
331
314
  }
332
- // Without persistent storage, keep the id stable within this analytics state.
333
- function getFallbackSessionId(state) {
315
+ // When the id can't be persisted (React Native has no `localStorage`), keep
316
+ // it stable for the process instead of minting a fresh one per call.
317
+ function getFallbackSessionId() {
334
318
  var _a;
335
- return ((_a = state.fallbackSessionId) !== null && _a !== void 0 ? _a : (state.fallbackSessionId = generateUuid()));
319
+ return ((_a = analyticsSharedState.fallbackSessionId) !== null && _a !== void 0 ? _a : (analyticsSharedState.fallbackSessionId = generateUuid()));
336
320
  }
337
- export function getAnalyticsSessionId(state = analyticsSharedState) {
321
+ export function getAnalyticsSessionId() {
338
322
  var _a;
339
323
  const visitorId = (_a = getExperimentsRuntime()) === null || _a === void 0 ? void 0 : _a.visitorId;
340
324
  if (visitorId && visitorId !== "anon")
341
325
  return visitorId;
342
326
  if (typeof window === "undefined") {
343
- return getFallbackSessionId(state);
327
+ return getFallbackSessionId();
344
328
  }
345
329
  try {
346
330
  const sessionId = localStorage.getItem(ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY);
@@ -352,6 +336,6 @@ export function getAnalyticsSessionId(state = analyticsSharedState) {
352
336
  return sessionId;
353
337
  }
354
338
  catch (_b) {
355
- return getFallbackSessionId(state);
339
+ return getFallbackSessionId();
356
340
  }
357
341
  }
@@ -177,7 +177,7 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
177
177
  // Drop identity resolved under the previous session: a `me()` already in
178
178
  // flight would otherwise resolve into callers that run after the logout.
179
179
  clearPendingMe();
180
- resetAnalyticsSessionContext(axios);
180
+ resetAnalyticsSessionContext();
181
181
  hasAccessToken = false;
182
182
  notifyAuthState({ status: "anonymous" });
183
183
  // Only do the rest if in a browser environment
@@ -207,7 +207,7 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
207
207
  // Same reasoning as in `logout`: the identity changes here, so anything
208
208
  // resolved for the previous one must not be handed to later callers.
209
209
  clearPendingMe();
210
- resetAnalyticsSessionContext(axios);
210
+ resetAnalyticsSessionContext();
211
211
  hasAccessToken = true;
212
212
  // handle token change for axios clients
213
213
  axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/sdk",
3
- "version": "0.8.48-pr.280.7eec9ba",
3
+ "version": "0.8.48-pr.280.b5c6133",
4
4
  "description": "JavaScript SDK for Base44 API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",