@doany-ai/sdk 0.1.0

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.
Files changed (75) hide show
  1. package/LICENSE +22 -0
  2. package/README.md +60 -0
  3. package/dist/client.d.ts +96 -0
  4. package/dist/client.js +395 -0
  5. package/dist/client.types.d.ts +149 -0
  6. package/dist/client.types.js +1 -0
  7. package/dist/index.d.ts +17 -0
  8. package/dist/index.js +5 -0
  9. package/dist/modules/agents.d.ts +2 -0
  10. package/dist/modules/agents.js +89 -0
  11. package/dist/modules/agents.types.d.ts +397 -0
  12. package/dist/modules/agents.types.js +1 -0
  13. package/dist/modules/ai-gateway.d.ts +2 -0
  14. package/dist/modules/ai-gateway.js +13 -0
  15. package/dist/modules/ai-gateway.types.d.ts +88 -0
  16. package/dist/modules/ai-gateway.types.js +1 -0
  17. package/dist/modules/analytics.d.ts +20 -0
  18. package/dist/modules/analytics.js +284 -0
  19. package/dist/modules/analytics.types.d.ts +122 -0
  20. package/dist/modules/analytics.types.js +1 -0
  21. package/dist/modules/app-logs.d.ts +11 -0
  22. package/dist/modules/app-logs.js +27 -0
  23. package/dist/modules/app-logs.types.d.ts +46 -0
  24. package/dist/modules/app-logs.types.js +1 -0
  25. package/dist/modules/app.types.d.ts +142 -0
  26. package/dist/modules/app.types.js +1 -0
  27. package/dist/modules/auth.d.ts +13 -0
  28. package/dist/modules/auth.js +240 -0
  29. package/dist/modules/auth.types.d.ts +517 -0
  30. package/dist/modules/auth.types.js +1 -0
  31. package/dist/modules/connectors.d.ts +20 -0
  32. package/dist/modules/connectors.js +98 -0
  33. package/dist/modules/connectors.types.d.ts +376 -0
  34. package/dist/modules/connectors.types.js +1 -0
  35. package/dist/modules/custom-integrations.d.ts +11 -0
  36. package/dist/modules/custom-integrations.js +32 -0
  37. package/dist/modules/custom-integrations.types.d.ts +89 -0
  38. package/dist/modules/custom-integrations.types.js +1 -0
  39. package/dist/modules/entities.d.ts +20 -0
  40. package/dist/modules/entities.js +163 -0
  41. package/dist/modules/entities.types.d.ts +702 -0
  42. package/dist/modules/entities.types.js +1 -0
  43. package/dist/modules/functions.d.ts +12 -0
  44. package/dist/modules/functions.js +79 -0
  45. package/dist/modules/functions.types.d.ts +150 -0
  46. package/dist/modules/functions.types.js +1 -0
  47. package/dist/modules/integrations.d.ts +11 -0
  48. package/dist/modules/integrations.js +77 -0
  49. package/dist/modules/integrations.types.d.ts +418 -0
  50. package/dist/modules/integrations.types.js +1 -0
  51. package/dist/modules/sso.d.ts +11 -0
  52. package/dist/modules/sso.js +22 -0
  53. package/dist/modules/sso.types.d.ts +68 -0
  54. package/dist/modules/sso.types.js +1 -0
  55. package/dist/modules/types.d.ts +5 -0
  56. package/dist/modules/types.js +5 -0
  57. package/dist/modules/users.d.ts +16 -0
  58. package/dist/modules/users.js +23 -0
  59. package/dist/types.d.ts +72 -0
  60. package/dist/types.js +1 -0
  61. package/dist/utils/auth-utils.d.ts +117 -0
  62. package/dist/utils/auth-utils.js +189 -0
  63. package/dist/utils/auth-utils.types.d.ts +146 -0
  64. package/dist/utils/auth-utils.types.js +1 -0
  65. package/dist/utils/axios-client.d.ts +100 -0
  66. package/dist/utils/axios-client.js +202 -0
  67. package/dist/utils/axios-client.types.d.ts +28 -0
  68. package/dist/utils/axios-client.types.js +1 -0
  69. package/dist/utils/common.d.ts +4 -0
  70. package/dist/utils/common.js +11 -0
  71. package/dist/utils/sharedInstance.d.ts +1 -0
  72. package/dist/utils/sharedInstance.js +15 -0
  73. package/dist/utils/socket-utils.d.ts +47 -0
  74. package/dist/utils/socket-utils.js +170 -0
  75. package/package.json +54 -0
