@base44-preview/sdk 0.8.42-pr.255.53b6586 → 0.8.42-pr.256.fb681e4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.js
CHANGED
|
@@ -113,7 +113,6 @@ export function createClient(config) {
|
|
|
113
113
|
const userAuthModule = createAuthModule(axiosClient, functionsAxiosClient, appId, {
|
|
114
114
|
appBaseUrl: normalizedAppBaseUrl,
|
|
115
115
|
serverUrl,
|
|
116
|
-
token,
|
|
117
116
|
});
|
|
118
117
|
// Apply the access token before any module that may issue authenticated
|
|
119
118
|
// requests during construction (notably analytics, which fires an init
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,6 @@ export type { AppLogsModule } from "./modules/app-logs.types.js";
|
|
|
14
14
|
export type { ActorsModule, ActorClient, ActorRef, Connection, ActorSubscription, ActorConnectOptions, ActorNameRegistry, ActorRegistry, } from "./modules/actors.types.js";
|
|
15
15
|
export type { SsoModule, SsoAccessTokenResponse } from "./modules/sso.types.js";
|
|
16
16
|
export { Actor, type Conn } from "./actor.js";
|
|
17
|
-
export type { ConnectorsModule, UserConnectorsModule, } from "./modules/connectors.types.js";
|
|
17
|
+
export type { ConnectorsModule, UserConnectorsModule, ConnectorApiRequest, ConnectorApiResponse, } from "./modules/connectors.types.js";
|
|
18
18
|
export type { CustomIntegrationsModule, CustomIntegrationCallParams, CustomIntegrationCallResponse, } from "./modules/custom-integrations.types.js";
|
|
19
19
|
export type { GetAccessTokenOptions, SaveAccessTokenOptions, RemoveAccessTokenOptions, GetLoginUrlOptions, } from "./utils/auth-utils.types.js";
|
|
@@ -247,13 +247,6 @@ export function resetAnalyticsSessionContext() {
|
|
|
247
247
|
}
|
|
248
248
|
async function getSessionContext(userAuthModule) {
|
|
249
249
|
if (!analyticsSharedState.sessionContext) {
|
|
250
|
-
// With no token there is no identity to resolve: `me()` can only answer 401,
|
|
251
|
-
// which the browser logs to the console before any handler here sees it. On
|
|
252
|
-
// a public page that request is the sole reason an error appears, so skip
|
|
253
|
-
// it. This is not memoized — a visitor who logs in later must still resolve.
|
|
254
|
-
if (!userAuthModule.hasToken()) {
|
|
255
|
-
return { user_id: null, session_id: getAnalyticsSessionId() };
|
|
256
|
-
}
|
|
257
250
|
if (!sessionContextPromise) {
|
|
258
251
|
const sessionId = getAnalyticsSessionId();
|
|
259
252
|
sessionContextPromise = userAuthModule
|
package/dist/modules/auth.js
CHANGED
|
@@ -78,14 +78,7 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
|
|
|
78
78
|
const clearPendingMe = () => {
|
|
79
79
|
pendingMe = null;
|
|
80
80
|
};
|
|
81
|
-
// Tracked here rather than read off `axios.defaults` so the answer stays tied
|
|
82
|
-
// to the identity transitions below (`setToken`, `logout`) instead of to the
|
|
83
|
-
// header a caller may have set on the instance directly.
|
|
84
|
-
let hasAccessToken = Boolean(options.token);
|
|
85
81
|
return {
|
|
86
|
-
hasToken() {
|
|
87
|
-
return hasAccessToken;
|
|
88
|
-
},
|
|
89
82
|
// Get current user information
|
|
90
83
|
async me() {
|
|
91
84
|
const request = pendingMe !== null && pendingMe !== void 0 ? pendingMe : axios.get(`/apps/${appId}/entities/User/me`).finally(() => {
|
|
@@ -151,7 +144,6 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
|
|
|
151
144
|
// flight would otherwise resolve into callers that run after the logout.
|
|
152
145
|
clearPendingMe();
|
|
153
146
|
resetAnalyticsSessionContext();
|
|
154
|
-
hasAccessToken = false;
|
|
155
147
|
// Only do the rest if in a browser environment
|
|
156
148
|
if (typeof window !== "undefined") {
|
|
157
149
|
// Remove token from localStorage
|
|
@@ -180,7 +172,6 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
|
|
|
180
172
|
// resolved for the previous one must not be handed to later callers.
|
|
181
173
|
clearPendingMe();
|
|
182
174
|
resetAnalyticsSessionContext();
|
|
183
|
-
hasAccessToken = true;
|
|
184
175
|
// handle token change for axios clients
|
|
185
176
|
axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
|
|
186
177
|
functionsAxiosClient.defaults.headers.common["Authorization"] = `Bearer ${token}`;
|
|
@@ -92,12 +92,6 @@ export interface AuthModuleOptions {
|
|
|
92
92
|
serverUrl: string;
|
|
93
93
|
/** Base URL for the app (used for login redirects). */
|
|
94
94
|
appBaseUrl: string;
|
|
95
|
-
/**
|
|
96
|
-
* Access token the client was constructed with, if any. Seeds the module's
|
|
97
|
-
* view of whether a session exists before {@link AuthModule.setToken} runs,
|
|
98
|
-
* which is how the server-side SDK reports a token it never sets explicitly.
|
|
99
|
-
*/
|
|
100
|
-
token?: string;
|
|
101
95
|
}
|
|
102
96
|
/**
|
|
103
97
|
* Authentication module for managing user authentication and authorization. The module automatically stores tokens in local storage when available and manages authorization headers for API requests.
|
|
@@ -117,16 +111,6 @@ export interface AuthModuleOptions {
|
|
|
117
111
|
* The auth module is only available in user authentication mode (`base44.auth`).
|
|
118
112
|
*/
|
|
119
113
|
export interface AuthModule {
|
|
120
|
-
/**
|
|
121
|
-
* Whether an access token is currently set on the client.
|
|
122
|
-
*
|
|
123
|
-
* Reports only the presence of a token, never its validity — an expired or
|
|
124
|
-
* revoked token still reads as `true`. Callers use this to skip requests that
|
|
125
|
-
* could not succeed without a session, not to decide that one is valid.
|
|
126
|
-
*
|
|
127
|
-
* @internal
|
|
128
|
-
*/
|
|
129
|
-
hasToken(): boolean;
|
|
130
114
|
/**
|
|
131
115
|
* Gets the current authenticated user's information.
|
|
132
116
|
*
|
|
@@ -68,6 +68,46 @@ export function createConnectorsModule(axios, appId) {
|
|
|
68
68
|
connectionConfig: (_a = data.connection_config) !== null && _a !== void 0 ? _a : null,
|
|
69
69
|
};
|
|
70
70
|
},
|
|
71
|
+
async callApi(integrationType, request) {
|
|
72
|
+
assertNonEmptyString(integrationType, "Integration type");
|
|
73
|
+
return proxyCall(axios, `/apps/${appId}/connectors/${integrationType}/call`, request);
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function assertNonEmptyString(value, label) {
|
|
78
|
+
if (!value || typeof value !== "string") {
|
|
79
|
+
throw new Error(`${label} is required and must be a string`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* POST a request to the connector proxy and normalize the response.
|
|
84
|
+
*
|
|
85
|
+
* The proxy reports upstream outcomes in the body rather than as HTTP status, so
|
|
86
|
+
* a provider 4xx/5xx arrives here as a resolved response with `success: false` —
|
|
87
|
+
* only Base44-side failures reject through the axios error interceptor.
|
|
88
|
+
*
|
|
89
|
+
* @internal
|
|
90
|
+
*/
|
|
91
|
+
async function proxyCall(axios, url, request) {
|
|
92
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
93
|
+
if (!request || typeof request !== "object") {
|
|
94
|
+
throw new Error("Request is required and must be an object");
|
|
95
|
+
}
|
|
96
|
+
assertNonEmptyString(request.path, "Request path");
|
|
97
|
+
const response = await axios.post(url, {
|
|
98
|
+
method: ((_a = request.method) !== null && _a !== void 0 ? _a : "GET").toUpperCase(),
|
|
99
|
+
path: request.path,
|
|
100
|
+
query: (_b = request.query) !== null && _b !== void 0 ? _b : {},
|
|
101
|
+
headers: (_c = request.headers) !== null && _c !== void 0 ? _c : {},
|
|
102
|
+
body: (_d = request.body) !== null && _d !== void 0 ? _d : null,
|
|
103
|
+
});
|
|
104
|
+
const data = response;
|
|
105
|
+
return {
|
|
106
|
+
success: data.success,
|
|
107
|
+
status: (_e = data.status_code) !== null && _e !== void 0 ? _e : null,
|
|
108
|
+
data: data.data,
|
|
109
|
+
headers: (_f = data.headers) !== null && _f !== void 0 ? _f : {},
|
|
110
|
+
creditsCharged: (_g = data.credits_charged) !== null && _g !== void 0 ? _g : 0,
|
|
71
111
|
};
|
|
72
112
|
}
|
|
73
113
|
/**
|
|
@@ -41,6 +41,52 @@ export interface AppUserConnectorConnectionResponse {
|
|
|
41
41
|
/** Key-value configuration for the connection, or `null` if the connector does not provide one. */
|
|
42
42
|
connectionConfig: Record<string, string> | null;
|
|
43
43
|
}
|
|
44
|
+
/**
|
|
45
|
+
* A request to forward to a metered connector's API through the Base44 proxy.
|
|
46
|
+
*/
|
|
47
|
+
export interface ConnectorApiRequest {
|
|
48
|
+
/** HTTP method for the upstream request. Defaults to `'GET'`. */
|
|
49
|
+
method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD";
|
|
50
|
+
/**
|
|
51
|
+
* Path relative to the connector's API root, starting with `/`, such as `'/2/tweets'`.
|
|
52
|
+
*
|
|
53
|
+
* Must not be an absolute URL. Query parameters may be included here or passed
|
|
54
|
+
* separately as {@link query}; either way they are forwarded and priced identically.
|
|
55
|
+
*/
|
|
56
|
+
path: string;
|
|
57
|
+
/** Query parameters. Merged into the request URL alongside any already present in {@link path}. */
|
|
58
|
+
query?: Record<string, string | number | boolean | Array<string | number>>;
|
|
59
|
+
/** Extra request headers. Only headers the connector explicitly allows are forwarded; the rest are dropped. */
|
|
60
|
+
headers?: Record<string, string>;
|
|
61
|
+
/** JSON request body. Ignored for `GET`, `HEAD`, and `DELETE`. */
|
|
62
|
+
body?: unknown;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* The upstream API's response, as returned by the Base44 connector proxy.
|
|
66
|
+
*/
|
|
67
|
+
export interface ConnectorApiResponse<T = unknown> {
|
|
68
|
+
/** `true` when the upstream API returned a 2xx status. */
|
|
69
|
+
success: boolean;
|
|
70
|
+
/** The upstream HTTP status code, or `null` if the request never reached the provider. */
|
|
71
|
+
status: number | null;
|
|
72
|
+
/** The parsed upstream response body. */
|
|
73
|
+
data: T;
|
|
74
|
+
/** The subset of upstream response headers the connector exposes, typically rate-limit counters. */
|
|
75
|
+
headers: Record<string, string>;
|
|
76
|
+
/** Integration credits billed to the workspace for this call. */
|
|
77
|
+
creditsCharged: number;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Raw proxy response shape. Mapped to {@link ConnectorApiResponse} before being returned.
|
|
81
|
+
* @internal
|
|
82
|
+
*/
|
|
83
|
+
export interface ConnectorProxyRawResponse {
|
|
84
|
+
success: boolean;
|
|
85
|
+
status_code: number | null;
|
|
86
|
+
data: unknown;
|
|
87
|
+
headers: Record<string, string>;
|
|
88
|
+
credits_charged: number;
|
|
89
|
+
}
|
|
44
90
|
/**
|
|
45
91
|
* Connectors module for managing OAuth tokens for external services.
|
|
46
92
|
*
|
|
@@ -71,6 +117,17 @@ export interface AppUserConnectorConnectionResponse {
|
|
|
71
117
|
* 3. In a backend function, call {@linkcode getCurrentAppUserConnection | getCurrentAppUserConnection()} using the service role client (`base44.asServiceRole.connectors`) with the connector ID to retrieve the app user's token.
|
|
72
118
|
* 4. Use the returned `accessToken` to call the external service's API directly. Some connectors also return a `connectionConfig` with additional values such as a subdomain for building the API URL.
|
|
73
119
|
*
|
|
120
|
+
* ## Metered connectors
|
|
121
|
+
*
|
|
122
|
+
* A few [platform connectors](#shared-connectors) are backed by paid third-party APIs that charge Base44 per call. For those, the OAuth token is **not** available to your code — {@linkcode getConnection | getConnection()} rejects with a `403`. Call them with {@linkcode callApi | callApi()} instead: Base44 attaches the credential server-side, forwards the request, and bills your workspace's integration credits for the call.
|
|
123
|
+
*
|
|
124
|
+
* This applies to platform connectors only. A workspace-registered or app user connector runs on **your own** OAuth app, so the provider invoices you directly and there is nothing for Base44 to meter — those keep normal token access via {@linkcode getWorkspaceConnection | getWorkspaceConnection()} and {@linkcode getCurrentAppUserConnection | getCurrentAppUserConnection()}.
|
|
125
|
+
*
|
|
126
|
+
* Two things to keep in mind when writing against a metered connector:
|
|
127
|
+
*
|
|
128
|
+
* - **Cost varies by endpoint, sometimes sharply.** The same connector can charge two orders of magnitude more for one endpoint than another, so avoid putting an expensive call inside a loop and batch wherever the provider supports it. Each response reports what it actually cost as `creditsCharged`.
|
|
129
|
+
* - **An upstream error is returned, not thrown.** A `4xx` or `5xx` from the provider comes back as `success: false` with the provider's own `status` and `data`, because it is a normal outcome of a call that Base44 completed. Only Base44-side failures — no connection, credits exhausted, a rejected request — reject the promise.
|
|
130
|
+
*
|
|
74
131
|
* ## Available connectors
|
|
75
132
|
*
|
|
76
133
|
* The connectors below can be used as shared connectors or as app user connectors. For a shared platform connector, pass the integration type string to {@linkcode getConnection | getConnection()}. For a connector you register in Workspace Settings with your own OAuth app, use the connector ID with {@linkcode getWorkspaceConnection | getWorkspaceConnection()} for a shared token, or with {@linkcode getCurrentAppUserConnection | getCurrentAppUserConnection()} for a per-user token.
|
|
@@ -328,6 +385,41 @@ export interface ConnectorsModule {
|
|
|
328
385
|
* ```
|
|
329
386
|
*/
|
|
330
387
|
getCurrentAppUserConnection(connectorId: string): Promise<AppUserConnectorConnectionResponse>;
|
|
388
|
+
/**
|
|
389
|
+
* Calls a [metered connector's](#metered-connectors) API through the Base44 proxy.
|
|
390
|
+
*
|
|
391
|
+
* Use this for a shared platform connector identified by an integration type. Base44 adds the OAuth credential to the outgoing request, forwards it, and bills the workspace for the call, so you never handle the token yourself.
|
|
392
|
+
*
|
|
393
|
+
* @param integrationType - The type of integration, such as `'x'`. See [Available connectors](#available-connectors).
|
|
394
|
+
* @param request - The upstream request to forward. See {@link ConnectorApiRequest}.
|
|
395
|
+
* @returns Promise resolving to a {@link ConnectorApiResponse}. Note that an upstream error is reported in `success` and `status`, not thrown — only Base44-side failures reject.
|
|
396
|
+
*
|
|
397
|
+
* @example
|
|
398
|
+
* ```typescript
|
|
399
|
+
* // Post to X
|
|
400
|
+
* const res = await base44.asServiceRole.connectors.callApi('x', {
|
|
401
|
+
* method: 'POST',
|
|
402
|
+
* path: '/2/tweets',
|
|
403
|
+
* body: { text: 'Shipped!' },
|
|
404
|
+
* });
|
|
405
|
+
*
|
|
406
|
+
* if (!res.success) {
|
|
407
|
+
* console.error('X rejected the post', res.status, res.data);
|
|
408
|
+
* }
|
|
409
|
+
* ```
|
|
410
|
+
*
|
|
411
|
+
* @example
|
|
412
|
+
* ```typescript
|
|
413
|
+
* // Read, with query parameters and a look at what the call cost
|
|
414
|
+
* const res = await base44.asServiceRole.connectors.callApi('x', {
|
|
415
|
+
* path: '/2/tweets/search/recent',
|
|
416
|
+
* query: { query: 'base44', max_results: 10 },
|
|
417
|
+
* });
|
|
418
|
+
*
|
|
419
|
+
* console.log(`${res.creditsCharged} credits`, res.data);
|
|
420
|
+
* ```
|
|
421
|
+
*/
|
|
422
|
+
callApi<T = unknown>(integrationType: ConnectorIntegrationType, request: ConnectorApiRequest): Promise<ConnectorApiResponse<T>>;
|
|
331
423
|
}
|
|
332
424
|
/**
|
|
333
425
|
* User-scoped connectors module for managing app user OAuth connections.
|