@base44-preview/sdk 0.8.6-pr.58.9363801 → 0.8.7-pr.59.f9ae6aa
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 +15 -14
- package/dist/client.types.d.ts +3 -0
- package/dist/index.d.ts +1 -1
- package/dist/modules/analytics.d.ts +18 -0
- package/dist/modules/analytics.js +222 -0
- package/dist/modules/analytics.types.d.ts +42 -0
- package/dist/modules/analytics.types.js +1 -0
- package/dist/modules/entities.d.ts +0 -19
- package/dist/modules/entities.js +11 -100
- package/dist/modules/entities.types.d.ts +0 -124
- package/dist/modules/types.d.ts +1 -0
- package/dist/modules/types.js +1 -0
- package/dist/utils/common.d.ts +1 -0
- package/dist/utils/common.js +4 -0
- package/dist/utils/sharedInstance.d.ts +1 -0
- package/dist/utils/sharedInstance.js +15 -0
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -10,6 +10,7 @@ import { createAgentsModule } from "./modules/agents.js";
|
|
|
10
10
|
import { createAppLogsModule } from "./modules/app-logs.js";
|
|
11
11
|
import { createUsersModule } from "./modules/users.js";
|
|
12
12
|
import { RoomsSocket } from "./utils/socket-utils.js";
|
|
13
|
+
import { createAnalyticsModule } from "./modules/analytics.js";
|
|
13
14
|
/**
|
|
14
15
|
* Creates a Base44 client.
|
|
15
16
|
*
|
|
@@ -98,17 +99,14 @@ export function createClient(config) {
|
|
|
98
99
|
token: serviceToken,
|
|
99
100
|
interceptResponses: false,
|
|
100
101
|
});
|
|
102
|
+
const userAuthModule = createAuthModule(axiosClient, functionsAxiosClient, appId, {
|
|
103
|
+
appBaseUrl,
|
|
104
|
+
serverUrl,
|
|
105
|
+
});
|
|
101
106
|
const userModules = {
|
|
102
|
-
entities: createEntitiesModule(
|
|
103
|
-
axios: axiosClient,
|
|
104
|
-
appId,
|
|
105
|
-
getSocket,
|
|
106
|
-
}),
|
|
107
|
+
entities: createEntitiesModule(axiosClient, appId),
|
|
107
108
|
integrations: createIntegrationsModule(axiosClient, appId),
|
|
108
|
-
auth:
|
|
109
|
-
appBaseUrl,
|
|
110
|
-
serverUrl,
|
|
111
|
-
}),
|
|
109
|
+
auth: userAuthModule,
|
|
112
110
|
functions: createFunctionsModule(functionsAxiosClient, appId),
|
|
113
111
|
agents: createAgentsModule({
|
|
114
112
|
axios: axiosClient,
|
|
@@ -119,18 +117,21 @@ export function createClient(config) {
|
|
|
119
117
|
}),
|
|
120
118
|
appLogs: createAppLogsModule(axiosClient, appId),
|
|
121
119
|
users: createUsersModule(axiosClient, appId),
|
|
120
|
+
analytics: createAnalyticsModule({
|
|
121
|
+
axiosClient,
|
|
122
|
+
serverUrl,
|
|
123
|
+
appId,
|
|
124
|
+
userAuthModule,
|
|
125
|
+
}),
|
|
122
126
|
cleanup: () => {
|
|
127
|
+
userModules.analytics.cleanup();
|
|
123
128
|
if (socket) {
|
|
124
129
|
socket.disconnect();
|
|
125
130
|
}
|
|
126
131
|
},
|
|
127
132
|
};
|
|
128
133
|
const serviceRoleModules = {
|
|
129
|
-
entities: createEntitiesModule(
|
|
130
|
-
axios: serviceRoleAxiosClient,
|
|
131
|
-
appId,
|
|
132
|
-
getSocket,
|
|
133
|
-
}),
|
|
134
|
+
entities: createEntitiesModule(serviceRoleAxiosClient, appId),
|
|
134
135
|
integrations: createIntegrationsModule(serviceRoleAxiosClient, appId),
|
|
135
136
|
sso: createSsoModule(serviceRoleAxiosClient, appId, token),
|
|
136
137
|
connectors: createConnectorsModule(serviceRoleAxiosClient, appId),
|
package/dist/client.types.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type { ConnectorsModule } from "./modules/connectors.types.js";
|
|
|
6
6
|
import type { FunctionsModule } from "./modules/functions.types.js";
|
|
7
7
|
import type { AgentsModule } from "./modules/agents.types.js";
|
|
8
8
|
import type { AppLogsModule } from "./modules/app-logs.types.js";
|
|
9
|
+
import type { AnalyticsModule } from "./modules/analytics.types.js";
|
|
9
10
|
/**
|
|
10
11
|
* Options for creating a Base44 client.
|
|
11
12
|
*/
|
|
@@ -82,6 +83,8 @@ export interface Base44Client {
|
|
|
82
83
|
agents: AgentsModule;
|
|
83
84
|
/** {@link AppLogsModule | App logs module} for tracking app usage. */
|
|
84
85
|
appLogs: AppLogsModule;
|
|
86
|
+
/** {@link AnalyticsModule | Analytics module} for tracking app usage. */
|
|
87
|
+
analytics: AnalyticsModule;
|
|
85
88
|
/** Cleanup function to disconnect WebSocket connections. Call when you're done with the client. */
|
|
86
89
|
cleanup: () => void;
|
|
87
90
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl } from
|
|
|
4
4
|
export { createClient, createClientFromRequest, Base44Error, getAccessToken, saveAccessToken, removeAccessToken, getLoginUrl, };
|
|
5
5
|
export type { Base44Client, CreateClientConfig, CreateClientOptions, Base44ErrorJSON, };
|
|
6
6
|
export * from "./types.js";
|
|
7
|
-
export type { EntitiesModule, EntityHandler,
|
|
7
|
+
export type { EntitiesModule, EntityHandler, } from "./modules/entities.types.js";
|
|
8
8
|
export type { AuthModule, LoginResponse, RegisterParams, VerifyOtpParams, ChangePasswordParams, ResetPasswordParams, User, } from "./modules/auth.types.js";
|
|
9
9
|
export type { IntegrationsModule, IntegrationPackage, IntegrationEndpointFunction, CoreIntegrations, InvokeLLMParams, GenerateImageParams, GenerateImageResult, UploadFileParams, UploadFileResult, SendEmailParams, SendEmailResult, ExtractDataFromUploadedFileParams, ExtractDataFromUploadedFileResult, UploadPrivateFileParams, UploadPrivateFileResult, CreateFileSignedUrlParams, CreateFileSignedUrlResult, } from "./modules/integrations.types.js";
|
|
10
10
|
export type { FunctionsModule } from "./modules/functions.types.js";
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { AxiosInstance } from "axios";
|
|
2
|
+
import { TrackEventParams, AnalyticsModuleOptions } from "./analytics.types";
|
|
3
|
+
import type { AuthModule } from "./auth.types";
|
|
4
|
+
export declare const USER_HEARTBEAT_EVENT_NAME = "__user_heartbeat_event__";
|
|
5
|
+
export declare const ANALYTICS_CONFIG_URL_PARAM_KEY = "analytics-disable";
|
|
6
|
+
export declare const ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY = "base44_analytics_session_id";
|
|
7
|
+
export interface AnalyticsModuleArgs {
|
|
8
|
+
axiosClient: AxiosInstance;
|
|
9
|
+
serverUrl: string;
|
|
10
|
+
appId: string;
|
|
11
|
+
userAuthModule: AuthModule;
|
|
12
|
+
}
|
|
13
|
+
export declare const createAnalyticsModule: ({ axiosClient, serverUrl, appId, userAuthModule, }: AnalyticsModuleArgs) => {
|
|
14
|
+
track: (params: TrackEventParams) => void;
|
|
15
|
+
cleanup: () => void;
|
|
16
|
+
};
|
|
17
|
+
export declare function getAnalyticsConfigFromUrlParams(): AnalyticsModuleOptions | undefined;
|
|
18
|
+
export declare function getAnalyticsSessionId(): string;
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { getSharedInstance } from "../utils/sharedInstance";
|
|
2
|
+
import { generateUuid } from "../utils/common";
|
|
3
|
+
export const USER_HEARTBEAT_EVENT_NAME = "__user_heartbeat_event__";
|
|
4
|
+
export const ANALYTICS_CONFIG_URL_PARAM_KEY = "analytics-disable";
|
|
5
|
+
export const ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY = "base44_analytics_session_id";
|
|
6
|
+
const defaultConfiguration = {
|
|
7
|
+
enabled: true,
|
|
8
|
+
maxQueueSize: 1000,
|
|
9
|
+
throttleTime: 1000,
|
|
10
|
+
batchSize: 30,
|
|
11
|
+
heartBeatInterval: 60 * 1000,
|
|
12
|
+
};
|
|
13
|
+
///////////////////////////////////////////////
|
|
14
|
+
//// shared queue for analytics events ////
|
|
15
|
+
///////////////////////////////////////////////
|
|
16
|
+
const ANALYTICS_SHARED_STATE_NAME = "analytics";
|
|
17
|
+
// shared state//
|
|
18
|
+
const analyticsSharedState = getSharedInstance(ANALYTICS_SHARED_STATE_NAME, () => ({
|
|
19
|
+
requestsQueue: [],
|
|
20
|
+
isProcessing: false,
|
|
21
|
+
isHeartBeatProcessing: false,
|
|
22
|
+
sessionContext: null,
|
|
23
|
+
config: {
|
|
24
|
+
...defaultConfiguration,
|
|
25
|
+
...getAnalyticsConfigFromUrlParams(),
|
|
26
|
+
},
|
|
27
|
+
}));
|
|
28
|
+
export const createAnalyticsModule = ({ axiosClient, serverUrl, appId, userAuthModule, }) => {
|
|
29
|
+
var _a;
|
|
30
|
+
// prevent overflow of events //
|
|
31
|
+
const { maxQueueSize, throttleTime, batchSize } = analyticsSharedState.config;
|
|
32
|
+
if (!((_a = analyticsSharedState.config) === null || _a === void 0 ? void 0 : _a.enabled)) {
|
|
33
|
+
return {
|
|
34
|
+
track: () => { },
|
|
35
|
+
cleanup: () => { },
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
let clearHeartBeatProcessor = undefined;
|
|
39
|
+
const trackBatchUrl = `${serverUrl}/api/apps/${appId}/analytics/track/batch`;
|
|
40
|
+
const batchRequestFallback = async (events) => {
|
|
41
|
+
await axiosClient.request({
|
|
42
|
+
method: "POST",
|
|
43
|
+
url: `/apps/${appId}/analytics/track/batch`,
|
|
44
|
+
data: { events },
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
const beaconRequest = async (events) => {
|
|
48
|
+
const beaconPayload = JSON.stringify({ events });
|
|
49
|
+
try {
|
|
50
|
+
const blob = new Blob([beaconPayload], { type: "application/json" });
|
|
51
|
+
return (typeof navigator === "undefined" ||
|
|
52
|
+
beaconPayload.length > 60000 ||
|
|
53
|
+
!navigator.sendBeacon(trackBatchUrl, blob));
|
|
54
|
+
}
|
|
55
|
+
catch (_a) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
const flush = async (eventsData) => {
|
|
60
|
+
const sessionContext_ = await getSessionContext(userAuthModule);
|
|
61
|
+
const events = eventsData.map(transformEventDataToApiRequestData(sessionContext_));
|
|
62
|
+
if (!(await beaconRequest(events))) {
|
|
63
|
+
return batchRequestFallback(events);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
const startProcessing = () => {
|
|
67
|
+
startAnalyticsProcessor(flush, {
|
|
68
|
+
throttleTime,
|
|
69
|
+
batchSize,
|
|
70
|
+
});
|
|
71
|
+
};
|
|
72
|
+
const track = (params) => {
|
|
73
|
+
if (analyticsSharedState.requestsQueue.length >= maxQueueSize) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const intrinsicData = getEventIntrinsicData();
|
|
77
|
+
analyticsSharedState.requestsQueue.push({
|
|
78
|
+
...params,
|
|
79
|
+
...intrinsicData,
|
|
80
|
+
});
|
|
81
|
+
startProcessing();
|
|
82
|
+
};
|
|
83
|
+
const onDocVisible = () => {
|
|
84
|
+
startAnalyticsProcessor(flush, {
|
|
85
|
+
throttleTime,
|
|
86
|
+
batchSize,
|
|
87
|
+
});
|
|
88
|
+
clearHeartBeatProcessor = startHeartBeatProcessor(track);
|
|
89
|
+
};
|
|
90
|
+
const onDocHidden = () => {
|
|
91
|
+
stopAnalyticsProcessor();
|
|
92
|
+
// flush entire queue on visibility change and hope for the best //
|
|
93
|
+
const eventsData = analyticsSharedState.requestsQueue.splice(0);
|
|
94
|
+
flush(eventsData);
|
|
95
|
+
clearHeartBeatProcessor === null || clearHeartBeatProcessor === void 0 ? void 0 : clearHeartBeatProcessor();
|
|
96
|
+
};
|
|
97
|
+
const onVisibilityChange = () => {
|
|
98
|
+
if (typeof window === "undefined")
|
|
99
|
+
return;
|
|
100
|
+
if (document.visibilityState === "hidden") {
|
|
101
|
+
onDocHidden();
|
|
102
|
+
}
|
|
103
|
+
else if (document.visibilityState === "visible") {
|
|
104
|
+
onDocVisible();
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
const cleanup = () => {
|
|
108
|
+
stopAnalyticsProcessor();
|
|
109
|
+
clearHeartBeatProcessor === null || clearHeartBeatProcessor === void 0 ? void 0 : clearHeartBeatProcessor();
|
|
110
|
+
if (typeof window !== "undefined") {
|
|
111
|
+
window.removeEventListener("visibilitychange", onVisibilityChange);
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
// start the flusing process ///
|
|
115
|
+
startProcessing();
|
|
116
|
+
// start the heart beat processor //
|
|
117
|
+
clearHeartBeatProcessor = startHeartBeatProcessor(track);
|
|
118
|
+
// start the visibility change listener //
|
|
119
|
+
if (typeof window !== "undefined") {
|
|
120
|
+
window.addEventListener("visibilitychange", onVisibilityChange);
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
track,
|
|
124
|
+
cleanup,
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
function stopAnalyticsProcessor() {
|
|
128
|
+
analyticsSharedState.isProcessing = false;
|
|
129
|
+
}
|
|
130
|
+
async function startAnalyticsProcessor(handleTrack, options) {
|
|
131
|
+
if (analyticsSharedState.isProcessing) {
|
|
132
|
+
// only one instance of the analytics processor can be running at a time //
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
analyticsSharedState.isProcessing = true;
|
|
136
|
+
const { throttleTime = 1000, batchSize = 30 } = options !== null && options !== void 0 ? options : {};
|
|
137
|
+
while (analyticsSharedState.isProcessing &&
|
|
138
|
+
analyticsSharedState.requestsQueue.length > 0) {
|
|
139
|
+
const requests = analyticsSharedState.requestsQueue.splice(0, batchSize);
|
|
140
|
+
requests.length && (await handleTrack(requests));
|
|
141
|
+
await new Promise((resolve) => setTimeout(resolve, throttleTime));
|
|
142
|
+
}
|
|
143
|
+
analyticsSharedState.isProcessing = false;
|
|
144
|
+
}
|
|
145
|
+
function startHeartBeatProcessor(track) {
|
|
146
|
+
var _a;
|
|
147
|
+
if (analyticsSharedState.isHeartBeatProcessing ||
|
|
148
|
+
((_a = analyticsSharedState.config.heartBeatInterval) !== null && _a !== void 0 ? _a : 0) < 10) {
|
|
149
|
+
return () => { };
|
|
150
|
+
}
|
|
151
|
+
analyticsSharedState.isHeartBeatProcessing = true;
|
|
152
|
+
const interval = setInterval(() => {
|
|
153
|
+
track({ eventName: USER_HEARTBEAT_EVENT_NAME });
|
|
154
|
+
}, analyticsSharedState.config.heartBeatInterval);
|
|
155
|
+
return () => {
|
|
156
|
+
clearInterval(interval);
|
|
157
|
+
analyticsSharedState.isHeartBeatProcessing = false;
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
function getEventIntrinsicData() {
|
|
161
|
+
return {
|
|
162
|
+
timestamp: new Date().toISOString(),
|
|
163
|
+
pageUrl: typeof window !== "undefined" ? window.location.pathname : null,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
function transformEventDataToApiRequestData(sessionContext) {
|
|
167
|
+
return (eventData) => ({
|
|
168
|
+
event_name: eventData.eventName,
|
|
169
|
+
properties: eventData.properties,
|
|
170
|
+
timestamp: eventData.timestamp,
|
|
171
|
+
page_url: eventData.pageUrl,
|
|
172
|
+
...sessionContext,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
let sessionContextPromise = null;
|
|
176
|
+
async function getSessionContext(userAuthModule) {
|
|
177
|
+
if (!analyticsSharedState.sessionContext) {
|
|
178
|
+
if (!sessionContextPromise) {
|
|
179
|
+
const sessionId = getAnalyticsSessionId();
|
|
180
|
+
sessionContextPromise = userAuthModule
|
|
181
|
+
.me()
|
|
182
|
+
.then((user) => ({
|
|
183
|
+
user_id: user.id,
|
|
184
|
+
session_id: sessionId,
|
|
185
|
+
}))
|
|
186
|
+
.catch(() => ({
|
|
187
|
+
user_id: null,
|
|
188
|
+
session_id: sessionId,
|
|
189
|
+
}));
|
|
190
|
+
}
|
|
191
|
+
analyticsSharedState.sessionContext = await sessionContextPromise;
|
|
192
|
+
}
|
|
193
|
+
return analyticsSharedState.sessionContext;
|
|
194
|
+
}
|
|
195
|
+
export function getAnalyticsConfigFromUrlParams() {
|
|
196
|
+
if (typeof window === "undefined")
|
|
197
|
+
return undefined;
|
|
198
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
199
|
+
const analyticsDisable = urlParams.get(ANALYTICS_CONFIG_URL_PARAM_KEY);
|
|
200
|
+
const newUrlParams = new URLSearchParams(window.location.search);
|
|
201
|
+
newUrlParams.delete(ANALYTICS_CONFIG_URL_PARAM_KEY);
|
|
202
|
+
const newUrl = `${window.location.pathname}?${newUrlParams.toString()}`;
|
|
203
|
+
window.history.replaceState({}, document.title, newUrl);
|
|
204
|
+
return analyticsDisable === "true" ? { enabled: false } : undefined;
|
|
205
|
+
}
|
|
206
|
+
export function getAnalyticsSessionId() {
|
|
207
|
+
if (typeof window === "undefined") {
|
|
208
|
+
return generateUuid();
|
|
209
|
+
}
|
|
210
|
+
try {
|
|
211
|
+
const sessionId = localStorage.getItem(ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY);
|
|
212
|
+
if (!sessionId) {
|
|
213
|
+
const newSessionId = generateUuid();
|
|
214
|
+
localStorage.setItem(ANALYTICS_SESSION_ID_LOCAL_STORAGE_KEY, newSessionId);
|
|
215
|
+
return newSessionId;
|
|
216
|
+
}
|
|
217
|
+
return sessionId;
|
|
218
|
+
}
|
|
219
|
+
catch (_a) {
|
|
220
|
+
return generateUuid();
|
|
221
|
+
}
|
|
222
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export type TrackEventProperties = {
|
|
2
|
+
[key: string]: string | number | boolean | null | undefined;
|
|
3
|
+
};
|
|
4
|
+
export type TrackEventParams = {
|
|
5
|
+
eventName: string;
|
|
6
|
+
properties?: TrackEventProperties;
|
|
7
|
+
};
|
|
8
|
+
export type TrackEventIntrinsicData = {
|
|
9
|
+
timestamp: string;
|
|
10
|
+
pageUrl?: string | null;
|
|
11
|
+
};
|
|
12
|
+
export type TrackEventData = {
|
|
13
|
+
properties?: TrackEventProperties;
|
|
14
|
+
eventName: string;
|
|
15
|
+
} & TrackEventIntrinsicData;
|
|
16
|
+
export type SessionContext = {
|
|
17
|
+
user_id?: string | null;
|
|
18
|
+
session_id?: string | null;
|
|
19
|
+
};
|
|
20
|
+
export type AnalyticsApiRequestData = {
|
|
21
|
+
event_name: string;
|
|
22
|
+
properties?: TrackEventProperties;
|
|
23
|
+
timestamp?: string;
|
|
24
|
+
page_url?: string | null;
|
|
25
|
+
} & SessionContext;
|
|
26
|
+
export type AnalyticsApiBatchRequest = {
|
|
27
|
+
method: "POST";
|
|
28
|
+
url: `/apps/${string}/analytics/track/batch`;
|
|
29
|
+
data: {
|
|
30
|
+
events: AnalyticsApiRequestData[];
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
export type AnalyticsModuleOptions = {
|
|
34
|
+
enabled?: boolean;
|
|
35
|
+
maxQueueSize?: number;
|
|
36
|
+
throttleTime?: number;
|
|
37
|
+
batchSize?: number;
|
|
38
|
+
heartBeatInterval?: number;
|
|
39
|
+
};
|
|
40
|
+
export type AnalyticsModule = {
|
|
41
|
+
track: (params: TrackEventParams) => void;
|
|
42
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,23 +1,5 @@
|
|
|
1
1
|
import { AxiosInstance } from "axios";
|
|
2
2
|
import { EntitiesModule } from "./entities.types";
|
|
3
|
-
import { RoomsSocket } from "../utils/socket-utils";
|
|
4
|
-
/**
|
|
5
|
-
* Configuration for the entities module.
|
|
6
|
-
* @internal
|
|
7
|
-
*/
|
|
8
|
-
export interface EntitiesModuleConfig {
|
|
9
|
-
axios: AxiosInstance;
|
|
10
|
-
appId: string;
|
|
11
|
-
getSocket: () => ReturnType<typeof RoomsSocket>;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Creates the entities module for the Base44 SDK.
|
|
15
|
-
*
|
|
16
|
-
* @param config - Configuration object containing axios, appId, and getSocket
|
|
17
|
-
* @returns Entities module with dynamic entity access
|
|
18
|
-
* @internal
|
|
19
|
-
*/
|
|
20
|
-
export declare function createEntitiesModule(config: EntitiesModuleConfig): EntitiesModule;
|
|
21
3
|
/**
|
|
22
4
|
* Creates the entities module for the Base44 SDK.
|
|
23
5
|
*
|
|
@@ -25,6 +7,5 @@ export declare function createEntitiesModule(config: EntitiesModuleConfig): Enti
|
|
|
25
7
|
* @param appId - Application ID
|
|
26
8
|
* @returns Entities module with dynamic entity access
|
|
27
9
|
* @internal
|
|
28
|
-
* @deprecated Use the config object overload instead
|
|
29
10
|
*/
|
|
30
11
|
export declare function createEntitiesModule(axios: AxiosInstance, appId: string): EntitiesModule;
|
package/dist/modules/entities.js
CHANGED
|
@@ -1,15 +1,12 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
},
|
|
11
|
-
};
|
|
12
|
-
const { axios, appId, getSocket } = config;
|
|
1
|
+
/**
|
|
2
|
+
* Creates the entities module for the Base44 SDK.
|
|
3
|
+
*
|
|
4
|
+
* @param axios - Axios instance
|
|
5
|
+
* @param appId - Application ID
|
|
6
|
+
* @returns Entities module with dynamic entity access
|
|
7
|
+
* @internal
|
|
8
|
+
*/
|
|
9
|
+
export function createEntitiesModule(axios, appId) {
|
|
13
10
|
// Using Proxy to dynamically handle entity names
|
|
14
11
|
return new Proxy({}, {
|
|
15
12
|
get(target, entityName) {
|
|
@@ -20,59 +17,20 @@ export function createEntitiesModule(configOrAxios, appIdArg) {
|
|
|
20
17
|
return undefined;
|
|
21
18
|
}
|
|
22
19
|
// Create entity handler
|
|
23
|
-
return createEntityHandler(axios, appId, entityName
|
|
20
|
+
return createEntityHandler(axios, appId, entityName);
|
|
24
21
|
},
|
|
25
22
|
});
|
|
26
23
|
}
|
|
27
|
-
/**
|
|
28
|
-
* Creates a stable hash from a query object for room naming.
|
|
29
|
-
* @internal
|
|
30
|
-
*/
|
|
31
|
-
function hashQuery(query) {
|
|
32
|
-
const sortedKeys = Object.keys(query).sort();
|
|
33
|
-
const normalized = sortedKeys
|
|
34
|
-
.map((k) => `${k}:${JSON.stringify(query[k])}`)
|
|
35
|
-
.join("|");
|
|
36
|
-
// Simple hash function
|
|
37
|
-
let hash = 0;
|
|
38
|
-
for (let i = 0; i < normalized.length; i++) {
|
|
39
|
-
const char = normalized.charCodeAt(i);
|
|
40
|
-
hash = (hash << 5) - hash + char;
|
|
41
|
-
hash = hash & hash; // Convert to 32bit integer
|
|
42
|
-
}
|
|
43
|
-
return Math.abs(hash).toString(36);
|
|
44
|
-
}
|
|
45
|
-
/**
|
|
46
|
-
* Parses the realtime message data and extracts event information.
|
|
47
|
-
* @internal
|
|
48
|
-
*/
|
|
49
|
-
function parseRealtimeMessage(dataStr) {
|
|
50
|
-
var _a;
|
|
51
|
-
try {
|
|
52
|
-
const parsed = JSON.parse(dataStr);
|
|
53
|
-
return {
|
|
54
|
-
type: parsed.type,
|
|
55
|
-
data: parsed.data,
|
|
56
|
-
id: parsed.id || ((_a = parsed.data) === null || _a === void 0 ? void 0 : _a.id),
|
|
57
|
-
timestamp: parsed.timestamp || new Date().toISOString(),
|
|
58
|
-
previousData: parsed.previousData,
|
|
59
|
-
};
|
|
60
|
-
}
|
|
61
|
-
catch (_b) {
|
|
62
|
-
return null;
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
24
|
/**
|
|
66
25
|
* Creates a handler for a specific entity.
|
|
67
26
|
*
|
|
68
27
|
* @param axios - Axios instance
|
|
69
28
|
* @param appId - Application ID
|
|
70
29
|
* @param entityName - Entity name
|
|
71
|
-
* @param getSocket - Function to get the socket instance
|
|
72
30
|
* @returns Entity handler with CRUD methods
|
|
73
31
|
* @internal
|
|
74
32
|
*/
|
|
75
|
-
function createEntityHandler(axios, appId, entityName
|
|
33
|
+
function createEntityHandler(axios, appId, entityName) {
|
|
76
34
|
const baseURL = `/apps/${appId}/entities/${entityName}`;
|
|
77
35
|
return {
|
|
78
36
|
// List entities with optional pagination and sorting
|
|
@@ -137,52 +95,5 @@ function createEntityHandler(axios, appId, entityName, getSocket) {
|
|
|
137
95
|
},
|
|
138
96
|
});
|
|
139
97
|
},
|
|
140
|
-
// Subscribe to realtime updates
|
|
141
|
-
subscribe(callbackOrIdOrQuery, callbackOrOptions, optionsArg) {
|
|
142
|
-
let room;
|
|
143
|
-
let callback;
|
|
144
|
-
let options;
|
|
145
|
-
// Parse overloaded arguments
|
|
146
|
-
if (typeof callbackOrIdOrQuery === "function") {
|
|
147
|
-
// subscribe(callback, options?)
|
|
148
|
-
room = `entities:${appId}:${entityName}`;
|
|
149
|
-
callback = callbackOrIdOrQuery;
|
|
150
|
-
options = callbackOrOptions;
|
|
151
|
-
}
|
|
152
|
-
else if (typeof callbackOrIdOrQuery === "string") {
|
|
153
|
-
// subscribe(id, callback, options?)
|
|
154
|
-
room = `entities:${appId}:${entityName}:${callbackOrIdOrQuery}`;
|
|
155
|
-
callback = callbackOrOptions;
|
|
156
|
-
options = optionsArg;
|
|
157
|
-
}
|
|
158
|
-
else {
|
|
159
|
-
// subscribe(query, callback, options?)
|
|
160
|
-
const queryHash = hashQuery(callbackOrIdOrQuery);
|
|
161
|
-
room = `entities:${appId}:${entityName}:query:${queryHash}`;
|
|
162
|
-
callback = callbackOrOptions;
|
|
163
|
-
options = optionsArg;
|
|
164
|
-
}
|
|
165
|
-
const eventFilter = options === null || options === void 0 ? void 0 : options.events;
|
|
166
|
-
// Get the socket and subscribe to the room
|
|
167
|
-
const socket = getSocket();
|
|
168
|
-
const unsubscribe = socket.subscribeToRoom(room, {
|
|
169
|
-
update_model: (msg) => {
|
|
170
|
-
// Only process messages for our room
|
|
171
|
-
if (msg.room !== room)
|
|
172
|
-
return;
|
|
173
|
-
const event = parseRealtimeMessage(msg.data);
|
|
174
|
-
if (!event)
|
|
175
|
-
return;
|
|
176
|
-
// Apply event type filter if specified
|
|
177
|
-
if (eventFilter && !eventFilter.includes(event.type)) {
|
|
178
|
-
return;
|
|
179
|
-
}
|
|
180
|
-
callback(event);
|
|
181
|
-
},
|
|
182
|
-
});
|
|
183
|
-
return {
|
|
184
|
-
unsubscribe,
|
|
185
|
-
};
|
|
186
|
-
},
|
|
187
98
|
};
|
|
188
99
|
}
|
|
@@ -1,40 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Event types for realtime entity updates.
|
|
3
|
-
*/
|
|
4
|
-
export type RealtimeEventType = "create" | "update" | "delete";
|
|
5
|
-
/**
|
|
6
|
-
* Payload received when a realtime event occurs.
|
|
7
|
-
*/
|
|
8
|
-
export interface RealtimeEvent<T = Record<string, any>> {
|
|
9
|
-
/** The type of change that occurred */
|
|
10
|
-
type: RealtimeEventType;
|
|
11
|
-
/** The entity data (new/updated for create/update, previous for delete) */
|
|
12
|
-
data: T;
|
|
13
|
-
/** The unique identifier of the affected entity */
|
|
14
|
-
id: string;
|
|
15
|
-
/** ISO 8601 timestamp of when the event occurred */
|
|
16
|
-
timestamp: string;
|
|
17
|
-
/** For update events, contains the previous data before the change */
|
|
18
|
-
previousData?: T;
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Callback function invoked when a realtime event occurs.
|
|
22
|
-
*/
|
|
23
|
-
export type RealtimeCallback<T = Record<string, any>> = (event: RealtimeEvent<T>) => void;
|
|
24
|
-
/**
|
|
25
|
-
* Options for subscribing to realtime updates.
|
|
26
|
-
*/
|
|
27
|
-
export interface SubscribeOptions {
|
|
28
|
-
/** Filter events by type. Defaults to all types. */
|
|
29
|
-
events?: RealtimeEventType[];
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* Handle returned from subscribe, used to unsubscribe.
|
|
33
|
-
*/
|
|
34
|
-
export interface Subscription {
|
|
35
|
-
/** Stops listening to updates and cleans up the subscription. */
|
|
36
|
-
unsubscribe: () => void;
|
|
37
|
-
}
|
|
38
1
|
/**
|
|
39
2
|
* Entity handler providing CRUD operations for a specific entity type.
|
|
40
3
|
*
|
|
@@ -279,93 +242,6 @@ export interface EntityHandler {
|
|
|
279
242
|
* ```
|
|
280
243
|
*/
|
|
281
244
|
importEntities(file: File): Promise<any>;
|
|
282
|
-
/**
|
|
283
|
-
* Subscribes to realtime updates for all records of this entity type.
|
|
284
|
-
*
|
|
285
|
-
* Receives notifications whenever any record is created, updated, or deleted.
|
|
286
|
-
*
|
|
287
|
-
* @param callback - Function called when an entity changes.
|
|
288
|
-
* @param options - Optional configuration for filtering events.
|
|
289
|
-
* @returns Subscription handle with an unsubscribe method.
|
|
290
|
-
*
|
|
291
|
-
* @example
|
|
292
|
-
* ```typescript
|
|
293
|
-
* // Subscribe to all Task changes
|
|
294
|
-
* const subscription = base44.entities.Task.subscribe((event) => {
|
|
295
|
-
* console.log(`Task ${event.id} was ${event.type}d:`, event.data);
|
|
296
|
-
* });
|
|
297
|
-
*
|
|
298
|
-
* // Later, unsubscribe
|
|
299
|
-
* subscription.unsubscribe();
|
|
300
|
-
* ```
|
|
301
|
-
*
|
|
302
|
-
* @example
|
|
303
|
-
* ```typescript
|
|
304
|
-
* // Subscribe only to create events
|
|
305
|
-
* const subscription = base44.entities.Task.subscribe(
|
|
306
|
-
* (event) => console.log("New task:", event.data),
|
|
307
|
-
* { events: ["create"] }
|
|
308
|
-
* );
|
|
309
|
-
* ```
|
|
310
|
-
*/
|
|
311
|
-
subscribe(callback: RealtimeCallback, options?: SubscribeOptions): Subscription;
|
|
312
|
-
/**
|
|
313
|
-
* Subscribes to realtime updates for a specific entity record.
|
|
314
|
-
*
|
|
315
|
-
* Receives notifications when the specified record is updated or deleted.
|
|
316
|
-
*
|
|
317
|
-
* @param id - The unique identifier of the record to watch.
|
|
318
|
-
* @param callback - Function called when the entity changes.
|
|
319
|
-
* @param options - Optional configuration for filtering events.
|
|
320
|
-
* @returns Subscription handle with an unsubscribe method.
|
|
321
|
-
*
|
|
322
|
-
* @example
|
|
323
|
-
* ```typescript
|
|
324
|
-
* // Subscribe to a specific task
|
|
325
|
-
* const subscription = base44.entities.Task.subscribe("task-123", (event) => {
|
|
326
|
-
* if (event.type === "update") {
|
|
327
|
-
* console.log("Task updated:", event.data);
|
|
328
|
-
* } else if (event.type === "delete") {
|
|
329
|
-
* console.log("Task was deleted");
|
|
330
|
-
* }
|
|
331
|
-
* });
|
|
332
|
-
* ```
|
|
333
|
-
*/
|
|
334
|
-
subscribe(id: string, callback: RealtimeCallback, options?: SubscribeOptions): Subscription;
|
|
335
|
-
/**
|
|
336
|
-
* Subscribes to realtime updates for records matching a query.
|
|
337
|
-
*
|
|
338
|
-
* Receives notifications for records that match the specified criteria.
|
|
339
|
-
* Includes create events when new records match the query, update events
|
|
340
|
-
* when matching records change, and delete events when matching records
|
|
341
|
-
* are removed.
|
|
342
|
-
*
|
|
343
|
-
* @param query - Query object with field-value pairs to filter records.
|
|
344
|
-
* @param callback - Function called when a matching entity changes.
|
|
345
|
-
* @param options - Optional configuration for filtering events.
|
|
346
|
-
* @returns Subscription handle with an unsubscribe method.
|
|
347
|
-
*
|
|
348
|
-
* @example
|
|
349
|
-
* ```typescript
|
|
350
|
-
* // Subscribe to all completed tasks
|
|
351
|
-
* const subscription = base44.entities.Task.subscribe(
|
|
352
|
-
* { isCompleted: true },
|
|
353
|
-
* (event) => {
|
|
354
|
-
* console.log(`Completed task ${event.type}:`, event.data);
|
|
355
|
-
* }
|
|
356
|
-
* );
|
|
357
|
-
* ```
|
|
358
|
-
*
|
|
359
|
-
* @example
|
|
360
|
-
* ```typescript
|
|
361
|
-
* // Subscribe to high-priority active tasks
|
|
362
|
-
* const subscription = base44.entities.Task.subscribe(
|
|
363
|
-
* { priority: "high", status: "active" },
|
|
364
|
-
* (event) => console.log("High priority task changed:", event.data)
|
|
365
|
-
* );
|
|
366
|
-
* ```
|
|
367
|
-
*/
|
|
368
|
-
subscribe(query: Record<string, any>, callback: RealtimeCallback, options?: SubscribeOptions): Subscription;
|
|
369
245
|
}
|
|
370
246
|
/**
|
|
371
247
|
* Entities module for managing app data.
|
package/dist/modules/types.d.ts
CHANGED
package/dist/modules/types.js
CHANGED
package/dist/utils/common.d.ts
CHANGED
package/dist/utils/common.js
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getSharedInstance<T>(name: string, factory: () => T): T;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
const windowObj = typeof window !== "undefined"
|
|
2
|
+
? window
|
|
3
|
+
: { base44SharedInstances: {} };
|
|
4
|
+
// Singleton (shared between sdk instances)//
|
|
5
|
+
export function getSharedInstance(name, factory) {
|
|
6
|
+
if (!windowObj.base44SharedInstances) {
|
|
7
|
+
windowObj.base44SharedInstances = {};
|
|
8
|
+
}
|
|
9
|
+
if (!windowObj.base44SharedInstances[name]) {
|
|
10
|
+
windowObj.base44SharedInstances[name] = {
|
|
11
|
+
instance: factory(),
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
return windowObj.base44SharedInstances[name].instance;
|
|
15
|
+
}
|