diff --git a/scripts/mintlify-post-processing/copy-to-local-docs.js b/scripts/mintlify-post-processing/copy-to-local-docs.js index 6e6b87ff..f6c4a96f 100644 --- a/scripts/mintlify-post-processing/copy-to-local-docs.js +++ b/scripts/mintlify-post-processing/copy-to-local-docs.js @@ -160,47 +160,72 @@ function updateDocsJson(repoDir, sdkFiles) { `SDK Reference pages: ${JSON.stringify(sdkReferencePages, null, 2)}` ); - // Navigate to: Developers tab -> SDK section -> groups -> SDK Reference - // Supports both legacy "anchors" format and current "dropdowns" format. - const developersTab = docs.navigation.tabs.find( - (tab) => tab.tab === "Developers" - ); - - if (!developersTab) { - console.error("Could not find 'Developers' tab in docs.json"); + // docs.json supports three navigation shapes we've seen in the wild: + // 1. top-level tabs (legacy) navigation.tabs + // 2. top-level tabs with dropdowns/anchors navigation.tabs[].dropdowns | .anchors + // 3. i18n layout (current) navigation.languages[].tabs[]... + // The SDK reference mdx files are English-only, so for every locale we point its + // SDK Reference group at the same English paths. This is what the docs site + // effectively shows today anyway. + // + // We locate the target group by content (any group whose pages reference + // `/sdk/docs/`) rather than by tab/group name, because the surrounding labels + // are translated per locale while the "SDK" dropdown id and the page paths + // stay stable. Preserves the existing translated group label. + const tabsContainers = + docs.navigation.languages?.map((l) => l.tabs).filter(Boolean) ?? + [docs.navigation.tabs].filter(Boolean); + + if (tabsContainers.length === 0) { + console.error("Could not find navigation.tabs or navigation.languages in docs.json"); process.exit(1); } - // Find the SDK section (try dropdowns first, then fall back to anchors) - const sdkAnchor = - developersTab.dropdowns?.find((d) => d.dropdown === "SDK") ?? - developersTab.anchors?.find((a) => a.anchor === "SDK"); - - if (!sdkAnchor) { - console.error("Could not find 'SDK' dropdown or anchor in Developers tab"); - process.exit(1); + const groupReferencesSdkDocs = (group) => + JSON.stringify(group).includes(`${basePath}/`); + + let updatedCount = 0; + for (const tabs of tabsContainers) { + for (const tab of tabs) { + const sdkAnchor = + tab.dropdowns?.find((d) => d.dropdown === "SDK") ?? + tab.anchors?.find((a) => a.anchor === "SDK"); + if (!sdkAnchor?.groups) continue; + + const sdkRefIndex = sdkAnchor.groups.findIndex(groupReferencesSdkDocs); + if (sdkRefIndex === -1) continue; + + const existing = sdkAnchor.groups[sdkRefIndex]; + + // Preserve existing subgroup labels (translated per locale) by position. + // Falls back to the English category-map label when no existing subgroup + // sits at that index (e.g. a locale that gains a new subgroup). + const existingSubgroups = Array.isArray(existing.pages) ? existing.pages : []; + const localizedPages = sdkReferencePages.map((g, i) => ({ + ...g, + group: existingSubgroups[i]?.group ?? g.group, + })); + + sdkAnchor.groups[sdkRefIndex] = { + ...existing, + group: existing.group, + icon: existing.icon ?? "brackets-curly", + expanded: true, + pages: localizedPages, + }; + updatedCount++; + } } - // Find SDK Reference within the SDK anchor's groups - const sdkRefIndex = sdkAnchor.groups.findIndex( - (g) => g.group === "SDK Reference" - ); - - if (sdkRefIndex === -1) { - console.error("Could not find 'SDK Reference' group in SDK anchor"); + if (updatedCount === 0) { + console.error( + "Could not find any SDK Reference navigation group to update (looked for groups whose pages reference '/sdk/docs/')" + ); process.exit(1); } - // Update the SDK Reference pages with our generated groups - sdkAnchor.groups[sdkRefIndex] = { - group: "SDK Reference", - icon: "brackets-curly", - expanded: true, - pages: sdkReferencePages, - }; - // Write updated docs.json - console.log(`Writing updated docs.json to ${docsJsonPath}...`); + console.log(`Writing updated docs.json to ${docsJsonPath} (${updatedCount} locale(s))...`); fs.writeFileSync(docsJsonPath, JSON.stringify(docs, null, 2) + "\n", "utf8"); console.log("Successfully updated docs.json"); diff --git a/src/client.ts b/src/client.ts index a028f337..3965f295 100644 --- a/src/client.ts +++ b/src/client.ts @@ -35,12 +35,12 @@ export type { Base44Client, CreateClientConfig, CreateClientOptions }; * The client supports three authentication modes: * - **Anonymous**: Access modules without authentication using `base44.moduleName`. Operations are scoped to public data and permissions. * - **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. - * - **Service role authentication**: Access modules with elevated permissions using `base44.asServiceRole.moduleName`. Operations can access any data available to the app's admin. Only available in Base44-hosted backend functions. Create a client with service role authentication using {@linkcode createClientFromRequest | createClientFromRequest()}. + * - **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()}. * * For example, when using the {@linkcode EntitiesModule | entities} module: * - **Anonymous**: Can only read public data. * - **User authentication**: Can access the current user's data. - * - **Service role authentication**: Can access all data that admins can access. + * - **Service role authentication**: Can read and write any record, bypassing access rules. * * Most modules are available in all three modes, but with different permission levels. However, some modules are only available in specific authentication modes. * @@ -302,7 +302,7 @@ export function createClient(config: CreateClientConfig): Base44Client { /** * Provides access to service role modules. * - * Service role authentication provides elevated permissions for backend operations. Unlike user authentication, which is scoped to a specific user's permissions, service role authentication has access to the data and operations available to the app's admin. + * 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. * * @throws {Error} When accessed without providing a serviceToken during client creation. * @@ -313,7 +313,7 @@ export function createClient(config: CreateClientConfig): Base44Client { * serviceToken: 'service-role-token' * }); * - * // Also access a module with elevated permissions + * // Read every user record, bypassing the User entity's access rules * const allUsers = await base44.asServiceRole.entities.User.list(); * ``` */ @@ -335,7 +335,7 @@ export function createClient(config: CreateClientConfig): Base44Client { * * This function is designed for use in Base44-hosted backend functions. For frontends and external backends, use {@linkcode createClient | createClient()} instead. * - * 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 provides admin-level permissions. + * 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. * * To learn more about the Base44 client, see {@linkcode createClient | createClient()}. * @@ -374,7 +374,7 @@ export function createClient(config: CreateClientConfig): Base44Client { * try { * const base44 = createClientFromRequest(req); * - * // Access admin data with service role permissions + * // Read across all users, bypassing the Orders entity's access rules * const recentOrders = await base44.asServiceRole.entities.Orders.list('-created_at', 50); * * return Response.json({ orders: recentOrders }); diff --git a/src/client.types.ts b/src/client.types.ts index 6b4c9c57..44c2a6c1 100644 --- a/src/client.types.ts +++ b/src/client.types.ts @@ -54,7 +54,7 @@ export interface CreateClientConfig { */ token?: string; /** - * Service role authentication token. Provides elevated permissions to access data available to the app's admin. Only available in Base44-hosted backend functions. Automatically added to client's created using {@linkcode createClientFromRequest | createClientFromRequest()}. + * Service role authentication token. Provides elevated permissions that bypass entity access rules and field-level security. Only available in Base44-hosted backend functions. Automatically added to clients created using {@linkcode createClientFromRequest | createClientFromRequest()}. * @internal */ serviceToken?: string; @@ -122,7 +122,7 @@ export interface Base44Client { /** * Provides access to supported modules with elevated permissions. * - * Service role authentication provides elevated permissions for backend operations. Unlike user authentication, which is scoped to a specific user's permissions, service role authentication has access to the data and operations available to the app's admin. + * 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. * * @throws {Error} When accessed without providing a serviceToken during client creation */ diff --git a/src/modules/agents.types.ts b/src/modules/agents.types.ts index 49918c0c..51e079da 100644 --- a/src/modules/agents.types.ts +++ b/src/modules/agents.types.ts @@ -207,7 +207,7 @@ export interface AgentsModuleConfig { * This module is available to use with a client in all authentication modes: * * - **Anonymous or User authentication** (`base44.agents`): Access is scoped to the current user's permissions. Users must be authenticated to create and access conversations. - * - **Service role authentication** (`base44.asServiceRole.agents`): Operations have elevated admin-level permissions. Can access all conversations that the app's admin role has access to. + * - **Service role authentication** (`base44.asServiceRole.agents`): Operations are invoked with the service role for backend code that needs elevated permissions. * * ## Generated Types * diff --git a/src/modules/entities.types.ts b/src/modules/entities.types.ts index c5854dd3..f552af63 100644 --- a/src/modules/entities.types.ts +++ b/src/modules/entities.types.ts @@ -724,7 +724,7 @@ type DynamicEntitiesModule = { * This module is available to use with a client in all authentication modes: * * - **Anonymous or User authentication** (`base44.entities`): Access is scoped to the current user's permissions. Anonymous users can only access public entities, while authenticated users can access entities they have permission to view or modify. - * - **Service role authentication** (`base44.asServiceRole.entities`): Operations have elevated admin-level permissions. Can access all entities that the app's admin role has access to. + * - **Service role authentication** (`base44.asServiceRole.entities`): Operations bypass entity access rules and field-level security entirely. Can read and write any record in any entity. * * ## Entity Handlers * @@ -753,7 +753,7 @@ type DynamicEntitiesModule = { * * @example * ```typescript - * // List all users (admin only) + * // List every user, bypassing the User entity's access rules * const allUsers = await base44.asServiceRole.entities.User.list(); * ``` */ diff --git a/src/modules/functions.types.ts b/src/modules/functions.types.ts index b4e8b305..65e5f0d4 100644 --- a/src/modules/functions.types.ts +++ b/src/modules/functions.types.ts @@ -45,7 +45,7 @@ export interface FunctionsModuleConfig { * This module is available to use with a client in all authentication modes: * * - **Anonymous or User authentication** (`base44.functions`): Functions are invoked with the current user's permissions. Anonymous users invoke functions without authentication, while authenticated users invoke functions with their authentication context. - * - **Service role authentication** (`base44.asServiceRole.functions`): Functions are invoked with elevated admin-level permissions. The function code receives a request with admin authentication context. + * - **Service role authentication** (`base44.asServiceRole.functions`): Functions are invoked with the service role for backend code that needs elevated permissions. * * ## Generated Types * diff --git a/src/modules/integrations.types.ts b/src/modules/integrations.types.ts index d7e126c2..89369e7e 100644 --- a/src/modules/integrations.types.ts +++ b/src/modules/integrations.types.ts @@ -393,7 +393,7 @@ export interface CoreIntegrations { * This module is available to use with a client in all authentication modes: * * - **Anonymous or User authentication** (`base44.integrations`): Integration methods are invoked with the current user's permissions. Anonymous users invoke methods without authentication, while authenticated users invoke methods with their authentication context. - * - **Service role authentication** (`base44.asServiceRole.integrations`): Integration methods are invoked with elevated admin-level permissions. The methods execute with admin authentication context. + * - **Service role authentication** (`base44.asServiceRole.integrations`): Integration methods are invoked with the service role for backend code that needs elevated permissions. */ export type IntegrationsModule = { /**