@base44-preview/sdk 0.8.57-pr.359.f19a932 → 0.8.57-pr.361.dda0ab9

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.
@@ -202,15 +202,15 @@ export interface AgentsModuleConfig {
202
202
  */
203
203
  export interface AgentsModule {
204
204
  /**
205
- * Gets all conversations from all agents in the app.
205
+ * Gets the current user's conversations with all agents in the app.
206
206
  *
207
- * Retrieves all conversations. Use {@linkcode listConversations | listConversations()} to filter which conversations are returned, apply sorting, or paginate results. Use {@linkcode getConversation | getConversation()} to retrieve a specific conversation by ID.
207
+ * Retrieves every conversation the current user started, across all agents. Conversations that other users started aren't included. Use {@linkcode listConversations | listConversations()} to filter which conversations are returned, apply sorting, or paginate results. Use {@linkcode getConversation | getConversation()} to retrieve a specific conversation by ID.
208
208
  *
209
209
  * @returns Promise resolving to an array of conversations.
210
210
  *
211
211
  * @example
212
212
  * ```typescript
213
- * // Get all conversations
213
+ * // Get the current user's conversations
214
214
  * const conversations = await base44.agents.getConversations();
215
215
  * console.log(`Total conversations: ${conversations.length}`);
216
216
  * ```
@@ -223,7 +223,7 @@ export interface AgentsModule {
223
223
  * Gets a specific conversation by ID.
224
224
  *
225
225
  * Retrieves a single conversation using its unique identifier. To retrieve
226
- * all conversations, use {@linkcode getConversations | getConversations()}. To filter, sort, or paginate conversations, use {@linkcode listConversations | listConversations()}.
226
+ * all of the current user's conversations, use {@linkcode getConversations | getConversations()}. To filter, sort, or paginate conversations, use {@linkcode listConversations | listConversations()}.
227
227
  *
228
228
  * This function returns the complete stored conversation including full tool call results, even for large responses.
229
229
  *
@@ -246,7 +246,7 @@ export interface AgentsModule {
246
246
  /**
247
247
  * Lists conversations with filtering, sorting, and pagination.
248
248
  *
249
- * Provides querying capabilities including filtering by fields, sorting, pagination, and field selection. For cases where you need all conversations without filtering, use {@linkcode getConversations | getConversations()}. To retrieve a specific conversation by ID, use {@linkcode getConversation | getConversation()}.
249
+ * Provides querying capabilities including filtering by fields, sorting, pagination, and field selection. For cases where you need all of the current user's conversations without filtering, use {@linkcode getConversations | getConversations()}. To retrieve a specific conversation by ID, use {@linkcode getConversation | getConversation()}.
250
250
  *
251
251
  * @param filterParams - Filter parameters for querying conversations.
252
252
  * @returns Promise resolving to an array of filtered conversations.
@@ -6,6 +6,9 @@ export declare const ANALYTICS_INITIALIZATION_EVENT_NAME = "__initialization_eve
6
6
  export declare const ANALYTICS_SESSION_DURATION_EVENT_NAME = "__session_duration_event__";
7
7
  export declare const ANALYTICS_CONFIG_ENABLE_URL_PARAM_KEY = "analytics-enable";
8
8
  export declare const ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY = "base44_analytics_session_id";
9
+ export declare const ANALYTICS_MODE_META_NAME = "base44-analytics";
10
+ /** Whether analytics may run and store the session id on this page. */
11
+ export declare function isAnalyticsAllowed(): boolean;
9
12
  export interface AnalyticsModuleArgs {
10
13
  axiosClient: AxiosInstance;
11
14
  serverUrl: string;
@@ -5,6 +5,25 @@ export const ANALYTICS_INITIALIZATION_EVENT_NAME = "__initialization_event__";
5
5
  export const ANALYTICS_SESSION_DURATION_EVENT_NAME = "__session_duration_event__";
6
6
  export const ANALYTICS_CONFIG_ENABLE_URL_PARAM_KEY = "analytics-enable";
7
7
  export const ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY = "base44_analytics_session_id";
8
+ // Set by the Base44 server from the app owner's choice: "off" never tracks,
9
+ // "consent" waits for the page's Google Consent Mode `analytics_storage` grant,
10
+ // "on" tracks until that consent is denied. Absent: track as before.
11
+ export const ANALYTICS_MODE_META_NAME = "base44-analytics";
12
+ function readAnalyticsMode() {
13
+ var _a;
14
+ if (typeof document === "undefined")
15
+ return null;
16
+ try {
17
+ const content = (_a = document
18
+ .querySelector(`meta[name="${ANALYTICS_MODE_META_NAME}"]`)) === null || _a === void 0 ? void 0 : _a.getAttribute("content");
19
+ return content === "off" || content === "consent" || content === "on"
20
+ ? content
21
+ : null;
22
+ }
23
+ catch (_b) {
24
+ return null;
25
+ }
26
+ }
8
27
  const defaultConfiguration = {
9
28
  // default to enabled //
10
29
  enabled: true,
@@ -33,15 +52,80 @@ const analyticsSharedState = getSharedInstance(ANALYTICS_SHARED_STATE_NAME, () =
33
52
  ...getAnalyticsConfigFromUrlParams(),
34
53
  },
35
54
  }));
55
+ ///////////////////////////////////////////////
56
+ //// visitor consent ////
57
+ ///////////////////////////////////////////////
58
+ // Its own shared instance: an older SDK copy on the page may own "analytics".
59
+ const consentSharedState = getSharedInstance("analytics-consent", () => {
60
+ const analyticsMode = readAnalyticsMode();
61
+ return {
62
+ analyticsMode,
63
+ // Whether the visitor may be tracked and the session id stored.
64
+ consentGranted: analyticsMode !== "consent",
65
+ isWatchingConsent: false,
66
+ listeners: [],
67
+ };
68
+ });
69
+ /** Whether analytics may run and store the session id on this page. */
70
+ export function isAnalyticsAllowed() {
71
+ const { analyticsMode, consentGranted } = consentSharedState;
72
+ return analyticsMode !== "off" && consentGranted;
73
+ }
74
+ function setConsentGranted(granted) {
75
+ var _a;
76
+ if (consentSharedState.consentGranted === granted)
77
+ return;
78
+ consentSharedState.consentGranted = granted;
79
+ if (!granted) {
80
+ try {
81
+ const sessionId = localStorage.getItem(ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY);
82
+ // Same id for the rest of the tab, so an anonymous agent chat keeps its owner.
83
+ if (sessionId)
84
+ (_a = analyticsSharedState.fallbackSessionId) !== null && _a !== void 0 ? _a : (analyticsSharedState.fallbackSessionId = sessionId);
85
+ localStorage.removeItem(ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY);
86
+ }
87
+ catch (_b) {
88
+ // storage unavailable: nothing was stored
89
+ }
90
+ }
91
+ for (const listener of [...consentSharedState.listeners]) {
92
+ listener(granted);
93
+ }
94
+ }
95
+ // Subscribes once to the consent listener Base44 injects next to the meta tag.
96
+ // Without it (e.g. a CSP blocked the inline script) "consent" never grants.
97
+ function watchAnalyticsConsent() {
98
+ const state = consentSharedState;
99
+ if (state.isWatchingConsent)
100
+ return;
101
+ state.isWatchingConsent = true;
102
+ if (state.analyticsMode !== "consent" && state.analyticsMode !== "on")
103
+ return;
104
+ const b44Consent = typeof window !== "undefined" ? window.__b44Consent : undefined;
105
+ b44Consent === null || b44Consent === void 0 ? void 0 : b44Consent.on("analytics_storage", () => setConsentGranted(true), () => setConsentGranted(false));
106
+ }
107
+ function onConsentChange(listener) {
108
+ consentSharedState.listeners.push(listener);
109
+ return () => {
110
+ const listeners = consentSharedState.listeners;
111
+ const index = listeners.indexOf(listener);
112
+ if (index >= 0)
113
+ listeners.splice(index, 1);
114
+ };
115
+ }
36
116
  export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthModule, enabled, }) => {
37
117
  var _a;
38
118
  // prevent overflow of events //
39
119
  const { maxQueueSize, throttleTime, batchSize } = analyticsSharedState.config;
120
+ watchAnalyticsConsent();
40
121
  // Disable analytics on React Native. It defines `window` but not `document`,
41
122
  // so the per-callsite `typeof window` guards below aren't enough to keep it
42
123
  // from touching `document` (e.g. `document.referrer` on init). Node/SSR is
43
124
  // still handled by those `window` guards, so this doesn't affect it.
44
- if (!enabled || !((_a = analyticsSharedState.config) === null || _a === void 0 ? void 0 : _a.enabled) || isReactNative) {
125
+ if (!enabled ||
126
+ !((_a = analyticsSharedState.config) === null || _a === void 0 ? void 0 : _a.enabled) ||
127
+ isReactNative ||
128
+ consentSharedState.analyticsMode === "off") {
45
129
  return {
46
130
  track: () => { },
47
131
  cleanup: () => { },
@@ -70,7 +154,8 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
70
154
  }
71
155
  };
72
156
  const flush = async (eventsData, options = {}) => {
73
- if (eventsData.length === 0)
157
+ // Consent may have been withdrawn while these events waited.
158
+ if (eventsData.length === 0 || !isAnalyticsAllowed())
74
159
  return;
75
160
  const sessionContext_ = await getSessionContext(userAuthModule);
76
161
  const events = eventsData.map(transformEventDataToApiRequestData(sessionContext_));
@@ -90,7 +175,8 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
90
175
  });
91
176
  };
