@base44-preview/sdk 0.8.44-pr.268.b6fd238 → 0.8.44-pr.270.91862eb
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 +2 -3
- package/dist/client.types.d.ts +17 -4
- package/dist/index.d.ts +0 -1
- package/dist/modules/analytics.d.ts +13 -2
- package/dist/modules/analytics.js +133 -15
- package/dist/modules/analytics.types.d.ts +91 -0
- package/dist/modules/app.types.d.ts +1 -53
- package/package.json +1 -1
- package/dist/modules/app.d.ts +0 -11
- package/dist/modules/app.js +0 -15
package/dist/client.js
CHANGED
|
@@ -9,7 +9,6 @@ import { createFunctionsModule } from "./modules/functions.js";
|
|
|
9
9
|
import { createAgentsModule } from "./modules/agents.js";
|
|
10
10
|
import { createAiGatewayModule } from "./modules/ai-gateway.js";
|
|
11
11
|
import { createAppLogsModule } from "./modules/app-logs.js";
|
|
12
|
-
import { createAppModule } from "./modules/app.js";
|
|
13
12
|
import { createUsersModule } from "./modules/users.js";
|
|
14
13
|
import { RoomsSocket } from "./utils/socket-utils.js";
|
|
15
14
|
import { createAnalyticsModule } from "./modules/analytics.js";
|
|
@@ -53,7 +52,7 @@ import { createActorsModule, resolveActorsHost, } from "./modules/actors.js";
|
|
|
53
52
|
*/
|
|
54
53
|
export function createClient(config) {
|
|
55
54
|
var _a, _b, _c;
|
|
56
|
-
const { serverUrl = "https://base44.app", appId, token, serviceToken, requiresAuth = false, appBaseUrl, options, functionsVersion, headers: optionalHeaders, } = config;
|
|
55
|
+
const { serverUrl = "https://base44.app", appId, token, serviceToken, requiresAuth = false, appBaseUrl, options, analytics: analyticsOptions, functionsVersion, headers: optionalHeaders, } = config;
|
|
57
56
|
// Normalize appBaseUrl to always be a string (empty if not provided or invalid)
|
|
58
57
|
const normalizedAppBaseUrl = typeof appBaseUrl === "string" ? appBaseUrl : "";
|
|
59
58
|
const socketConfig = {
|
|
@@ -188,13 +187,13 @@ export function createClient(config) {
|
|
|
188
187
|
}),
|
|
189
188
|
aiGateway: createAiGatewayModule({ serverUrl, token, appId }),
|
|
190
189
|
appLogs: createAppLogsModule(axiosClient, appId),
|
|
191
|
-
app: createAppModule(axiosClient, appId),
|
|
192
190
|
users: createUsersModule(axiosClient, appId),
|
|
193
191
|
analytics: createAnalyticsModule({
|
|
194
192
|
axiosClient,
|
|
195
193
|
serverUrl,
|
|
196
194
|
appId,
|
|
197
195
|
userAuthModule,
|
|
196
|
+
options: analyticsOptions,
|
|
198
197
|
}),
|
|
199
198
|
actors: actorsModule.module,
|
|
200
199
|
cleanup: () => {
|
package/dist/client.types.d.ts
CHANGED
|
@@ -7,8 +7,7 @@ import type { FunctionsModule } from "./modules/functions.types.js";
|
|
|
7
7
|
import type { AgentsModule } from "./modules/agents.types.js";
|
|
8
8
|
import type { AiGatewayModule } from "./modules/ai-gateway.types.js";
|
|
9
9
|
import type { AppLogsModule } from "./modules/app-logs.types.js";
|
|
10
|
-
import type {
|
|
11
|
-
import type { AnalyticsModule } from "./modules/analytics.types.js";
|
|
10
|
+
import type { AnalyticsModule, CreateClientAnalyticsOptions } from "./modules/analytics.types.js";
|
|
12
11
|
import type { ActorsModule } from "./modules/actors.types.js";
|
|
13
12
|
/**
|
|
14
13
|
* Options for creating a Base44 client.
|
|
@@ -83,6 +82,22 @@ export interface CreateClientConfig {
|
|
|
83
82
|
* @internal
|
|
84
83
|
*/
|
|
85
84
|
headers?: Record<string, string>;
|
|
85
|
+
/**
|
|
86
|
+
* Analytics configuration for this client.
|
|
87
|
+
*
|
|
88
|
+
* By default, analytics is enabled and starts as soon as the client is created: a persistent visitor ID is stored in `localStorage` and automatic events are sent.
|
|
89
|
+
*
|
|
90
|
+
* Set `consent: "pending"` to keep analytics dormant until the visitor makes a consent decision, then call {@linkcode AnalyticsModule.optIn | analytics.optIn()} or {@linkcode AnalyticsModule.optOut | analytics.optOut()}. Set `enabled: false` to turn the analytics module off entirely.
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* ```typescript
|
|
94
|
+
* const base44 = createClient({
|
|
95
|
+
* appId: 'my-app-id',
|
|
96
|
+
* analytics: { consent: 'pending' }
|
|
97
|
+
* });
|
|
98
|
+
* ```
|
|
99
|
+
*/
|
|
100
|
+
analytics?: CreateClientAnalyticsOptions;
|
|
86
101
|
/**
|
|
87
102
|
* Additional client options.
|
|
88
103
|
*/
|
|
@@ -102,8 +117,6 @@ export interface Base44Client {
|
|
|
102
117
|
analytics: AnalyticsModule;
|
|
103
118
|
/** {@link AppLogsModule | App logs module} for tracking app usage. */
|
|
104
119
|
appLogs: AppLogsModule;
|
|
105
|
-
/** {@link AppModule | App module} for reading the app's own public configuration. */
|
|
106
|
-
app: AppModule;
|
|
107
120
|
/** {@link ActorsModule | Actors module} for subscribing to and sending messages via Cloudflare Durable Object-backed Actors. */
|
|
108
121
|
actors: ActorsModule;
|
|
109
122
|
/** {@link AuthModule | Auth module} for user authentication and management. */
|
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,6 @@ export type { FunctionsModule, FunctionName, FunctionNameRegistry, } from "./mod
|
|
|
11
11
|
export type { AgentsModule, AgentName, AgentNameRegistry, AgentConversation, AgentMessage, AgentMessageReasoning, AgentMessageToolCall, AgentMessageUsage, AgentMessageCustomContext, AgentMessageMetadata, CreateConversationParams, } from "./modules/agents.types.js";
|
|
12
12
|
export type { AiGatewayModule, AiGatewayConnection, } from "./modules/ai-gateway.types.js";
|
|
13
13
|
export type { AppLogsModule } from "./modules/app-logs.types.js";
|
|
14
|
-
export type { AppModule, AppPublicSettings, AppPublicSettingsResponse, } from "./modules/app.types.js";
|
|
15
14
|
export type { ActorsModule, ActorClient, ActorRef, Connection, ActorSubscription, ActorConnectOptions, ActorNameRegistry, ActorRegistry, } from "./modules/actors.types.js";
|
|
16
15
|
export type { SsoModule, SsoAccessTokenResponse } from "./modules/sso.types.js";
|
|
17
16
|
export { Actor, type Conn } from "./actor.js";
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AxiosInstance } from "axios";
|
|
2
|
-
import { TrackEventParams, AnalyticsModuleOptions } from "./analytics.types";
|
|
2
|
+
import { TrackEventParams, AnalyticsModuleOptions, AnalyticsConsentStatus, CreateClientAnalyticsOptions } from "./analytics.types";
|
|
3
3
|
import type { InternalAuthModule } from "./auth.types";
|
|
4
4
|
export declare const USER_HEARTBEAT_EVENT_NAME = "__user_heartbeat_event__";
|
|
5
5
|
export declare const ANALYTICS_INITIALIZATION_EVENT_NAME = "__initialization_event__";
|
|
@@ -11,9 +11,20 @@ export interface AnalyticsModuleArgs {
|
|
|
11
11
|
serverUrl: string;
|
|
12
12
|
appId: string;
|
|
13
13
|
userAuthModule: InternalAuthModule;
|
|
14
|
+
options?: CreateClientAnalyticsOptions;
|
|
14
15
|
}
|
|
15
|
-
|
|
16
|
+
/**
|
|
17
|
+
* The effective analytics consent status. `"granted"` when no client set one
|
|
18
|
+
* explicitly, preserving the legacy always-on behavior.
|
|
19
|
+
*
|
|
20
|
+
* @internal
|
|
21
|
+
*/
|
|
22
|
+
export declare function getAnalyticsConsentStatus(): AnalyticsConsentStatus;
|
|
23
|
+
export declare const createAnalyticsModule: ({ axiosClient, serverUrl, appId, userAuthModule, options, }: AnalyticsModuleArgs) => {
|
|
16
24
|
track: (params: TrackEventParams) => void;
|
|
25
|
+
optIn: () => void;
|
|
26
|
+
optOut: () => void;
|
|
27
|
+
getConsentStatus: typeof getAnalyticsConsentStatus;
|
|
17
28
|
cleanup: () => void;
|
|
18
29
|
};
|
|
19
30
|
/**
|
|
@@ -28,22 +28,81 @@ const analyticsSharedState = getSharedInstance(ANALYTICS_SHARED_STATE_NAME, () =
|
|
|
28
28
|
// Memoized session id for when `localStorage` can't persist one — see
|
|
29
29
|
// getAnalyticsSessionId.
|
|
30
30
|
fallbackSessionId: null,
|
|
31
|
+
// Consent status shared by every client on the page. `null` means no
|
|
32
|
+
// client set one explicitly, which keeps the legacy behavior (granted).
|
|
33
|
+
consent: null,
|
|
31
34
|
config: {
|
|
32
35
|
...defaultConfiguration,
|
|
33
36
|
...getAnalyticsConfigFromUrlParams(),
|
|
34
37
|
},
|
|
35
38
|
}));
|
|
36
|
-
|
|
39
|
+
// Lower ranks are more restrictive. Used to merge the consent status of
|
|
40
|
+
// multiple clients created on the same page: the shared state (and therefore
|
|
41
|
+
// the shared persistent id) can only honor one status, so the most
|
|
42
|
+
// restrictive explicitly-configured one wins.
|
|
43
|
+
const CONSENT_RESTRICTIVENESS = {
|
|
44
|
+
denied: 0,
|
|
45
|
+
pending: 1,
|
|
46
|
+
granted: 2,
|
|
47
|
+
};
|
|
48
|
+
function applyInitialConsent(consent) {
|
|
49
|
+
if (!consent)
|
|
50
|
+
return;
|
|
51
|
+
const current = analyticsSharedState.consent;
|
|
52
|
+
if (current === null ||
|
|
53
|
+
CONSENT_RESTRICTIVENESS[consent] < CONSENT_RESTRICTIVENESS[current]) {
|
|
54
|
+
analyticsSharedState.consent = consent;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The effective analytics consent status. `"granted"` when no client set one
|
|
59
|
+
* explicitly, preserving the legacy always-on behavior.
|
|
60
|
+
*
|
|
61
|
+
* @internal
|
|
62
|
+
*/
|
|
63
|
+
export function getAnalyticsConsentStatus() {
|
|
64
|
+
var _a;
|
|
65
|
+
return (_a = analyticsSharedState.consent) !== null && _a !== void 0 ? _a : "granted";
|
|
66
|
+
}
|
|
67
|
+
function clearPersistedAnalyticsSessionId() {
|
|
68
|
+
if (typeof window === "undefined")
|
|
69
|
+
return;
|
|
70
|
+
try {
|
|
71
|
+
localStorage.removeItem(ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY);
|
|
72
|
+
}
|
|
73
|
+
catch (_a) {
|
|
74
|
+
// Storage unavailable — nothing was persisted, so nothing to clear.
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthModule, options, }) => {
|
|
37
78
|
var _a;
|
|
79
|
+
// Consent gates more than this module: getAnalyticsSessionId() also backs
|
|
80
|
+
// the anonymous-id HTTP header and the socket handshake, so the client's
|
|
81
|
+
// consent choice must be recorded even when the early returns below make
|
|
82
|
+
// the module itself a no-op.
|
|
83
|
+
applyInitialConsent(options === null || options === void 0 ? void 0 : options.consent);
|
|
38
84
|
// prevent overflow of events //
|
|
39
85
|
const { maxQueueSize, throttleTime, batchSize } = analyticsSharedState.config;
|
|
40
86
|
// Disable analytics on React Native. It defines `window` but not `document`,
|
|
41
87
|
// so the per-callsite `typeof window` guards below aren't enough to keep it
|
|
42
88
|
// from touching `document` (e.g. `document.referrer` on init). Node/SSR is
|
|
43
89
|
// still handled by those `window` guards, so this doesn't affect it.
|
|
44
|
-
if (!((_a = analyticsSharedState.config) === null || _a === void 0 ? void 0 : _a.enabled) ||
|
|
90
|
+
if (!((_a = analyticsSharedState.config) === null || _a === void 0 ? void 0 : _a.enabled) ||
|
|
91
|
+
(options === null || options === void 0 ? void 0 : options.enabled) === false ||
|
|
92
|
+
isReactNative) {
|
|
45
93
|
return {
|
|
46
94
|
track: () => { },
|
|
95
|
+
// Consent still matters with the event pipeline off: it decides whether
|
|
96
|
+
// the persistent id may back the anonymous-id header and socket
|
|
97
|
+
// handshake, so opting in/out has to work here too.
|
|
98
|
+
optIn: () => {
|
|
99
|
+
analyticsSharedState.consent = "granted";
|
|
100
|
+
},
|
|
101
|
+
optOut: () => {
|
|
102
|
+
analyticsSharedState.consent = "denied";
|
|
103
|
+
clearPersistedAnalyticsSessionId();
|
|
104
|
+
},
|
|
105
|
+
getConsentStatus: getAnalyticsConsentStatus,
|
|
47
106
|
cleanup: () => { },
|
|
48
107
|
};
|
|
49
108
|
}
|
|
@@ -90,6 +149,12 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
|
|
|
90
149
|
});
|
|
91
150
|
};
|
|
92
151
|
const track = (params) => {
|
|
152
|
+
const consent = getAnalyticsConsentStatus();
|
|
153
|
+
// Denied: drop. Pending: buffer in memory (no network, no storage) so the
|
|
154
|
+
// events can be delivered if the visitor opts in later.
|
|
155
|
+
if (consent === "denied") {
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
93
158
|
if (analyticsSharedState.requestsQueue.length >= maxQueueSize) {
|
|
94
159
|
return;
|
|
95
160
|
}
|
|
@@ -98,7 +163,9 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
|
|
|
98
163
|
...params,
|
|
99
164
|
...intrinsicData,
|
|
100
165
|
});
|
|
101
|
-
|
|
166
|
+
if (consent === "granted") {
|
|
167
|
+
startProcessing();
|
|
168
|
+
}
|
|
102
169
|
};
|
|
103
170
|
const onDocVisible = () => {
|
|
104
171
|
startAnalyticsProcessor(flush, {
|
|
@@ -126,25 +193,66 @@ export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthM
|
|
|
126
193
|
onDocVisible();
|
|
127
194
|
}
|
|
128
195
|
};
|
|
129
|
-
|
|
196
|
+
// Everything with a side effect beyond this module — the persistent id,
|
|
197
|
+
// automatic events, timers, network — starts in activate(), so a client
|
|
198
|
+
// created with consent "pending" or "denied" stays fully dormant until the
|
|
199
|
+
// visitor opts in.
|
|
200
|
+
let isActive = false;
|
|
201
|
+
const activate = () => {
|
|
202
|
+
if (isActive)
|
|
203
|
+
return;
|
|
204
|
+
isActive = true;
|
|
205
|
+
// start the flusing process ///
|
|
206
|
+
startProcessing();
|
|
207
|
+
// start the heart beat processor //
|
|
208
|
+
clearHeartBeatProcessor = startHeartBeatProcessor(track);
|
|
209
|
+
// track the referrer event //
|
|
210
|
+
trackInitializationEvent(track);
|
|
211
|
+
// start the visibility change listener //
|
|
212
|
+
if (typeof window !== "undefined") {
|
|
213
|
+
window.addEventListener("visibilitychange", onVisibilityChange);
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
const deactivate = () => {
|
|
217
|
+
if (!isActive)
|
|
218
|
+
return;
|
|
219
|
+
isActive = false;
|
|
130
220
|
stopAnalyticsProcessor();
|
|
131
221
|
clearHeartBeatProcessor === null || clearHeartBeatProcessor === void 0 ? void 0 : clearHeartBeatProcessor();
|
|
222
|
+
clearHeartBeatProcessor = undefined;
|
|
132
223
|
if (typeof window !== "undefined") {
|
|
133
224
|
window.removeEventListener("visibilitychange", onVisibilityChange);
|
|
134
225
|
}
|
|
135
226
|
};
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
227
|
+
const optIn = () => {
|
|
228
|
+
analyticsSharedState.consent = "granted";
|
|
229
|
+
// Persist the id now rather than on the next event: this adopts the
|
|
230
|
+
// ephemeral pre-consent id (see getAnalyticsSessionId), keeping the
|
|
231
|
+
// visitor's identity continuous across the consent grant.
|
|
232
|
+
getAnalyticsSessionId();
|
|
233
|
+
activate();
|
|
234
|
+
};
|
|
235
|
+
const optOut = () => {
|
|
236
|
+
analyticsSharedState.consent = "denied";
|
|
237
|
+
deactivate();
|
|
238
|
+
// Drop anything buffered while consent was pending, and forget the
|
|
239
|
+
// identity: both the persisted id and the memoized session context.
|
|
240
|
+
analyticsSharedState.requestsQueue.length = 0;
|
|
241
|
+
analyticsSharedState.sessionStartTime = null;
|
|
242
|
+
resetAnalyticsSessionContext();
|
|
243
|
+
clearPersistedAnalyticsSessionId();
|
|
244
|
+
};
|
|
245
|
+
const cleanup = () => {
|
|
246
|
+
deactivate();
|
|
247
|
+
};
|
|
248
|
+
if (getAnalyticsConsentStatus() === "granted") {
|
|
249
|
+
activate();
|
|
145
250
|
}
|
|
146
251
|
return {
|
|
147
252
|
track,
|
|
253
|
+
optIn,
|
|
254
|
+
optOut,
|
|
255
|
+
getConsentStatus: getAnalyticsConsentStatus,
|
|
148
256
|
cleanup,
|
|
149
257
|
};
|
|
150
258
|
};
|
|
@@ -314,19 +422,29 @@ function getFallbackSessionId() {
|
|
|
314
422
|
return ((_a = analyticsSharedState.fallbackSessionId) !== null && _a !== void 0 ? _a : (analyticsSharedState.fallbackSessionId = generateUuid()));
|
|
315
423
|
}
|
|
316
424
|
export function getAnalyticsSessionId() {
|
|
425
|
+
var _a;
|
|
317
426
|
if (typeof window === "undefined") {
|
|
318
427
|
return getFallbackSessionId();
|
|
319
428
|
}
|
|
429
|
+
// Until consent is granted, never read or write the persistent id — hand out
|
|
430
|
+
// a per-page-load ephemeral id instead. The anonymous-id HTTP header and the
|
|
431
|
+
// socket handshake resolve their id through here too, so this single gate
|
|
432
|
+
// covers every place a persistent identifier could be minted pre-consent.
|
|
433
|
+
if (getAnalyticsConsentStatus() !== "granted") {
|
|
434
|
+
return getFallbackSessionId();
|
|
435
|
+
}
|
|
320
436
|
try {
|
|
321
437
|
const sessionId = localStorage.getItem(ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY);
|
|
322
438
|
if (!sessionId) {
|
|
323
|
-
|
|
439
|
+
// Adopt the ephemeral pre-consent id when one was handed out, so the
|
|
440
|
+
// visitor keeps a single identity across the consent grant.
|
|
441
|
+
const newSessionId = (_a = analyticsSharedState.fallbackSessionId) !== null && _a !== void 0 ? _a : generateUuid();
|
|
324
442
|
localStorage.setItem(ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY, newSessionId);
|
|
325
443
|
return newSessionId;
|
|
326
444
|
}
|
|
327
445
|
return sessionId;
|
|
328
446
|
}
|
|
329
|
-
catch (
|
|
447
|
+
catch (_b) {
|
|
330
448
|
return getFallbackSessionId();
|
|
331
449
|
}
|
|
332
450
|
}
|
|
@@ -67,6 +67,41 @@ export type AnalyticsModuleOptions = {
|
|
|
67
67
|
batchSize?: number;
|
|
68
68
|
heartBeatInterval?: number;
|
|
69
69
|
};
|
|
70
|
+
/**
|
|
71
|
+
* Consent status for analytics tracking.
|
|
72
|
+
*
|
|
73
|
+
* - `"granted"`: Analytics is fully active. The SDK persists a visitor ID in `localStorage`, sends automatic events, and delivers tracked events to the server.
|
|
74
|
+
* - `"pending"`: Analytics is dormant while waiting for a consent decision. No visitor ID is persisted and nothing is sent to the server. Events passed to {@linkcode AnalyticsModule.track | track()} are buffered in memory and delivered if consent is later granted with {@linkcode AnalyticsModule.optIn | optIn()}.
|
|
75
|
+
* - `"denied"`: Analytics is off. No visitor ID is persisted, nothing is sent to the server, and tracked events are discarded.
|
|
76
|
+
*/
|
|
77
|
+
export type AnalyticsConsentStatus = "granted" | "denied" | "pending";
|
|
78
|
+
/**
|
|
79
|
+
* Analytics configuration for {@linkcode createClient | createClient()}.
|
|
80
|
+
*
|
|
81
|
+
* Controls whether analytics runs and whether it waits for a consent decision before persisting a visitor ID or sending events.
|
|
82
|
+
*/
|
|
83
|
+
export type CreateClientAnalyticsOptions = {
|
|
84
|
+
/**
|
|
85
|
+
* Whether the analytics module is enabled.
|
|
86
|
+
*
|
|
87
|
+
* When `false`, {@linkcode AnalyticsModule.track | track()} is a no-op and no automatic events are sent, regardless of consent status.
|
|
88
|
+
*
|
|
89
|
+
* @defaultValue `true`
|
|
90
|
+
*/
|
|
91
|
+
enabled?: boolean;
|
|
92
|
+
/**
|
|
93
|
+
* Initial consent status for analytics.
|
|
94
|
+
*
|
|
95
|
+
* Defaults to `"granted"`, which preserves the SDK's original behavior: analytics starts as soon as the client is created.
|
|
96
|
+
*
|
|
97
|
+
* Set to `"pending"` when your app needs a consent decision (for example, from a cookie banner) before tracking starts. The client is still created immediately, but analytics stays dormant — no visitor ID is written to `localStorage`, no automatic events fire, and tracked events are buffered in memory. Call {@linkcode AnalyticsModule.optIn | optIn()} once consent is granted, or {@linkcode AnalyticsModule.optOut | optOut()} if it's refused.
|
|
98
|
+
*
|
|
99
|
+
* When multiple clients are created on the same page, the most restrictive explicitly-configured consent status wins (`"denied"` over `"pending"` over `"granted"`).
|
|
100
|
+
*
|
|
101
|
+
* @defaultValue `"granted"`
|
|
102
|
+
*/
|
|
103
|
+
consent?: AnalyticsConsentStatus;
|
|
104
|
+
};
|
|
70
105
|
/**
|
|
71
106
|
* Analytics module for tracking custom events in your app.
|
|
72
107
|
*
|
|
@@ -81,6 +116,10 @@ export type AnalyticsModuleOptions = {
|
|
|
81
116
|
* - Choose clear, descriptive event names in snake_case like `signup_button_click` or `purchase_completed` rather than generic names like `click`.
|
|
82
117
|
* - Include relevant context in your properties such as identifiers like `product_id`, measurements like `price`, and flags like `is_first_purchase`.
|
|
83
118
|
*
|
|
119
|
+
* ## Consent
|
|
120
|
+
*
|
|
121
|
+
* Apps that need a consent decision (for example, from a cookie banner) before tracking starts can create the client with `analytics: { consent: 'pending' }` and then call {@linkcode optIn | optIn()} or {@linkcode optOut | optOut()} once the visitor decides. See {@linkcode CreateClientAnalyticsOptions} for details.
|
|
122
|
+
*
|
|
84
123
|
* ## Authentication Modes
|
|
85
124
|
*
|
|
86
125
|
* This module is only available in user authentication mode (`base44.analytics`).
|
|
@@ -119,4 +158,56 @@ export interface AnalyticsModule {
|
|
|
119
158
|
* ```
|
|
120
159
|
*/
|
|
121
160
|
track(params: TrackEventParams): void;
|
|
161
|
+
/**
|
|
162
|
+
* Grants analytics consent and activates tracking.
|
|
163
|
+
*
|
|
164
|
+
* Use this after the visitor accepts analytics in your consent flow (for example, a cookie banner). It sets the consent status to `"granted"`, persists the visitor ID, starts automatic events, and delivers any events buffered while consent was `"pending"`.
|
|
165
|
+
*
|
|
166
|
+
* The visitor keeps a single identity across the consent grant: the temporary in-memory ID used before consent is adopted as the persistent ID.
|
|
167
|
+
*
|
|
168
|
+
* Calling this when consent is already `"granted"` has no effect.
|
|
169
|
+
*
|
|
170
|
+
* @example
|
|
171
|
+
* ```typescript
|
|
172
|
+
* // Create the client without tracking, then activate it once the
|
|
173
|
+
* // visitor accepts analytics in your consent banner.
|
|
174
|
+
* const base44 = createClient({
|
|
175
|
+
* appId: 'my-app-id',
|
|
176
|
+
* analytics: { consent: 'pending' }
|
|
177
|
+
* });
|
|
178
|
+
*
|
|
179
|
+
* onConsentBannerAccept(() => {
|
|
180
|
+
* base44.analytics.optIn();
|
|
181
|
+
* });
|
|
182
|
+
* ```
|
|
183
|
+
*/
|
|
184
|
+
optIn(): void;
|
|
185
|
+
/**
|
|
186
|
+
* Revokes analytics consent and deactivates tracking.
|
|
187
|
+
*
|
|
188
|
+
* Use this when the visitor declines analytics in your consent flow, or withdraws consent later. It sets the consent status to `"denied"`, stops automatic events, discards any buffered events, and removes the persistent visitor ID from `localStorage`.
|
|
189
|
+
*
|
|
190
|
+
* Tracking can be re-enabled later with {@linkcode optIn | optIn()}.
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```typescript
|
|
194
|
+
* onConsentBannerDecline(() => {
|
|
195
|
+
* base44.analytics.optOut();
|
|
196
|
+
* });
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
optOut(): void;
|
|
200
|
+
/**
|
|
201
|
+
* Gets the current analytics consent status.
|
|
202
|
+
*
|
|
203
|
+
* @returns The current consent status: `"granted"`, `"denied"`, or `"pending"`.
|
|
204
|
+
*
|
|
205
|
+
* @example
|
|
206
|
+
* ```typescript
|
|
207
|
+
* if (base44.analytics.getConsentStatus() === 'pending') {
|
|
208
|
+
* showConsentBanner();
|
|
209
|
+
* }
|
|
210
|
+
* ```
|
|
211
|
+
*/
|
|
212
|
+
getConsentStatus(): AnalyticsConsentStatus;
|
|
122
213
|
}
|
|
@@ -1,55 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The app's access policy: whether the app is reachable without an account, and
|
|
3
|
-
* who may sign in.
|
|
4
|
-
*/
|
|
5
|
-
export type AppPublicSettings = "private_with_login" | "public_with_login" | "public_without_login" | "workspace_with_login" | string;
|
|
6
|
-
/**
|
|
7
|
-
* The app's public configuration, as returned by {@link AppModule.getPublicSettings}.
|
|
8
|
-
*/
|
|
9
|
-
export interface AppPublicSettingsResponse {
|
|
10
|
-
/** The app's ID. */
|
|
11
|
-
id: string;
|
|
12
|
-
/** The app's access policy. */
|
|
13
|
-
public_settings: AppPublicSettings;
|
|
14
|
-
}
|
|
15
|
-
/**
|
|
16
|
-
* App module for reading the app's own public configuration.
|
|
17
|
-
*
|
|
18
|
-
* Use it to discover how the app is gated before rendering it, so a private app
|
|
19
|
-
* can send the visitor to login instead of rendering an empty shell.
|
|
20
|
-
*
|
|
21
|
-
* ## Authentication Modes
|
|
22
|
-
*
|
|
23
|
-
* This module is available to use with a client in all authentication modes. The
|
|
24
|
-
* client's token, when it has one, is sent with the request — a signed-in visitor
|
|
25
|
-
* who has no access to the app is reported differently from an anonymous one.
|
|
26
|
-
*/
|
|
27
|
-
export interface AppModule {
|
|
28
|
-
/**
|
|
29
|
-
* Get the app's public configuration.
|
|
30
|
-
*
|
|
31
|
-
* Rejects with a {@linkcode Base44Error} when the visitor may not open the app:
|
|
32
|
-
* `status` is `403` and `data.extra_data.reason` says why — `"auth_required"`
|
|
33
|
-
* when the visitor must sign in, `"user_not_registered"` when the signed-in
|
|
34
|
-
* visitor has no access to this app.
|
|
35
|
-
*
|
|
36
|
-
* @returns Promise resolving to the app's ID and access policy.
|
|
37
|
-
*
|
|
38
|
-
* @example
|
|
39
|
-
* ```typescript
|
|
40
|
-
* // Decide what to render before the app boots
|
|
41
|
-
* try {
|
|
42
|
-
* const { public_settings } = await base44.app.getPublicSettings();
|
|
43
|
-
* console.log('App access policy:', public_settings);
|
|
44
|
-
* } catch (error) {
|
|
45
|
-
* if (error.status === 403) {
|
|
46
|
-
* console.log('Blocked because:', error.data?.extra_data?.reason);
|
|
47
|
-
* }
|
|
48
|
-
* }
|
|
49
|
-
* ```
|
|
50
|
-
*/
|
|
51
|
-
getPublicSettings(): Promise<AppPublicSettingsResponse>;
|
|
52
|
-
}
|
|
53
1
|
/**
|
|
54
2
|
* @internal
|
|
55
3
|
*/
|
|
@@ -114,7 +62,7 @@ export interface AppLike {
|
|
|
114
62
|
agents?: Record<string, any>;
|
|
115
63
|
logo_url?: string;
|
|
116
64
|
slug?: string;
|
|
117
|
-
public_settings?:
|
|
65
|
+
public_settings?: "private_with_login" | "public_with_login" | "public_without_login" | "workspace_with_login" | string;
|
|
118
66
|
is_blocked?: boolean;
|
|
119
67
|
github_repo_url?: string;
|
|
120
68
|
main_page?: string;
|
package/package.json
CHANGED
package/dist/modules/app.d.ts
DELETED
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
import { AxiosInstance } from "axios";
|
|
2
|
-
import { AppModule } from "./app.types";
|
|
3
|
-
/**
|
|
4
|
-
* Creates the app module for the Base44 SDK.
|
|
5
|
-
*
|
|
6
|
-
* @param axios - Axios instance
|
|
7
|
-
* @param appId - Application ID
|
|
8
|
-
* @returns App module for reading the app's own configuration
|
|
9
|
-
* @internal
|
|
10
|
-
*/
|
|
11
|
-
export declare function createAppModule(axios: AxiosInstance, appId: string): AppModule;
|
package/dist/modules/app.js
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Creates the app module for the Base44 SDK.
|
|
3
|
-
*
|
|
4
|
-
* @param axios - Axios instance
|
|
5
|
-
* @param appId - Application ID
|
|
6
|
-
* @returns App module for reading the app's own configuration
|
|
7
|
-
* @internal
|
|
8
|
-
*/
|
|
9
|
-
export function createAppModule(axios, appId) {
|
|
10
|
-
return {
|
|
11
|
-
async getPublicSettings() {
|
|
12
|
-
return axios.get(`/apps/public/prod/public-settings/by-id/${appId}`);
|
|
13
|
-
},
|
|
14
|
-
};
|
|
15
|
-
}
|