From a7d07f091e161773b946fab62dab364fcef7ef75 Mon Sep 17 00:00:00 2001 From: Sam Markowitz Date: Tue, 17 Feb 2026 09:21:20 +0200 Subject: [PATCH 1/4] Add Apple as supported authentication provider in SDK documentation - Add Apple to loginWithProvider JSDoc with Sign in with Apple link - Include Apple in supported providers list - Add example showing Apple login usage Co-authored-by: Cursor --- src/modules/auth.types.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/modules/auth.types.ts b/src/modules/auth.types.ts index 52dedec..35a2a04 100644 --- a/src/modules/auth.types.ts +++ b/src/modules/auth.types.ts @@ -193,9 +193,10 @@ export interface AuthModule { * Supported providers: * - `'google'` - {@link https://developers.google.com/identity/protocols/oauth2 | Google OAuth}. Enabled by default. * - `'microsoft'` - {@link https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow | Microsoft OAuth}. Enable Microsoft in your app's authentication settings before specifying this provider. - * - `'facebook'` - {@link https://developers.facebook.com/docs/facebook-login | Facebook Login}. Enable this in your app's authentication settings before using. + * - `'facebook'` - {@link https://developers.facebook.com/docs/facebook-login | Facebook Login}. Enable Facebook in your app's authentication settings before using. + * - `'apple'` - {@link https://developer.apple.com/sign-in-with-apple/ | Sign in with Apple}. Enable Apple in your app's authentication settings before using this provider. * - * @param provider - The authentication provider to use: `'google'`, `'microsoft'`, or `'facebook'`. + * @param provider - The authentication provider to use: `'google'`, `'microsoft'`, `'facebook'`, or `'apple'`. * @param fromUrl - URL to redirect to after successful authentication. Defaults to `'/'`. * * @example @@ -209,6 +210,12 @@ export interface AuthModule { * // Login with Microsoft and redirect to dashboard * base44.auth.loginWithProvider('microsoft', '/dashboard'); * ``` + * + * @example + * ```typescript + * // Login with Apple + * base44.auth.loginWithProvider('apple', '/dashboard'); + * ``` */ loginWithProvider(provider: string, fromUrl?: string): void; From f07aaa68f33842360622f5e059dfaf5fc4a09a87 Mon Sep 17 00:00:00 2001 From: Sam Markowitz Date: Tue, 17 Feb 2026 09:26:18 +0200 Subject: [PATCH 2/4] Set SDK reference docs groups to expanded by default - Update file-processing.js to add expanded: true to generated groups - Update copy-to-local-docs.js to preserve expanded: true in nested groups - Ensures Client and Modules groups are open by default in docs Co-authored-by: Cursor --- scripts/mintlify-post-processing/copy-to-local-docs.js | 1 + .../file-processing/file-processing.js | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/scripts/mintlify-post-processing/copy-to-local-docs.js b/scripts/mintlify-post-processing/copy-to-local-docs.js index a50ed8a..a525159 100644 --- a/scripts/mintlify-post-processing/copy-to-local-docs.js +++ b/scripts/mintlify-post-processing/copy-to-local-docs.js @@ -151,6 +151,7 @@ function updateDocsJson(repoDir, sdkFiles) { const sdkReferencePages = Array.from(groupMap.entries()).map( ([groupName, pages]) => ({ group: groupName, + expanded: true, pages: pages.sort(), // Sort pages alphabetically within each group }) ); diff --git a/scripts/mintlify-post-processing/file-processing/file-processing.js b/scripts/mintlify-post-processing/file-processing/file-processing.js index 4599f7f..158843f 100755 --- a/scripts/mintlify-post-processing/file-processing/file-processing.js +++ b/scripts/mintlify-post-processing/file-processing/file-processing.js @@ -361,6 +361,7 @@ function generateDocsJson(docsContent) { if (docsContent.functions.length > 0 && categoryMap.functions) { groups.push({ group: getGroupName("functions", categoryMap), + expanded: true, pages: docsContent.functions, }); } @@ -368,6 +369,7 @@ function generateDocsJson(docsContent) { if (docsContent.interfaces.length > 0 && categoryMap.interfaces) { groups.push({ group: getGroupName("interfaces", categoryMap), + expanded: true, pages: docsContent.interfaces, }); } @@ -375,6 +377,7 @@ function generateDocsJson(docsContent) { if (docsContent.classes.length > 0 && categoryMap.classes) { groups.push({ group: getGroupName("classes", categoryMap), + expanded: true, pages: docsContent.classes, }); } @@ -391,6 +394,7 @@ function generateDocsJson(docsContent) { } else { groups.push({ group: groupName, + expanded: true, pages: docsContent.typeAliases, }); } From 39d647ba5a7c513ce24b9e9d80595dd92e88dee7 Mon Sep 17 00:00:00 2001 From: Sam Markowitz Date: Tue, 17 Feb 2026 10:33:27 +0200 Subject: [PATCH 3/4] Shorten example descriptions for loginWithProvider Changed from verbose descriptions to simple provider names (Google, Microsoft, Apple) Co-authored-by: Cursor --- src/modules/auth.types.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/modules/auth.types.ts b/src/modules/auth.types.ts index 35a2a04..3ced34a 100644 --- a/src/modules/auth.types.ts +++ b/src/modules/auth.types.ts @@ -201,19 +201,19 @@ export interface AuthModule { * * @example * ```typescript - * // Login with Google and return to current page + * // Google * base44.auth.loginWithProvider('google', window.location.pathname); * ``` * * @example * ```typescript - * // Login with Microsoft and redirect to dashboard + * // Microsoft * base44.auth.loginWithProvider('microsoft', '/dashboard'); * ``` * * @example * ```typescript - * // Login with Apple + * // Apple * base44.auth.loginWithProvider('apple', '/dashboard'); * ``` */ From 80ad6f8b661d88f64474c1f5181f86002781c4fa Mon Sep 17 00:00:00 2001 From: Sam Markowitz Date: Thu, 19 Feb 2026 11:45:37 +0200 Subject: [PATCH 4/4] Improve SortField type documentation and linking - Export SortField type from SDK index - Configure SortField to be embedded in entities page (not standalone) - Add post-processing to integrate clickable type links naturally into ParamField descriptions - Clean up SortField signature display for better readability - Update JSDoc for SortField with clearer bullet points and improved example - Fix ServerEntityFields JSDoc to accurately list fields - Remove standalone "See" links in favor of integrated description links Co-authored-by: Cursor --- .../appended-articles.json | 3 +- .../file-processing/file-processing.js | 79 +++++++++++++++++++ .../typedoc-mintlify-parameters.js | 47 +++++++++-- .../types-to-delete-after-processing.json | 3 +- .../types-to-expose.json | 1 + src/index.ts | 1 + src/modules/entities.types.ts | 12 +-- 7 files changed, 132 insertions(+), 14 deletions(-) diff --git a/scripts/mintlify-post-processing/appended-articles.json b/scripts/mintlify-post-processing/appended-articles.json index 4c2d346..cb83dff 100644 --- a/scripts/mintlify-post-processing/appended-articles.json +++ b/scripts/mintlify-post-processing/appended-articles.json @@ -2,7 +2,8 @@ "type-aliases/EntitiesModule": [ "interfaces/EntityHandler", "type-aliases/EntityRecord", - "interfaces/EntityTypeRegistry" + "interfaces/EntityTypeRegistry", + "type-aliases/SortField" ], "interfaces/FunctionsModule": [ "type-aliases/FunctionName", diff --git a/scripts/mintlify-post-processing/file-processing/file-processing.js b/scripts/mintlify-post-processing/file-processing/file-processing.js index 158843f..437639c 100755 --- a/scripts/mintlify-post-processing/file-processing/file-processing.js +++ b/scripts/mintlify-post-processing/file-processing/file-processing.js @@ -1220,6 +1220,79 @@ function applyNonExposedTypeLinkRemoval(dir, exposedTypeNames) { } } +/** + * Add clickable links for types in ParamFields that reference types on the same page + */ +function addTypeLinksToParamFields(dir) { + if (!fs.existsSync(dir)) return; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const entry of entries) { + const entryPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + addTypeLinksToParamFields(entryPath); + } else if ( + entry.isFile() && + (entry.name.endsWith(".mdx") || entry.name.endsWith(".md")) + ) { + let content = fs.readFileSync(entryPath, "utf-8"); + let modified = false; + + // Integrate clickable link into the description for SortField type + // Pattern: \n\nSort parameter, ... + // Replace with: \n\nA [`SortField`](#sortfield) specifying sort order, ... + const paramFieldPattern = /(]*type=")(SortField<([^>]*)>)("[^>]*>\n\n)Sort parameter,/g; + + content = content.replace(paramFieldPattern, (match, prefix, fullType, generic, suffix) => { + modified = true; + return `${prefix}${fullType}${suffix}A [\`${fullType}\`](#sortfield) specifying sort order,`; + }); + + if (modified) { + fs.writeFileSync(entryPath, content, "utf-8"); + console.log(`Added type links to ParamFields: ${path.relative(DOCS_DIR, entryPath)}`); + } + } + } +} + +/** + * Clean up SortField type signature to be more readable + */ +function cleanupSortFieldSignature(dir) { + if (!fs.existsSync(dir)) return; + const entries = fs.readdirSync(dir, { withFileTypes: true }); + for (const entry of entries) { + const entryPath = path.join(dir, entry.name); + if (entry.isDirectory()) { + cleanupSortFieldSignature(entryPath); + } else if ( + entry.isFile() && + (entry.name.endsWith(".mdx") || entry.name.endsWith(".md")) + ) { + let content = fs.readFileSync(entryPath, "utf-8"); + let modified = false; + + // Replace the complex SortField signature with a cleaner version + // Match: > **SortField**\<`T`\> = ... & ... | `` `+${(...) & (...)}` `` | `` `-${(...) & (...)}` `` + // Replace with: > **SortField**\<`T`\> = `string` | `` `+${string}` `` | `` `-${string}` `` + const sortFieldSignaturePattern = /> \*\*SortField\*\*\\<`T`\\> = \.\.\. & \.\.\. \| `` `\+\$\{\(\.\.\.\) & \(\.\.\.\)\}` `` \| `` `-\$\{\(\.\.\.\) & \(\.\.\.\)\}` ``/; + + if (sortFieldSignaturePattern.test(content)) { + content = content.replace( + sortFieldSignaturePattern, + "> **SortField**\\<`T`\\> = `keyof T` | `` `+${keyof T}` `` | `` `-${keyof T}` ``" + ); + modified = true; + } + + if (modified) { + fs.writeFileSync(entryPath, content, "utf-8"); + console.log(`Cleaned SortField signature: ${path.relative(DOCS_DIR, entryPath)}`); + } + } + } +} + /** * Main function */ @@ -1288,6 +1361,12 @@ function main() { const appendedArticles = loadAppendedArticlesConfig(); applyAppendedArticles(appendedArticles); + // Add clickable links for types in ParamFields + addTypeLinksToParamFields(DOCS_DIR); + + // Clean up SortField signature specifically (before general signature cleanup) + cleanupSortFieldSignature(DOCS_DIR); + // Clean up signatures: fix truncated generics, simplify keyof constraints, break long lines applySignatureCleanup(DOCS_DIR); diff --git a/scripts/mintlify-post-processing/typedoc-plugin/typedoc-mintlify-parameters.js b/scripts/mintlify-post-processing/typedoc-plugin/typedoc-mintlify-parameters.js index a5388be..759eed7 100644 --- a/scripts/mintlify-post-processing/typedoc-plugin/typedoc-mintlify-parameters.js +++ b/scripts/mintlify-post-processing/typedoc-plugin/typedoc-mintlify-parameters.js @@ -289,7 +289,23 @@ function parseParametersWithExpansion( if (!line) return null; const trimmed = line.trim(); - // Handle [`TypeName`](link) format first (backticks inside the link) + // Handle [`TypeName`](link)\<`T`\> format (with generics after the link) + const linkWithBackticksAndGenericsMatch = trimmed.match(/^\[`([^`]+)`\]\(([^)]+)\)(.*)$/); + if (linkWithBackticksAndGenericsMatch) { + const typeName = linkWithBackticksAndGenericsMatch[1]; + const link = linkWithBackticksAndGenericsMatch[2]; + const generics = linkWithBackticksAndGenericsMatch[3].trim(); + + // If there are generics, append them to the type name (cleaning up markdown escapes) + const fullType = generics ? typeName + generics.replace(/\\/g, '') : typeName; + + return { + type: fullType, + link: link, + }; + } + + // Handle [`TypeName`](link) format (backticks inside the link, no generics) const linkWithBackticksMatch = trimmed.match(/^\[`([^`]+)`\]\(([^)]+)\)$/); if (linkWithBackticksMatch) { return { @@ -518,6 +534,7 @@ function parseParametersWithExpansion( params.push({ name: cleanName, type: type, + typeLink: typeLink, // Preserve the link description: descriptionLines.join("\n").trim(), optional, nested, @@ -571,7 +588,23 @@ function parseParameters( if (!line) return null; const trimmed = line.trim(); - // Handle [`TypeName`](link) format first (backticks inside the link) + // Handle [`TypeName`](link)\<`T`\> format (with generics after the link) + const linkWithBackticksAndGenericsMatch = trimmed.match(/^\[`([^`]+)`\]\(([^)]+)\)(.*)$/); + if (linkWithBackticksAndGenericsMatch) { + const typeName = linkWithBackticksAndGenericsMatch[1]; + const link = linkWithBackticksAndGenericsMatch[2]; + const generics = linkWithBackticksAndGenericsMatch[3].trim(); + + // If there are generics, append them to the type name (cleaning up markdown escapes) + const fullType = generics ? typeName + generics.replace(/\\/g, '') : typeName; + + return { + type: fullType, + link: link, + }; + } + + // Handle [`TypeName`](link) format (backticks inside the link, no generics) const linkWithBackticksMatch = trimmed.match(/^\[`([^`]+)`\]\(([^)]+)\)$/); if (linkWithBackticksMatch) { return { @@ -826,16 +859,16 @@ function buildParamFieldsSection( for (const param of params) { const requiredAttr = param.optional ? "" : " required"; - // Track non-primitive parameter types for suppression - - fieldsOutput += `\n`; + // Clean up the type string by removing markdown backticks + let typeAttr = param.type.replace(/`/g, ''); + fieldsOutput += `\n`; // Always show description in ParamField if it exists if (param.description) { - fieldsOutput += `\n${param.description}\n`; + fieldsOutput += `\n${param.description}`; } - fieldsOutput += "\n\n"; + fieldsOutput += "\n\n\n"; // If param has nested fields, wrap them in an Accordion if (param.nested.length > 0) { diff --git a/scripts/mintlify-post-processing/types-to-delete-after-processing.json b/scripts/mintlify-post-processing/types-to-delete-after-processing.json index 1b79c6c..392e12e 100644 --- a/scripts/mintlify-post-processing/types-to-delete-after-processing.json +++ b/scripts/mintlify-post-processing/types-to-delete-after-processing.json @@ -1,5 +1,6 @@ [ "DeleteManyResult", "DeleteResult", - "ImportResult" + "ImportResult", + "SortField" ] diff --git a/scripts/mintlify-post-processing/types-to-expose.json b/scripts/mintlify-post-processing/types-to-expose.json index 2cd803c..20229cf 100644 --- a/scripts/mintlify-post-processing/types-to-expose.json +++ b/scripts/mintlify-post-processing/types-to-expose.json @@ -19,5 +19,6 @@ "ImportResult", "IntegrationsModule", "CoreIntegrations", + "SortField", "SsoModule" ] diff --git a/src/index.ts b/src/index.ts index 4ae03a9..d772c1a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -44,6 +44,7 @@ export type { RealtimeEventType, RealtimeEvent, RealtimeCallback, + SortField, } from "./modules/entities.types.js"; export type { diff --git a/src/modules/entities.types.ts b/src/modules/entities.types.ts index ebc04c4..3376ff3 100644 --- a/src/modules/entities.types.ts +++ b/src/modules/entities.types.ts @@ -61,13 +61,16 @@ export interface ImportResult { /** * Sort field type for entity queries. * - * Supports ascending (no prefix or `'+'`) and descending (`'-'`) sorting. + * Accepts any field name from the entity type with an optional prefix: + * - `'+'` prefix or no prefix: ascending sort + * - `'-'` prefix: descending sort * * @typeParam T - The entity type to derive sortable fields from. * * @example * ```typescript - * // Ascending sort (default) + * // Specify sort direction by prefixing field names with + or - + * // Ascending sort * 'created_date' * '+created_date' * @@ -81,7 +84,7 @@ export type SortField = | `-${keyof T & string}`; /** - * Fields added by the server to every entity record (id, dates, created_by, etc.). + * Fields added by the server to every entity record, such as `id`, `created_date`, `updated_date`, and `created_by`. */ interface ServerEntityFields { /** Unique identifier of the record */ @@ -108,8 +111,7 @@ export interface EntityTypeRegistry {} * * @example * ```typescript - * import type { EntityRecord } from '@base44/sdk'; - * + * // Using EntityRecord to get the complete type for an entity * // Combine your schema with server fields (id, created_date, etc.) * type TaskRecord = EntityRecord['Task']; *