package/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 base44
4
+ Copyright (c) 2026 doany
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # @doany-ai/sdk
2
+
3
+ JavaScript/TypeScript SDK for the doany app platform.
4
+
5
+ This is an API-compatible MIT fork of [`@base44/sdk`](https://github.com/base44/javascript-sdk).
6
+ Only the package name and the default `serverUrl` have changed — the wire contract
7
+ (endpoints, headers, auth flow, storage keys) is byte-identical, so the official
8
+ `@base44/sdk` also works against a doany backend by pointing its `serverUrl` at it.
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm i @doany-ai/sdk
14
+ ```
15
+
16
+ ## Quickstart
17
+
18
+ ```js
19
+ import { createClient } from '@doany-ai/sdk';
20
+
21
+ // Defaults to serverUrl: https://api.doany.ai
22
+ const client = createClient({
23
+ appId: 'your-app-id',
24
+ });
25
+
26
+ // Entities: CRUD on your app's data
27
+ const products = await client.entities.Products.list();
28
+ await client.entities.Products.create({ name: 'Widget', price: 9.99 });
29
+
30
+ // Auth: current user
31
+ const me = await client.auth.me();
32
+ ```
33
+
34
+ For local development, override the server URL:
35
+
36
+ ```js
37
+ const client = createClient({
38
+ appId: 'your-app-id',
39
+ serverUrl: 'http://localhost:8000',
40
+ });
41
+ ```
42
+
43
+ ## Modules
44
+
45
+ - `entities` — CRUD, filtering, realtime subscriptions
46
+ - `auth` — login, tokens, current user
47
+ - `users` — user management
48
+ - `integrations` — built-in integrations
49
+ - `connectors` — third-party connectors
50
+ - `functions` — invoke backend functions
51
+ - `agents` — agent conversations
52
+ - `aiGateway` — AI gateway (LLM calls)
53
+ - `analytics` — analytics events
54
+ - `appLogs` — app logging
55
+ - `sso` — single sign-on
56
+ - `asServiceRole` — service-role scoped client
57
+
58
+ ## License
59
+
60
+ MIT — see [LICENSE](./LICENSE).
@@ -0,0 +1,96 @@
1
+ import type { Base44Client, CreateClientConfig, CreateClientOptions } from "./client.types.js";
2
+ export type { Base44Client, CreateClientConfig, CreateClientOptions };
3
+ /**
4
+ * Creates a Base44 client.
5
+ *
6
+ * This is the main entry point for the Base44 SDK. It creates a client that provides access to the SDK's modules, such as {@linkcode EntitiesModule | entities}, {@linkcode AuthModule | auth}, and {@linkcode FunctionsModule | functions}.
7
+ *
8
+ * How you get a client depends on your context:
9
+ * - **Inside a Base44 app:** The client is automatically created and configured for you. Import it from `@/api/base44Client`.
10
+ * - **External app using Base44 as a backend:** Call `createClient()` directly in your code to create and configure the client.
11
+ *
12
+ * The client supports three authentication modes:
13
+ * - **Anonymous**: Access modules without authentication using `base44.moduleName`. Operations are scoped to public data and permissions.
14
+ * - **User authentication**: Access modules with user-level permissions using `base44.moduleName`. Operations are scoped to the authenticated user's data and permissions. Use `base44.auth.loginViaEmailPassword()` or other auth methods to get a token.
15
+ * - **Service role authentication**: Access modules with elevated permissions using `base44.asServiceRole.moduleName`. Operations bypass entity access rules and field-level security, giving full read and write access to all of the app's data. Only available in Base44-hosted backend functions. Create a client with service role authentication using {@linkcode createClientFromRequest | createClientFromRequest()}.
16
+ *
17
+ * For example, when using the {@linkcode EntitiesModule | entities} module:
18
+ * - **Anonymous**: Can only read public data.
19
+ * - **User authentication**: Can access the current user's data.
20
+ * - **Service role authentication**: Can read and write any record, bypassing access rules.
21
+ *
22
+ * Most modules are available in all three modes, but with different permission levels. However, some modules are only available in specific authentication modes.
23
+ *
24
+ * @param config - Configuration object for the client.
25
+ * @returns A configured Base44 client instance with access to all SDK modules.
26
+ *
27
+ * @example
28
+ * ```typescript
29
+ * // Create a client for your app
30
+ * import { createClient } from '@base44/sdk';
31
+ *
32
+ * const base44 = createClient({
33
+ * appId: 'my-app-id'
34
+ * });
35
+ *
36
+ * // Use the client to access your data
37
+ * const products = await base44.entities.Products.list();
38
+ * ```
39
+ */
40
+ export declare function createClient(config: CreateClientConfig): Base44Client;
41
+ /**
42
+ * Creates a Base44 client from an HTTP request.
43
+ *
44
+ * This function is designed for use in Base44-hosted backend functions. For frontends and external backends, use {@linkcode createClient | createClient()} instead.
45
+ *
46
+ * When used in a Base44-hosted backend function, `createClientFromRequest()` automatically extracts authentication tokens from the request headers that Base44 injects when forwarding requests. The returned client includes service role access using `base44.asServiceRole`, which bypasses entity access rules and field-level security.
47
+ *
48
+ * To learn more about the Base44 client, see {@linkcode createClient | createClient()}.
49
+ *
50
+ * @param request - The incoming HTTP request object containing Base44 authentication headers.
51
+ * @returns A configured Base44 client instance with authentication from the incoming request.
52
+ *
53
+ * @example
54
+ * ```typescript
55
+ * // User authentication in backend function
56
+ * import { createClientFromRequest } from 'npm:@base44/sdk';
57
+ *
58
+ * Deno.serve(async (req) => {
59
+ * try {
60
+ * const base44 = createClientFromRequest(req);
61
+ * const user = await base44.auth.me();
62
+ *
63
+ * if (!user) {
64
+ * return Response.json({ error: 'Unauthorized' }, { status: 401 });
65
+ * }
66
+ *
67
+ * // Access user's data
68
+ * const userOrders = await base44.entities.Orders.filter({ userId: user.id });
69
+ * return Response.json({ orders: userOrders });
70
+ * } catch (error) {
71
+ * return Response.json({ error: error.message }, { status: 500 });
72
+ * }
73
+ * });
74
+ * ```
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * // Service role authentication in backend function
79
+ * import { createClientFromRequest } from 'npm:@base44/sdk';
80
+ *
81
+ * Deno.serve(async (req) => {
82
+ * try {
83
+ * const base44 = createClientFromRequest(req);
84
+ *
85
+ * // Read across all users, bypassing the Orders entity's access rules
86
+ * const recentOrders = await base44.asServiceRole.entities.Orders.list('-created_at', 50);
87
+ *
88
+ * return Response.json({ orders: recentOrders });
89
+ * } catch (error) {
90
+ * return Response.json({ error: error.message }, { status: 500 });
91
+ * }
92
+ * });
93
+ * ```
94
+ *
95
+ */
96
+ export declare function createClientFromRequest(request: Request): Base44Client;
package/dist/client.js ADDED
@@ -0,0 +1,395 @@
1
+ import { createAxiosClient } from "./utils/axios-client.js";
2
+ import { createEntitiesModule } from "./modules/entities.js";
3
+ import { createIntegrationsModule } from "./modules/integrations.js";
4
+ import { createAuthModule } from "./modules/auth.js";
5
+ import { createSsoModule } from "./modules/sso.js";
6
+ import { createConnectorsModule, createUserConnectorsModule, } from "./modules/connectors.js";
7
+ import { getAccessToken } from "./utils/auth-utils.js";
8
+ import { createFunctionsModule } from "./modules/functions.js";
9
+ import { createAgentsModule } from "./modules/agents.js";
10
+ import { createAiGatewayModule } from "./modules/ai-gateway.js";
11
+ import { createAppLogsModule } from "./modules/app-logs.js";
12
+ import { createUsersModule } from "./modules/users.js";
13
+ import { RoomsSocket } from "./utils/socket-utils.js";
14
+ import { createAnalyticsModule } from "./modules/analytics.js";
15
+ /**
16
+ * Creates a Base44 client.
17
+ *
18
+ * This is the main entry point for the Base44 SDK. It creates a client that provides access to the SDK's modules, such as {@linkcode EntitiesModule | entities}, {@linkcode AuthModule | auth}, and {@linkcode FunctionsModule | functions}.
19
+ *
20
+ * How you get a client depends on your context:
21
+ * - **Inside a Base44 app:** The client is automatically created and configured for you. Import it from `@/api/base44Client`.
22
+ * - **External app using Base44 as a backend:** Call `createClient()` directly in your code to create and configure the client.
23
+ *
24
+ * The client supports three authentication modes:
25
+ * - **Anonymous**: Access modules without authentication using `base44.moduleName`. Operations are scoped to public data and permissions.
26
+ * - **User authentication**: Access modules with user-level permissions using `base44.moduleName`. Operations are scoped to the authenticated user's data and permissions. Use `base44.auth.loginViaEmailPassword()` or other auth methods to get a token.
27
+ * - **Service role authentication**: Access modules with elevated permissions using `base44.asServiceRole.moduleName`. Operations bypass entity access rules and field-level security, giving full read and write access to all of the app's data. Only available in Base44-hosted backend functions. Create a client with service role authentication using {@linkcode createClientFromRequest | createClientFromRequest()}.
28
+ *
29
+ * For example, when using the {@linkcode EntitiesModule | entities} module:
30
+ * - **Anonymous**: Can only read public data.
31
+ * - **User authentication**: Can access the current user's data.
32
+ * - **Service role authentication**: Can read and write any record, bypassing access rules.
33
+ *
34
+ * Most modules are available in all three modes, but with different permission levels. However, some modules are only available in specific authentication modes.
35
+ *
36
+ * @param config - Configuration object for the client.
37
+ * @returns A configured Base44 client instance with access to all SDK modules.
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * // Create a client for your app
42
+ * import { createClient } from '@base44/sdk';
43
+ *
44
+ * const base44 = createClient({
45
+ * appId: 'my-app-id'
46
+ * });
47
+ *
48
+ * // Use the client to access your data
49
+ * const products = await base44.entities.Products.list();
50
+ * ```
51
+ */
52
+ export function createClient(config) {
53
+ var _a, _b;
54
+ const { serverUrl = "https://api.doany.ai", appId, token, serviceToken, requiresAuth = false, appBaseUrl, options, functionsVersion, headers: optionalHeaders, } = config;
55
+ // Normalize appBaseUrl to always be a string (empty if not provided or invalid)
56
+ const normalizedAppBaseUrl = typeof appBaseUrl === "string" ? appBaseUrl : "";
57
+ const socketConfig = {
58
+ serverUrl,
59
+ mountPath: "/ws-user-apps/socket.io/",
60
+ transports: ["websocket"],
61
+ appId,
62
+ token,
63
+ };
64
+ let socket = null;
65
+ const getSocket = () => {
66
+ if (!socket) {
67
+ socket = RoomsSocket({
68
+ config: socketConfig,
69
+ });
70
+ }
71
+ return socket;
72
+ };
73
+ const headers = {
74
+ ...optionalHeaders,
75
+ "X-App-Id": String(appId),
76
+ };
77
+ const functionHeaders = functionsVersion
78
+ ? {
79
+ ...headers,
80
+ "Base44-Functions-Version": functionsVersion,
81
+ }
82
+ : headers;
83
+ const axiosClient = createAxiosClient({
84
+ baseURL: `${serverUrl}/api`,
85
+ headers,
86
+ token,
87
+ onError: options === null || options === void 0 ? void 0 : options.onError,
88
+ });
89
+ const functionsAxiosClient = createAxiosClient({
90
+ baseURL: `${serverUrl}/api`,
91
+ headers: functionHeaders,
92
+ token,
93
+ interceptResponses: false,
94
+ onError: options === null || options === void 0 ? void 0 : options.onError,
95
+ });
96
+ const serviceRoleHeaders = {
97
+ ...headers,
98
+ ...(token ? { "on-behalf-of": `Bearer ${token}` } : {}),
99
+ };
100
+ const serviceRoleAxiosClient = createAxiosClient({
101
+ baseURL: `${serverUrl}/api`,
102
+ headers: serviceRoleHeaders,
103
+ token: serviceToken,
104
+ onError: options === null || options === void 0 ? void 0 : options.onError,
105
+ });
106
+ const serviceRoleFunctionsAxiosClient = createAxiosClient({
107
+ baseURL: `${serverUrl}/api`,
108
+ headers: functionHeaders,
109
+ token: serviceToken,
110
+ interceptResponses: false,
111
+ });
112
+ const userAuthModule = createAuthModule(axiosClient, functionsAxiosClient, appId, {
113
+ appBaseUrl: normalizedAppBaseUrl,
114
+ serverUrl,
115
+ });
116
+ // Apply the access token before any module that may issue authenticated
117
+ // requests during construction (notably analytics, which fires an init
118
+ // event whose flush calls auth.me()). Without this, the first User/me
119
+ // request is built before setToken runs and goes out unauthenticated.
120
+ if (typeof window !== "undefined") {
121
+ const accessToken = token || getAccessToken();
122
+ if (accessToken) {
123
+ userAuthModule.setToken(accessToken);
124
+ }
125
+ }
126
+ const userModules = {
127
+ entities: createEntitiesModule({
128
+ axios: axiosClient,
129
+ appId,
130
+ getSocket,
131
+ }),
132
+ integrations: createIntegrationsModule(axiosClient, appId),
133
+ connectors: createUserConnectorsModule(axiosClient, appId),
134
+ auth: userAuthModule,
135
+ functions: createFunctionsModule(functionsAxiosClient, appId, {
136
+ getAuthHeaders: () => {
137
+ const headers = {};
138
+ // Get current token from storage or initial config
139
+ const currentToken = token || getAccessToken();
140
+ if (currentToken) {
141
+ headers["Authorization"] = `Bearer ${currentToken}`;
142
+ }
143
+ return headers;
144
+ },
145
+ baseURL: (_a = functionsAxiosClient.defaults) === null || _a === void 0 ? void 0 : _a.baseURL,
146
+ }),
147
+ agents: createAgentsModule({
148
+ axios: axiosClient,
149
+ getSocket,
150
+ appId,
151
+ serverUrl,
152
+ token,
153
+ }),
154
+ aiGateway: createAiGatewayModule({ serverUrl, token, appId }),
155
+ appLogs: createAppLogsModule(axiosClient, appId),
156
+ users: createUsersModule(axiosClient, appId),
157
+ analytics: createAnalyticsModule({
158
+ axiosClient,
159
+ serverUrl,
160
+ appId,
161
+ userAuthModule,
162
+ }),
163
+ cleanup: () => {
164
+ userModules.analytics.cleanup();
165
+ if (socket) {
166
+ socket.disconnect();
167
+ }
168
+ },
169
+ };
170
+ const serviceRoleModules = {
171
+ entities: createEntitiesModule({
172
+ axios: serviceRoleAxiosClient,
173
+ appId,
174
+ getSocket,
175
+ }),
176
+ integrations: createIntegrationsModule(serviceRoleAxiosClient, appId),
177
+ sso: createSsoModule(serviceRoleAxiosClient, appId),
178
+ connectors: createConnectorsModule(serviceRoleAxiosClient, appId),
179
+ functions: createFunctionsModule(serviceRoleFunctionsAxiosClient, appId, {
180
+ getAuthHeaders: () => {
181
+ const headers = {};
182
+ // Use service token for authorization
183
+ if (serviceToken) {
184
+ headers["Authorization"] = `Bearer ${serviceToken}`;
185
+ }
186
+ return headers;
187
+ },
188
+ baseURL: (_b = serviceRoleFunctionsAxiosClient.defaults) === null || _b === void 0 ? void 0 : _b.baseURL,
189
+ }),
190
+ agents: createAgentsModule({
191
+ axios: serviceRoleAxiosClient,
192
+ getSocket,
193
+ appId,
194
+ serverUrl,
195
+ token,
196
+ }),
197
+ aiGateway: createAiGatewayModule({ serverUrl, token: serviceToken, appId }),
198
+ appLogs: createAppLogsModule(serviceRoleAxiosClient, appId),
199
+ cleanup: () => {
200
+ if (socket) {
201
+ socket.disconnect();
202
+ }
203
+ },
204
+ };
205
+ // If authentication is required, verify token and redirect to login if needed
206
+ if (requiresAuth && typeof window !== "undefined") {
207
+ // We perform this check asynchronously to not block client creation
208
+ setTimeout(async () => {
209
+ try {
210
+ const isAuthenticated = await userModules.auth.isAuthenticated();
211
+ if (!isAuthenticated) {
212
+ userModules.auth.redirectToLogin(window.location.href);
213
+ }
214
+ }
215
+ catch (error) {
216
+ console.error("Authentication check failed:", error);
217
+ userModules.auth.redirectToLogin(window.location.href);
218
+ }
219
+ }, 0);
220
+ }
221
+ // Assemble and return the client
222
+ const client = {
223
+ ...userModules,
224
+ /**
225
+ * Sets a new authentication token for all subsequent requests.
226
+ *
227
+ * @param newToken - The new authentication token
228
+ *
229
+ * @example
230
+ * ```typescript
231
+ * // Update token after login
232
+ * const { access_token } = await base44.auth.loginViaEmailPassword(
233
+ * 'user@example.com',
234
+ * 'password'
235
+ * );
236
+ * base44.setToken(access_token);
237
+ * ```
238
+ */
239
+ setToken(newToken) {
240
+ userModules.auth.setToken(newToken);
241
+ if (socket) {
242
+ socket.updateConfig({
243
+ token: newToken,
244
+ });
245
+ }
246
+ socketConfig.token = newToken;
247
+ },
248
+ /**
249
+ * Gets the current client configuration.
250
+ *
251
+ * @internal
252
+ */
253
+ getConfig() {
254
+ return {
255
+ serverUrl,
256
+ appId,
257
+ requiresAuth,
258
+ };
259
+ },
260
+ /**
261
+ * Provides access to service role modules.
262
+ *
263
+ * Service role authentication provides elevated permissions for backend operations. Unlike user authentication, which is scoped to a specific user's permissions, service role authentication bypasses entity access rules and field-level security entirely, giving full read and write access to all of the app's data.
264
+ *
265
+ * @throws {Error} When accessed without providing a serviceToken during client creation.
266
+ *
267
+ * @example
268
+ * ```typescript
269
+ * const base44 = createClient({
270
+ * appId: 'my-app-id',
271
+ * serviceToken: 'service-role-token'
272
+ * });
273
+ *
274
+ * // Read every user record, bypassing the User entity's access rules
275
+ * const allUsers = await base44.asServiceRole.entities.User.list();
276
+ * ```
277
+ */
278
+ get asServiceRole() {
279
+ if (!serviceToken) {
280
+ throw new Error("Service token is required to use asServiceRole. Please provide a serviceToken when creating the client.");
281
+ }
282
+ return serviceRoleModules;
283
+ },
284
+ };
285
+ return client;
286
+ }
287
+ /**
288
+ * Creates a Base44 client from an HTTP request.
289
+ *
290
+ * This function is designed for use in Base44-hosted backend functions. For frontends and external backends, use {@linkcode createClient | createClient()} instead.
291
+ *
292
+ * When used in a Base44-hosted backend function, `createClientFromRequest()` automatically extracts authentication tokens from the request headers that Base44 injects when forwarding requests. The returned client includes service role access using `base44.asServiceRole`, which bypasses entity access rules and field-level security.
293
+ *
294
+ * To learn more about the Base44 client, see {@linkcode createClient | createClient()}.
295
+ *
296
+ * @param request - The incoming HTTP request object containing Base44 authentication headers.
297
+ * @returns A configured Base44 client instance with authentication from the incoming request.
298
+ *
299
+ * @example
300
+ * ```typescript
301
+ * // User authentication in backend function
302
+ * import { createClientFromRequest } from 'npm:@base44/sdk';
303
+ *
304
+ * Deno.serve(async (req) => {
305
+ * try {
306
+ * const base44 = createClientFromRequest(req);
307
+ * const user = await base44.auth.me();
308
+ *
309
+ * if (!user) {
310
+ * return Response.json({ error: 'Unauthorized' }, { status: 401 });
311
+ * }
312
+ *
313
+ * // Access user's data
314
+ * const userOrders = await base44.entities.Orders.filter({ userId: user.id });
315
+ * return Response.json({ orders: userOrders });
316
+ * } catch (error) {
317
+ * return Response.json({ error: error.message }, { status: 500 });
318
+ * }
319
+ * });
320
+ * ```
321
+ *
322
+ * @example
323
+ * ```typescript
324
+ * // Service role authentication in backend function
325
+ * import { createClientFromRequest } from 'npm:@base44/sdk';
326
+ *
327
+ * Deno.serve(async (req) => {
328
+ * try {
329
+ * const base44 = createClientFromRequest(req);
330
+ *
331
+ * // Read across all users, bypassing the Orders entity's access rules
332
+ * const recentOrders = await base44.asServiceRole.entities.Orders.list('-created_at', 50);
333
+ *
334
+ * return Response.json({ orders: recentOrders });
335
+ * } catch (error) {
336
+ * return Response.json({ error: error.message }, { status: 500 });
337
+ * }
338
+ * });
339
+ * ```
340
+ *
341
+ */
342
+ export function createClientFromRequest(request) {
343
+ const authHeader = request.headers.get("Authorization");
344
+ const serviceRoleAuthHeader = request.headers.get("Base44-Service-Authorization");
345
+ const appId = request.headers.get("Base44-App-Id");
346
+ const serverUrlHeader = request.headers.get("Base44-Api-Url");
347
+ const functionsVersion = request.headers.get("Base44-Functions-Version");
348
+ const stateHeader = request.headers.get("Base44-State");
349
+ const dataEnvHeader = request.headers.get("X-Data-Env");
350
+ if (!appId) {
351
+ throw new Error("Base44-App-Id header is required, but is was not found on the request");
352
+ }
353
+ // Validate authorization header formats
354
+ let serviceRoleToken;
355
+ let userToken;
356
+ if (serviceRoleAuthHeader !== null) {
357
+ if (serviceRoleAuthHeader === "" ||
358
+ !serviceRoleAuthHeader.startsWith("Bearer ") ||
359
+ serviceRoleAuthHeader.split(" ").length !== 2) {
360
+ throw new Error('Invalid authorization header format. Expected "Bearer <token>"');
361
+ }
362
+ serviceRoleToken = serviceRoleAuthHeader.split(" ")[1];
363
+ }
364
+ if (authHeader !== null) {
365
+ if (authHeader === "" ||
366
+ !authHeader.startsWith("Bearer ") ||
367
+ authHeader.split(" ").length !== 2) {
368
+ throw new Error('Invalid authorization header format. Expected "Bearer <token>"');
369
+ }
370
+ userToken = authHeader.split(" ")[1];
371
+ }
372
+ // Prepare additional headers to propagate
373
+ const additionalHeaders = {};
374
+ if (stateHeader) {
375
+ additionalHeaders["Base44-State"] = stateHeader;
376
+ }
377
+ // Propagate the data environment so entity operations from the function stay
378
+ // in the same environment (e.g. test data) as the triggering request. This
379
+ // matters for the user-scoped client: unlike the service token, the user JWT
380
+ // carries no data-env, so without forwarding this header the callbacks fall
381
+ // back to production data even when the app runs in test-data mode.
382
+ // Forward only the known closed set (matches the backend contract) rather
383
+ // than relaying an arbitrary attacker-supplied header value onward.
384
+ if (dataEnvHeader === "dev" || dataEnvHeader === "prod") {
385
+ additionalHeaders["X-Data-Env"] = dataEnvHeader;
386
+ }
387
+ return createClient({
388
+ serverUrl: serverUrlHeader || "https://api.doany.ai",
389
+ appId,
390
+ token: userToken,
391
+ serviceToken: serviceRoleToken,
392
+ functionsVersion: functionsVersion !== null && functionsVersion !== void 0 ? functionsVersion : undefined,
393
+ headers: additionalHeaders,
394
+ });
395
+ }