@base44-preview/sdk 0.8.42-pr.256.fb681e4 → 0.8.43-pr.256.e07d4b3

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,6 +113,7 @@ export function createClient(config) {
113
113
  const userAuthModule = createAuthModule(axiosClient, functionsAxiosClient, appId, {
114
114
  appBaseUrl: normalizedAppBaseUrl,
115
115
  serverUrl,
116
+ token,
116
117
  });
117
118
  // Apply the access token before any module that may issue authenticated
118
119
  // 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, ConnectorApiRequest, ConnectorApiResponse, } from "./modules/connectors.types.js";
17
+ export type { ConnectorsModule, UserConnectorsModule, ConnectorApiRequest, ConnectorApiResponse, ConnectorApiResponsePhase, } 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";
@@ -1,6 +1,6 @@
1
1
  import { AxiosInstance } from "axios";
2
2
  import { TrackEventParams, AnalyticsModuleOptions } from "./analytics.types";
3
- import type { AuthModule } from "./auth.types";
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__";
6
6
  export declare const ANALYTICS_SESSION_DURATION_EVENT_NAME = "__session_duration_event__";
@@ -10,7 +10,7 @@ export interface AnalyticsModuleArgs {
10
10
  axiosClient: AxiosInstance;
11
11
  serverUrl: string;
12
12
  appId: string;
13
- userAuthModule: AuthModule;
13
+ userAuthModule: InternalAuthModule;
14
14
  }
15
15
  export declare const createAnalyticsModule: ({ axiosClient, serverUrl, appId, userAuthModule, }: AnalyticsModuleArgs) => {
16
16
  track: (params: TrackEventParams) => void;
@@ -247,6 +247,13 @@ 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
+ }
250
257
  if (!sessionContextPromise) {
251
258
  const sessionId = getAnalyticsSessionId();
252
259
  sessionContextPromise = userAuthModule
@@ -1,5 +1,5 @@
1
1
  import { AxiosInstance } from "axios";
2
- import { AuthModule, AuthModuleOptions } from "./auth.types";
2
+ import { AuthModuleOptions, InternalAuthModule } from "./auth.types";
3
3
  /**
4
4
  * Creates the auth module for the Base44 SDK.
5
5
  *
@@ -10,4 +10,4 @@ import { AuthModule, AuthModuleOptions } from "./auth.types";
10
10
  * @returns Auth module with authentication and user management methods
11
11
  * @internal
12
12
  */
13
- export declare function createAuthModule(axios: AxiosInstance, functionsAxiosClient: AxiosInstance, appId: string, options: AuthModuleOptions): AuthModule;
13
+ export declare function createAuthModule(axios: AxiosInstance, functionsAxiosClient: AxiosInstance, appId: string, options: AuthModuleOptions): InternalAuthModule;
@@ -78,7 +78,14 @@ 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);
81
85
  return {
86
+ hasToken() {
87
+ return hasAccessToken;
88
+ },
82
89
  // Get current user information
83
90
  async me() {
84
91
  const request = pendingMe !== null && pendingMe !== void 0 ? pendingMe : axios.get(`/apps/${appId}/entities/User/me`).finally(() => {
@@ -144,6 +151,7 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
144
151
  // flight would otherwise resolve into callers that run after the logout.
145
152
  clearPendingMe();
146
153
  resetAnalyticsSessionContext();
154
+ hasAccessToken = false;
147
155
  // Only do the rest if in a browser environment
148
156
  if (typeof window !== "undefined") {
149
157
  // Remove token from localStorage
@@ -172,6 +180,7 @@ export function createAuthModule(axios, functionsAxiosClient, appId, options) {
172
180
  // resolved for the previous one must not be handed to later callers.
173
181
  clearPendingMe();
174
182
  resetAnalyticsSessionContext();
183
+ hasAccessToken = true;
175
184
  // handle token change for axios clients
176
185
  axios.defaults.headers.common["Authorization"] = `Bearer ${token}`;
177
186
  functionsAxiosClient.defaults.headers.common["Authorization"] = `Bearer ${token}`;
@@ -92,6 +92,12 @@ 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;
95
101
  }
96
102
  /**
97
103
  * 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.
@@ -515,3 +521,20 @@ export interface AuthModule {
515
521
  */
516
522
  changePassword(params: ChangePasswordParams): Promise<any>;
517
523
  }
524
+ /**
525
+ * The auth module as constructed internally, before it is narrowed to
526
+ * {@link AuthModule} on the public client. Not exported from the package
527
+ * index — SDK consumers see only {@link AuthModule}.
528
+ *
529
+ * @internal
530
+ */
531
+ export interface InternalAuthModule extends AuthModule {
532
+ /**
533
+ * Whether an access token is currently set on the client.
534
+ *
535
+ * Reports only the presence of a token, never its validity — an expired or
536
+ * revoked token still reads as `true`. Callers use this to skip requests that
537
+ * could not succeed without a session, not to decide that one is valid.
538
+ */
539
+ hasToken(): boolean;
540
+ }
@@ -1,3 +1,11 @@
1
+ const CONNECTOR_API_METHODS = new Set([
2
+ "GET",
3
+ "POST",
4
+ "PUT",
5
+ "PATCH",
6
+ "DELETE",
7
+ "HEAD",
8
+ ]);
1
9
  /**
2
10
  * Creates the Connectors module for the Base44 SDK.
3
11
  *
@@ -89,13 +97,20 @@ function assertNonEmptyString(value, label) {
89
97
  * @internal
90
98
  */
91
99
  async function proxyCall(axios, url, request) {
92
- var _a, _b, _c, _d, _e, _f, _g;
100
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j;
93
101
  if (!request || typeof request !== "object") {
94
102
  throw new Error("Request is required and must be an object");
95
103
  }
96
104
  assertNonEmptyString(request.path, "Request path");
105
+ const method = (_a = request.method) !== null && _a !== void 0 ? _a : "GET";
106
+ if (!CONNECTOR_API_METHODS.has(method)) {
107
+ throw new Error("Request method must be one of GET, POST, PUT, PATCH, DELETE, or HEAD");
108
+ }
97
109
  const response = await axios.post(url, {
98
- method: ((_a = request.method) !== null && _a !== void 0 ? _a : "GET").toUpperCase(),
110
+ method,
111
+ // Omitted rather than sent as null so the proxy applies the connector's
112
+ // declared default host.
113
+ ...(request.host === undefined ? {} : { host: request.host }),
99
114
  path: request.path,
100
115
  query: (_b = request.query) !== null && _b !== void 0 ? _b : {},
101
116
  headers: (_c = request.headers) !== null && _c !== void 0 ? _c : {},
@@ -104,10 +119,13 @@ async function proxyCall(axios, url, request) {
104
119
  const data = response;
105
120
  return {
106
121
  success: data.success,
122
+ phase: data.phase,
107
123
  status: (_e = data.status_code) !== null && _e !== void 0 ? _e : null,
108
124
  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,
125
+ dataBase64: (_f = data.data_base64) !== null && _f !== void 0 ? _f : null,
126
+ contentType: (_g = data.content_type) !== null && _g !== void 0 ? _g : null,
127
+ headers: (_h = data.headers) !== null && _h !== void 0 ? _h : {},
128
+ creditsCharged: (_j = data.credits_charged) !== null && _j !== void 0 ? _j : 0,
111
129
  };
112
130
  }
113
131
  /**
@@ -41,12 +41,26 @@ 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
+ * How far a metered connector call progressed through the Base44 proxy.
46
+ *
47
+ * Only `not_sent` proves that the provider did not execute the request.
48
+ * `timed_out` and `sent_unconfirmed` may have executed upstream, so do not
49
+ * automatically retry non-idempotent requests based on those phases.
50
+ */
51
+ export type ConnectorApiResponsePhase = "not_sent" | "responded" | "timed_out" | "sent_unconfirmed";
44
52
  /**
45
53
  * A request to forward to a metered connector's API through the Base44 proxy.
46
54
  */
47
55
  export interface ConnectorApiRequest {
48
56
  /** HTTP method for the upstream request. Defaults to `'GET'`. */
49
57
  method?: "GET" | "POST" | "PUT" | "PATCH" | "DELETE" | "HEAD";
58
+ /**
59
+ * Which of the connector's API hosts to call, by the name it declares.
60
+ * Omit for its default host (the first one declared). Only relevant for
61
+ * connectors that expose more than one host.
62
+ */
63
+ host?: string;
50
64
  /**
51
65
  * Path relative to the connector's API root, starting with `/`, such as `'/2/tweets'`.
52
66
  *
@@ -58,19 +72,31 @@ export interface ConnectorApiRequest {
58
72
  query?: Record<string, string | number | boolean | Array<string | number>>;
59
73
  /** Extra request headers. Only headers the connector explicitly allows are forwarded; the rest are dropped. */
60
74
  headers?: Record<string, string>;
61
- /** JSON request body. Ignored for `GET`, `HEAD`, and `DELETE`. */
75
+ /** JSON request body. Ignored for `GET` and `HEAD`. */
62
76
  body?: unknown;
63
77
  }
64
78
  /**
65
79
  * The upstream API's response, as returned by the Base44 connector proxy.
66
80
  */
67
81
  export interface ConnectorApiResponse<T = unknown> {
68
- /** `true` when the upstream API returned a 2xx status. */
82
+ /** `true` only when the upstream API returned a 2xx status. Proxy and upstream errors are `false`. */
69
83
  success: boolean;
70
- /** The upstream HTTP status code, or `null` if the request never reached the provider. */
84
+ /** How far the call progressed. Only `not_sent` proves the provider did not execute it. */
85
+ phase: ConnectorApiResponsePhase;
86
+ /** The upstream HTTP status code, or `null` when no response was received. */
71
87
  status: number | null;
72
- /** The parsed upstream response body. */
88
+ /**
89
+ * The parsed upstream response body, or proxy error details when no response
90
+ * was received. `null` when the response was binary — see {@link dataBase64}.
91
+ */
73
92
  data: T;
93
+ /**
94
+ * The response body base64-encoded, for the media types the connector declares
95
+ * as binary (images, PDFs). Set instead of {@link data}, never alongside it.
96
+ */
97
+ dataBase64: string | null;
98
+ /** The response media type, set only alongside {@link dataBase64}. */
99
+ contentType: string | null;
74
100
  /** The subset of upstream response headers the connector exposes, typically rate-limit counters. */
75
101
  headers: Record<string, string>;
76
102
  /** Integration credits billed to the workspace for this call. */
@@ -82,8 +108,11 @@ export interface ConnectorApiResponse<T = unknown> {
82
108
  */
83
109
  export interface ConnectorProxyRawResponse {
84
110
  success: boolean;
111
+ phase: ConnectorApiResponsePhase;
85
112
  status_code: number | null;
86
113
  data: unknown;
114
+ data_base64: string | null;
115
+ content_type: string | null;
87
116
  headers: Record<string, string>;
88
117
  credits_charged: number;
89
118
  }
@@ -126,7 +155,8 @@ export interface ConnectorProxyRawResponse {
126
155
  * Two things to keep in mind when writing against a metered connector:
127
156
  *
128
157
  * - **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.
158
+ * - **Provider and transport outcomes are returned, not thrown.** A provider `4xx`/`5xx` or a connection failure comes back as `success: false` with its `phase`; authorization, quota, and invalid proxy requests reject the promise.
159
+ * - **Only `phase: 'not_sent'` proves the provider did not execute the request.** A timeout or in-flight failure may have executed upstream, so do not automatically retry a non-idempotent call unless the provider supports an idempotency key.
130
160
  *
131
161
  * ## Available connectors
132
162
  *
@@ -185,11 +185,11 @@ export function createAxiosClient({ baseURL, headers = {}, token, interceptRespo
185
185
  }
186
186
  return response.data;
187
187
  }, (error) => {
188
- var _a, _b, _c, _d, _e, _f, _g, _h;
188
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
189
189
  const message = ((_b = (_a = error.response) === null || _a === void 0 ? void 0 : _a.data) === null || _b === void 0 ? void 0 : _b.message) ||
190
190
  ((_d = (_c = error.response) === null || _c === void 0 ? void 0 : _c.data) === null || _d === void 0 ? void 0 : _d.detail) ||
191
191
  error.message;
192
- const base44Error = new Base44Error(message, (_e = error.response) === null || _e === void 0 ? void 0 : _e.status, (_g = (_f = error.response) === null || _f === void 0 ? void 0 : _f.data) === null || _g === void 0 ? void 0 : _g.code, (_h = error.response) === null || _h === void 0 ? void 0 : _h.data, error);
192
+ const base44Error = new Base44Error(message, (_e = error.response) === null || _e === void 0 ? void 0 : _e.status, (_m = (_h = (_g = (_f = error.response) === null || _f === void 0 ? void 0 : _f.data) === null || _g === void 0 ? void 0 : _g.code) !== null && _h !== void 0 ? _h : (_l = (_k = (_j = error.response) === null || _j === void 0 ? void 0 : _j.headers) === null || _k === void 0 ? void 0 : _k.get) === null || _l === void 0 ? void 0 : _l.call(_k, "x-base44-connector-error")) !== null && _m !== void 0 ? _m : (_p = (_o = error.response) === null || _o === void 0 ? void 0 : _o.headers) === null || _p === void 0 ? void 0 : _p["x-base44-connector-error"], (_q = error.response) === null || _q === void 0 ? void 0 : _q.data, error);
193
193
  // Log errors in development
194
194
  if (process.env.NODE_ENV !== "production") {
195
195
  safeErrorLog("[Base44 SDK Error]", base44Error);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@base44-preview/sdk",
3
- "version": "0.8.42-pr.256.fb681e4",
3
+ "version": "0.8.43-pr.256.e07d4b3",
4
4
  "description": "JavaScript SDK for Base44 API",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",