@base44-preview/sdk 0.8.30-pr.160.b403af6 → 0.8.31-pr.178.78bd45c
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 +6 -0
- package/dist/client.types.d.ts +3 -0
- package/dist/index.d.ts +1 -0
- package/dist/modules/accounts.d.ts +11 -0
- package/dist/modules/accounts.js +61 -0
- package/dist/modules/accounts.types.d.ts +112 -0
- package/dist/modules/accounts.types.js +10 -0
- package/dist/modules/connectors.js +15 -16
- package/dist/modules/connectors.types.d.ts +7 -9
- package/dist/utils/axios-client.d.ts +2 -1
- package/dist/utils/axios-client.js +12 -2
- package/dist/utils/common.d.ts +9 -0
- package/dist/utils/common.js +20 -0
- package/package.json +1 -1
package/dist/client.js
CHANGED
|
@@ -9,6 +9,7 @@ import { createFunctionsModule } from "./modules/functions.js";
|
|
|
9
9
|
import { createAgentsModule } from "./modules/agents.js";
|
|
10
10
|
import { createAppLogsModule } from "./modules/app-logs.js";
|
|
11
11
|
import { createUsersModule } from "./modules/users.js";
|
|
12
|
+
import { createAccountsModule } from "./modules/accounts.js";
|
|
12
13
|
import { RoomsSocket } from "./utils/socket-utils.js";
|
|
13
14
|
import { createAnalyticsModule } from "./modules/analytics.js";
|
|
14
15
|
/**
|
|
@@ -83,12 +84,14 @@ export function createClient(config) {
|
|
|
83
84
|
baseURL: `${serverUrl}/api`,
|
|
84
85
|
headers,
|
|
85
86
|
token,
|
|
87
|
+
appId: String(appId),
|
|
86
88
|
onError: options === null || options === void 0 ? void 0 : options.onError,
|
|
87
89
|
});
|
|
88
90
|
const functionsAxiosClient = createAxiosClient({
|
|
89
91
|
baseURL: `${serverUrl}/api`,
|
|
90
92
|
headers: functionHeaders,
|
|
91
93
|
token,
|
|
94
|
+
appId: String(appId),
|
|
92
95
|
interceptResponses: false,
|
|
93
96
|
onError: options === null || options === void 0 ? void 0 : options.onError,
|
|
94
97
|
});
|
|
@@ -100,12 +103,14 @@ export function createClient(config) {
|
|
|
100
103
|
baseURL: `${serverUrl}/api`,
|
|
101
104
|
headers: serviceRoleHeaders,
|
|
102
105
|
token: serviceToken,
|
|
106
|
+
appId: String(appId),
|
|
103
107
|
onError: options === null || options === void 0 ? void 0 : options.onError,
|
|
104
108
|
});
|
|
105
109
|
const serviceRoleFunctionsAxiosClient = createAxiosClient({
|
|
106
110
|
baseURL: `${serverUrl}/api`,
|
|
107
111
|
headers: functionHeaders,
|
|
108
112
|
token: serviceToken,
|
|
113
|
+
appId: String(appId),
|
|
109
114
|
interceptResponses: false,
|
|
110
115
|
});
|
|
111
116
|
const userAuthModule = createAuthModule(axiosClient, functionsAxiosClient, appId, {
|
|
@@ -152,6 +157,7 @@ export function createClient(config) {
|
|
|
152
157
|
}),
|
|
153
158
|
appLogs: createAppLogsModule(axiosClient, appId),
|
|
154
159
|
users: createUsersModule(axiosClient, appId),
|
|
160
|
+
accounts: createAccountsModule(axiosClient, appId),
|
|
155
161
|
analytics: createAnalyticsModule({
|
|
156
162
|
axiosClient,
|
|
157
163
|
serverUrl,
|
package/dist/client.types.d.ts
CHANGED
|
@@ -7,6 +7,7 @@ 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
9
|
import type { AnalyticsModule } from "./modules/analytics.types.js";
|
|
10
|
+
import type { AccountsModule } from "./modules/accounts.types.js";
|
|
10
11
|
/**
|
|
11
12
|
* Options for creating a Base44 client.
|
|
12
13
|
*/
|
|
@@ -79,6 +80,8 @@ export interface CreateClientConfig {
|
|
|
79
80
|
* Provides access to all SDK modules for interacting with the app.
|
|
80
81
|
*/
|
|
81
82
|
export interface Base44Client {
|
|
83
|
+
/** {@link AccountsModule | Accounts module} for multi-tenancy (accounts, members, billing). */
|
|
84
|
+
accounts: AccountsModule;
|
|
82
85
|
/** {@link AgentsModule | Agents module} for managing AI agent conversations. */
|
|
83
86
|
agents: AgentsModule;
|
|
84
87
|
/** {@link AnalyticsModule | Analytics module} for tracking custom events in your app. */
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export type { IntegrationsModule, IntegrationEndpointFunction, CoreIntegrations,
|
|
|
10
10
|
export type { FunctionsModule, FunctionName, FunctionNameRegistry, } from "./modules/functions.types.js";
|
|
11
11
|
export type { AgentsModule, AgentName, AgentNameRegistry, AgentConversation, AgentMessage, AgentMessageReasoning, AgentMessageToolCall, AgentMessageUsage, AgentMessageCustomContext, AgentMessageMetadata, CreateConversationParams, } from "./modules/agents.types.js";
|
|
12
12
|
export type { AppLogsModule } from "./modules/app-logs.types.js";
|
|
13
|
+
export type { AccountsModule, Account, AccountMembership, AccountPlan, AccountRole, AssignableAccountRole, AccountStatus, AccountMembershipStatus, MyAccountsResponse, CheckoutSession, } from "./modules/accounts.types.js";
|
|
13
14
|
export type { SsoModule, SsoAccessTokenResponse } from "./modules/sso.types.js";
|
|
14
15
|
export type { ConnectorsModule, UserConnectorsModule, } from "./modules/connectors.types.js";
|
|
15
16
|
export type { CustomIntegrationsModule, CustomIntegrationCallParams, CustomIntegrationCallResponse, } from "./modules/custom-integrations.types.js";
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { AxiosInstance } from "axios";
|
|
2
|
+
import type { AccountsModule } from "./accounts.types.js";
|
|
3
|
+
/**
|
|
4
|
+
* Creates the accounts module (multi-tenancy) for the Base44 SDK.
|
|
5
|
+
*
|
|
6
|
+
* @param axios - Axios instance (responses are unwrapped to data).
|
|
7
|
+
* @param appId - Application ID.
|
|
8
|
+
* @returns The accounts module.
|
|
9
|
+
* @internal
|
|
10
|
+
*/
|
|
11
|
+
export declare function createAccountsModule(axios: AxiosInstance, appId: string): AccountsModule;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { getActiveAccountIdFromPath } from "../utils/common.js";
|
|
2
|
+
/**
|
|
3
|
+
* Creates the accounts module (multi-tenancy) for the Base44 SDK.
|
|
4
|
+
*
|
|
5
|
+
* @param axios - Axios instance (responses are unwrapped to data).
|
|
6
|
+
* @param appId - Application ID.
|
|
7
|
+
* @returns The accounts module.
|
|
8
|
+
* @internal
|
|
9
|
+
*/
|
|
10
|
+
export function createAccountsModule(axios, appId) {
|
|
11
|
+
const base = `/apps/${appId}/accounts`;
|
|
12
|
+
const enc = encodeURIComponent;
|
|
13
|
+
return {
|
|
14
|
+
getActiveAccountId() {
|
|
15
|
+
return getActiveAccountIdFromPath(appId);
|
|
16
|
+
},
|
|
17
|
+
switchAccount(accountId, subPath = "") {
|
|
18
|
+
if (typeof window === "undefined")
|
|
19
|
+
return;
|
|
20
|
+
const clean = subPath.replace(/^\/+/, "");
|
|
21
|
+
window.location.assign(`/${accountId}${clean ? `/${clean}` : "/"}`);
|
|
22
|
+
},
|
|
23
|
+
async listMine() {
|
|
24
|
+
return axios.get(`${base}/me`);
|
|
25
|
+
},
|
|
26
|
+
async create(params) {
|
|
27
|
+
return axios.post(base, params);
|
|
28
|
+
},
|
|
29
|
+
async update(accountId, params) {
|
|
30
|
+
return axios.patch(`${base}/${accountId}`, params);
|
|
31
|
+
},
|
|
32
|
+
async listMembers(accountId) {
|
|
33
|
+
return axios.get(`${base}/${accountId}/members`);
|
|
34
|
+
},
|
|
35
|
+
async invite(accountId, email, role = "member") {
|
|
36
|
+
return axios.post(`${base}/${accountId}/invites`, { email, role });
|
|
37
|
+
},
|
|
38
|
+
async acceptInvite(accountId) {
|
|
39
|
+
return axios.post(`${base}/${accountId}/accept`, {});
|
|
40
|
+
},
|
|
41
|
+
async changeMemberRole(accountId, email, role) {
|
|
42
|
+
return axios.patch(`${base}/${accountId}/members/${enc(email)}/role`, {
|
|
43
|
+
role,
|
|
44
|
+
});
|
|
45
|
+
},
|
|
46
|
+
async removeMember(accountId, email) {
|
|
47
|
+
return axios.delete(`${base}/${accountId}/members/${enc(email)}`);
|
|
48
|
+
},
|
|
49
|
+
async transferOwnership(accountId, email) {
|
|
50
|
+
return axios.post(`${base}/${accountId}/transfer-ownership`, { email });
|
|
51
|
+
},
|
|
52
|
+
billing: {
|
|
53
|
+
async listPlans(accountId) {
|
|
54
|
+
return axios.get(`${base}/${accountId}/billing/plans`);
|
|
55
|
+
},
|
|
56
|
+
async startCheckout(accountId, params) {
|
|
57
|
+
return axios.post(`${base}/${accountId}/billing/checkout`, params);
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the {@link AccountsModule | accounts} module (multi-tenancy).
|
|
3
|
+
*
|
|
4
|
+
* An Account groups the app's end-users into an isolated tenant (a company,
|
|
5
|
+
* team, or organization). Users join accounts via membership and act inside one
|
|
6
|
+
* active account at a time. Account-scoped entities are transparently isolated
|
|
7
|
+
* to the active account (carried by the `X-Active-Account-Id` header, derived
|
|
8
|
+
* from the `/<account_id>/...` URL path).
|
|
9
|
+
*/
|
|
10
|
+
/** Account-management role. Distinct from the app's business roles. */
|
|
11
|
+
export type AccountRole = "owner" | "admin" | "member";
|
|
12
|
+
/** Assignable (non-owner) role used for invites/role changes. */
|
|
13
|
+
export type AssignableAccountRole = "admin" | "member";
|
|
14
|
+
export type AccountStatus = "active" | "suspended";
|
|
15
|
+
export type AccountMembershipStatus = "pending" | "active";
|
|
16
|
+
/** An account (tenant) within the app. */
|
|
17
|
+
export interface Account {
|
|
18
|
+
id: string;
|
|
19
|
+
app_id: string;
|
|
20
|
+
name: string;
|
|
21
|
+
status: AccountStatus;
|
|
22
|
+
plan_id?: string | null;
|
|
23
|
+
billing_status?: string;
|
|
24
|
+
/** The current user's role in this account (present on `listMine()` results). */
|
|
25
|
+
my_role?: AccountRole;
|
|
26
|
+
/** Builder-defined custom fields. */
|
|
27
|
+
data?: Record<string, unknown>;
|
|
28
|
+
created_date?: string;
|
|
29
|
+
}
|
|
30
|
+
/** The accounts the current user belongs to, plus the active one. */
|
|
31
|
+
export interface MyAccountsResponse {
|
|
32
|
+
accounts: Account[];
|
|
33
|
+
active_account_id: string | null;
|
|
34
|
+
}
|
|
35
|
+
/** A user's membership in an account. */
|
|
36
|
+
export interface AccountMembership {
|
|
37
|
+
id: string;
|
|
38
|
+
account_id: string;
|
|
39
|
+
email: string;
|
|
40
|
+
role: AccountRole;
|
|
41
|
+
status: AccountMembershipStatus;
|
|
42
|
+
}
|
|
43
|
+
/** A subscription plan/tier offered to accounts. */
|
|
44
|
+
export interface AccountPlan {
|
|
45
|
+
id: string;
|
|
46
|
+
name: string;
|
|
47
|
+
description?: string | null;
|
|
48
|
+
price_amount: number;
|
|
49
|
+
currency: string;
|
|
50
|
+
interval: "month" | "year";
|
|
51
|
+
is_active: boolean;
|
|
52
|
+
}
|
|
53
|
+
/** A provider checkout session. */
|
|
54
|
+
export interface CheckoutSession {
|
|
55
|
+
url: string;
|
|
56
|
+
session_id: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* The accounts module — manage multi-tenancy ("Accounts") from inside the app.
|
|
60
|
+
*
|
|
61
|
+
* Access via `base44.accounts`. Available when the app has multi-tenancy enabled.
|
|
62
|
+
*/
|
|
63
|
+
export interface AccountsModule {
|
|
64
|
+
/** The active account id, read from the current URL path (or `undefined`). */
|
|
65
|
+
getActiveAccountId(): string | undefined;
|
|
66
|
+
/**
|
|
67
|
+
* Switch the active account by navigating to its folder (`/<accountId>/...`).
|
|
68
|
+
* A full navigation re-roots the app so all data follows the new account.
|
|
69
|
+
* @param accountId - The account to switch to.
|
|
70
|
+
* @param subPath - Optional in-account route to land on (defaults to the root).
|
|
71
|
+
*/
|
|
72
|
+
switchAccount(accountId: string, subPath?: string): void;
|
|
73
|
+
/** List the accounts the current user belongs to, plus the active one. */
|
|
74
|
+
listMine(): Promise<MyAccountsResponse>;
|
|
75
|
+
/** Create a new account; the current user becomes its owner. */
|
|
76
|
+
create(params: {
|
|
77
|
+
name: string;
|
|
78
|
+
data?: Record<string, unknown>;
|
|
79
|
+
}): Promise<Account>;
|
|
80
|
+
/** Rename and/or update an account's custom fields (managers only). */
|
|
81
|
+
update(accountId: string, params: {
|
|
82
|
+
name?: string;
|
|
83
|
+
data?: Record<string, unknown>;
|
|
84
|
+
}): Promise<Account>;
|
|
85
|
+
/** List an account's members (any active member). */
|
|
86
|
+
listMembers(accountId: string): Promise<AccountMembership[]>;
|
|
87
|
+
/** Invite a user by email to an account (managers only). */
|
|
88
|
+
invite(accountId: string, email: string, role?: AssignableAccountRole): Promise<AccountMembership>;
|
|
89
|
+
/** Accept a pending invite to an account for the current user. */
|
|
90
|
+
acceptInvite(accountId: string): Promise<AccountMembership>;
|
|
91
|
+
/** Change a member's role (managers only; not for the owner). */
|
|
92
|
+
changeMemberRole(accountId: string, email: string, role: AssignableAccountRole): Promise<AccountMembership>;
|
|
93
|
+
/** Remove a member from an account (managers only; not the owner). */
|
|
94
|
+
removeMember(accountId: string, email: string): Promise<{
|
|
95
|
+
removed: boolean;
|
|
96
|
+
}>;
|
|
97
|
+
/** Transfer ownership to another active member (owner only). */
|
|
98
|
+
transferOwnership(accountId: string, email: string): Promise<{
|
|
99
|
+
transferred: boolean;
|
|
100
|
+
}>;
|
|
101
|
+
/** Per-account billing. */
|
|
102
|
+
billing: {
|
|
103
|
+
/** List the active plans available to this account. */
|
|
104
|
+
listPlans(accountId: string): Promise<AccountPlan[]>;
|
|
105
|
+
/** Start a subscription checkout session for a plan. */
|
|
106
|
+
startCheckout(accountId: string, params: {
|
|
107
|
+
plan_id: string;
|
|
108
|
+
success_url: string;
|
|
109
|
+
cancel_url: string;
|
|
110
|
+
}): Promise<CheckoutSession>;
|
|
111
|
+
};
|
|
112
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Types for the {@link AccountsModule | accounts} module (multi-tenancy).
|
|
3
|
+
*
|
|
4
|
+
* An Account groups the app's end-users into an isolated tenant (a company,
|
|
5
|
+
* team, or organization). Users join accounts via membership and act inside one
|
|
6
|
+
* active account at a time. Account-scoped entities are transparently isolated
|
|
7
|
+
* to the active account (carried by the `X-Active-Account-Id` header, derived
|
|
8
|
+
* from the `/<account_id>/...` URL path).
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
@@ -21,25 +21,24 @@ export function createConnectorsModule(axios, appId) {
|
|
|
21
21
|
// @ts-expect-error
|
|
22
22
|
return response.access_token;
|
|
23
23
|
},
|
|
24
|
-
async getConnection(
|
|
24
|
+
async getConnection(integrationType) {
|
|
25
25
|
var _a;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
if (!arg) {
|
|
29
|
-
throw new Error("Integration type is required and must be a string");
|
|
30
|
-
}
|
|
31
|
-
url = `/apps/${appId}/external-auth/tokens/${arg}`;
|
|
32
|
-
}
|
|
33
|
-
else if (arg && typeof arg === "object" && typeof arg.connectorId === "string") {
|
|
34
|
-
if (!arg.connectorId) {
|
|
35
|
-
throw new Error("Connector ID is required and must be a string");
|
|
36
|
-
}
|
|
37
|
-
url = `/apps/${appId}/external-auth/tokens/by-connector/${arg.connectorId}`;
|
|
26
|
+
if (!integrationType || typeof integrationType !== "string") {
|
|
27
|
+
throw new Error("Integration type is required and must be a string");
|
|
38
28
|
}
|
|
39
|
-
|
|
40
|
-
|
|
29
|
+
const response = await axios.get(`/apps/${appId}/external-auth/tokens/${integrationType}`);
|
|
30
|
+
const data = response;
|
|
31
|
+
return {
|
|
32
|
+
accessToken: data.access_token,
|
|
33
|
+
connectionConfig: (_a = data.connection_config) !== null && _a !== void 0 ? _a : null,
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
async getWorkspaceConnection(connectorId) {
|
|
37
|
+
var _a;
|
|
38
|
+
if (!connectorId || typeof connectorId !== "string") {
|
|
39
|
+
throw new Error("Connector ID is required and must be a string");
|
|
41
40
|
}
|
|
42
|
-
const response = await axios.get(
|
|
41
|
+
const response = await axios.get(`/apps/${appId}/external-auth/tokens/connectors/${connectorId}`);
|
|
43
42
|
const data = response;
|
|
44
43
|
return {
|
|
45
44
|
accessToken: data.access_token,
|
|
@@ -255,30 +255,28 @@ export interface ConnectorsModule {
|
|
|
255
255
|
* Retrieves the OAuth access token and connection configuration for a **workspace-registered** connector
|
|
256
256
|
* (a connector backed by an OAuth app registered in the workspace, consented to once by the app builder).
|
|
257
257
|
*
|
|
258
|
-
* Use this
|
|
258
|
+
* Use this method when the app's backend function needs to use a connector identified by its
|
|
259
259
|
* workspace-connector ID rather than a platform integration type. The token returned represents
|
|
260
260
|
* the app builder's consent against the workspace's OAuth app and is shared across all app users
|
|
261
|
-
* of the app — identical semantics to the platform-shared
|
|
261
|
+
* of the app — identical semantics to the platform-shared {@link getConnection} form,
|
|
262
262
|
* differing only in which OAuth app was used to produce the token.
|
|
263
263
|
*
|
|
264
|
-
* @param
|
|
264
|
+
* @param connectorId - The ID of the workspace connector (the `OrganizationConnector` database ID) as surfaced in the builder chat context.
|
|
265
265
|
* @returns Promise resolving to a {@link ConnectorConnectionResponse} with `accessToken` and `connectionConfig`.
|
|
266
266
|
*
|
|
267
267
|
* @example
|
|
268
268
|
* ```typescript
|
|
269
269
|
* // Get the connection for a workspace-registered connector
|
|
270
|
-
* const { accessToken, connectionConfig } = await base44.asServiceRole.connectors.
|
|
271
|
-
*
|
|
272
|
-
*
|
|
270
|
+
* const { accessToken, connectionConfig } = await base44.asServiceRole.connectors.getWorkspaceConnection(
|
|
271
|
+
* 'abc123def',
|
|
272
|
+
* );
|
|
273
273
|
*
|
|
274
274
|
* const response = await fetch(`https://${connectionConfig?.subdomain}.snowflakecomputing.com/api/v2/statements`, {
|
|
275
275
|
* headers: { Authorization: `Bearer ${accessToken}` },
|
|
276
276
|
* });
|
|
277
277
|
* ```
|
|
278
278
|
*/
|
|
279
|
-
|
|
280
|
-
connectorId: string;
|
|
281
|
-
}): Promise<ConnectorConnectionResponse>;
|
|
279
|
+
getWorkspaceConnection(connectorId: string): Promise<ConnectorConnectionResponse>;
|
|
282
280
|
/**
|
|
283
281
|
* @internal
|
|
284
282
|
* @deprecated Use {@link getCurrentAppUserConnection} instead.
|
|
@@ -90,10 +90,11 @@ export declare class Base44Error extends Error {
|
|
|
90
90
|
* @returns Configured axios instance
|
|
91
91
|
* @internal
|
|
92
92
|
*/
|
|
93
|
-
export declare function createAxiosClient({ baseURL, headers, token, interceptResponses, onError, }: {
|
|
93
|
+
export declare function createAxiosClient({ baseURL, headers, token, appId, interceptResponses, onError, }: {
|
|
94
94
|
baseURL: string;
|
|
95
95
|
headers?: Record<string, string>;
|
|
96
96
|
token?: string;
|
|
97
|
+
appId?: string;
|
|
97
98
|
interceptResponses?: boolean;
|
|
98
99
|
onError?: (error: Error) => void;
|
|
99
100
|
}): import("axios").AxiosInstance;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
|
-
import { isInIFrame } from "./common.js";
|
|
2
|
+
import { getActiveAccountIdFromPath, isInIFrame } from "./common.js";
|
|
3
3
|
import { v4 as uuidv4 } from "uuid";
|
|
4
4
|
/**
|
|
5
5
|
* Custom error class for Base44 SDK errors.
|
|
@@ -114,7 +114,7 @@ function safeErrorLog(prefix, error) {
|
|
|
114
114
|
* @returns Configured axios instance
|
|
115
115
|
* @internal
|
|
116
116
|
*/
|
|
117
|
-
export function createAxiosClient({ baseURL, headers = {}, token, interceptResponses = true, onError, }) {
|
|
117
|
+
export function createAxiosClient({ baseURL, headers = {}, token, appId, interceptResponses = true, onError, }) {
|
|
118
118
|
const client = axios.create({
|
|
119
119
|
baseURL,
|
|
120
120
|
headers: {
|
|
@@ -131,6 +131,16 @@ export function createAxiosClient({ baseURL, headers = {}, token, interceptRespo
|
|
|
131
131
|
client.interceptors.request.use((config) => {
|
|
132
132
|
if (typeof window !== "undefined") {
|
|
133
133
|
config.headers.set("X-Origin-URL", window.location.href);
|
|
134
|
+
// Multi-tenancy: forward the active account (from the URL path) per request
|
|
135
|
+
// so account-scoped reads/writes stay isolated to the current tenant even
|
|
136
|
+
// after a client-side account switch. The path is the canonical source, so
|
|
137
|
+
// it overrides any stale default header (e.g. one frozen at module load);
|
|
138
|
+
// no-op for single-tenant apps (no account segment in the path). The app id
|
|
139
|
+
// is passed so the sandbox base path (/<appId>/) is never read as an account.
|
|
140
|
+
const activeAccountId = getActiveAccountIdFromPath(appId);
|
|
141
|
+
if (activeAccountId) {
|
|
142
|
+
config.headers.set("X-Active-Account-Id", activeAccountId);
|
|
143
|
+
}
|
|
134
144
|
}
|
|
135
145
|
const requestId = uuidv4();
|
|
136
146
|
config.requestId = requestId;
|
package/dist/utils/common.d.ts
CHANGED
|
@@ -1,3 +1,12 @@
|
|
|
1
1
|
export declare const isNode: boolean;
|
|
2
2
|
export declare const isInIFrame: boolean;
|
|
3
|
+
/**
|
|
4
|
+
* The active account id from the URL, or undefined.
|
|
5
|
+
*
|
|
6
|
+
* In the sandbox/preview the app is served under `/<appId>/` (the dev-server base
|
|
7
|
+
* path), so the first segment is the app id — its own base, NOT an account. When
|
|
8
|
+
* `appId` is supplied and matches the leading segment, it's skipped so the app id
|
|
9
|
+
* is never sent as an account id; the account, if any, is the next segment.
|
|
10
|
+
*/
|
|
11
|
+
export declare function getActiveAccountIdFromPath(appId?: string): string | undefined;
|
|
3
12
|
export declare const generateUuid: () => string;
|
package/dist/utils/common.js
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
export const isNode = typeof window === "undefined";
|
|
2
2
|
export const isInIFrame = !isNode && window.self !== window.top;
|
|
3
|
+
// Multi-tenancy: apps are served under `/<account_id>/<route>` where the first
|
|
4
|
+
// path segment is a 24-hex Mongo ObjectId. Read it at request time so the active
|
|
5
|
+
// account is always current — even after client-side (Link/useNavigate) account
|
|
6
|
+
// switches that don't reload the module.
|
|
7
|
+
const ACCOUNT_ID_RE = /^[a-f0-9]{24}$/;
|
|
8
|
+
/**
|
|
9
|
+
* The active account id from the URL, or undefined.
|
|
10
|
+
*
|
|
11
|
+
* In the sandbox/preview the app is served under `/<appId>/` (the dev-server base
|
|
12
|
+
* path), so the first segment is the app id — its own base, NOT an account. When
|
|
13
|
+
* `appId` is supplied and matches the leading segment, it's skipped so the app id
|
|
14
|
+
* is never sent as an account id; the account, if any, is the next segment.
|
|
15
|
+
*/
|
|
16
|
+
export function getActiveAccountIdFromPath(appId) {
|
|
17
|
+
if (isNode)
|
|
18
|
+
return undefined;
|
|
19
|
+
const segments = window.location.pathname.split("/").filter(Boolean);
|
|
20
|
+
const candidate = appId && segments[0] === appId ? segments[1] : segments[0];
|
|
21
|
+
return candidate && ACCOUNT_ID_RE.test(candidate) ? candidate : undefined;
|
|
22
|
+
}
|
|
3
23
|
export const generateUuid = () => {
|
|
4
24
|
return (Math.random().toString(36).substring(2, 15) +
|
|
5
25
|
Math.random().toString(36).substring(2, 15));
|