92
177
  const track = (params) => {
93
- if (analyticsSharedState.requestsQueue.length >= maxQueueSize) {
178
+ if (!isAnalyticsAllowed() ||
179
+ analyticsSharedState.requestsQueue.length >= maxQueueSize) {
94
180
  return;
95
181
  }
96
182
  const intrinsicData = getEventIntrinsicData();
@@ -126,23 +212,45 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
126
212
  onDocVisible();
127
213
  }
128
214
  };
129
- const cleanup = () => {
215
+ let isStarted = false;
216
+ const start = () => {
217
+ if (isStarted)
218
+ return;
219
+ isStarted = true;
220
+ // start the flusing process ///
221
+ startProcessing();
222
+ // start the heart beat processor //
223
+ clearHeartBeatProcessor = startHeartBeatProcessor(track);
224
+ // track the referrer event //
225
+ trackInitializationEvent(track);
226
+ // start the visibility change listener //
227
+ if (typeof window !== "undefined") {
228
+ window.addEventListener("visibilitychange", onVisibilityChange);
229
+ }
230
+ };
231
+ const stop = () => {
232
+ isStarted = false;
130
233
  stopAnalyticsProcessor();
131
234
  clearHeartBeatProcessor === null || clearHeartBeatProcessor === void 0 ? void 0 : clearHeartBeatProcessor();
132
235
  if (typeof window !== "undefined") {
133
236
  window.removeEventListener("visibilitychange", onVisibilityChange);
134
237
  }
135
238
  };
136
- // start the flusing process ///
137
- startProcessing();
138
- // start the heart beat processor //
139
- clearHeartBeatProcessor = startHeartBeatProcessor(track);
140
- // track the referrer event //
141
- trackInitializationEvent(track);
142
- // start the visibility change listener //
143
- if (typeof window !== "undefined") {
144
- window.addEventListener("visibilitychange", onVisibilityChange);
145
- }
239
+ const stopWatchingConsent = onConsentChange((granted) => {
240
+ if (granted) {
241
+ start();
242
+ }
243
+ else {
244
+ stop();
245
+ analyticsSharedState.requestsQueue.splice(0);
246
+ }
247
+ });
248
+ const cleanup = () => {
249
+ stopWatchingConsent();
250
+ stop();
251
+ };
252
+ if (isAnalyticsAllowed())
253
+ start();
146
254
  return {
147
255
  track,
148
256
  cleanup,
@@ -338,19 +446,21 @@ function getFallbackSessionId() {
338
446
  return ((_a = analyticsSharedState.fallbackSessionId) !== null && _a !== void 0 ? _a : (analyticsSharedState.fallbackSessionId = generateUuid()));
339
447
  }
340
448
  export function getAnalyticsSessionId() {
341
- if (typeof window === "undefined") {
449
+ var _a;
450
+ if (typeof window === "undefined" || !isAnalyticsAllowed()) {
342
451
  return getFallbackSessionId();
343
452
  }
344
453
  try {
345
454
  const sessionId = localStorage.getItem(ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY);
346
455
  if (!sessionId) {
347
- const newSessionId = generateUuid();
456
+ // An id used before consent was granted carries on, so it is stored now.
457
+ const newSessionId = (_a = analyticsSharedState.fallbackSessionId) !== null && _a !== void 0 ? _a : generateUuid();
348
458
  localStorage.setItem(ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY, newSessionId);
349
459
  return newSessionId;
350
460
  }
351
461
  return sessionId;
352
462
  }
353
- catch (_a) {
463
+ catch (_b) {
354
464
  return getFallbackSessionId();
355
465
  }
356
466
  }
@@ -1,3 +1,4 @@
1
+ import { isAnalyticsAllowed } from "./analytics.js";
1
2
  /**
2
3
  * Creates the app logs module for the Base44 SDK.
3
4
  *
@@ -11,6 +12,9 @@ export function createAppLogsModule(axios, appId) {
11
12
  return {
12
13
  // Log user activity in the app
13
14
  async logUserInApp(pageName) {
15
+ // A page visit feeds App Analytics, so it follows the same consent.
16
+ if (!isAnalyticsAllowed())
17
+ return;
14
18
  await axios.post(`${baseURL}/log-user-in-app/${pageName}`);
15
19
  },
16
20
  // Fetch app logs with optional parameters
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/sdk",
3
- "version": "0.8.57-pr.359.f19a932",
3
+ "version": "0.8.57-pr.361.dda0ab9",
4
4
  "description": "JavaScript SDK for Base44 API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",