diff --git a/src/index.ts b/src/index.ts index 9ea7892..05632ca 100644 --- a/src/index.ts +++ b/src/index.ts @@ -36,6 +36,8 @@ export * from "./types.js"; export type { EntitiesModule, EntityHandler, + EntityRecord, + EntityTypeRegistry, RealtimeEventType, RealtimeEvent, RealtimeCallback, @@ -71,10 +73,14 @@ export type { CreateFileSignedUrlResult, } from "./modules/integrations.types.js"; -export type { FunctionsModule } from "./modules/functions.types.js"; +export type { + FunctionsModule, + FunctionNameRegistry, +} from "./modules/functions.types.js"; export type { AgentsModule, + AgentNameRegistry, AgentConversation, AgentMessage, AgentMessageReasoning, diff --git a/src/modules/agents.types.ts b/src/modules/agents.types.ts index b437eb2..8b71cc4 100644 --- a/src/modules/agents.types.ts +++ b/src/modules/agents.types.ts @@ -2,6 +2,19 @@ import { AxiosInstance } from "axios"; import { RoomsSocket } from "../utils/socket-utils.js"; import { ModelFilterParams } from "../types.js"; +/** + * Registry of agent names. + * Augment this interface to enable autocomplete for agent names. + */ +export interface AgentNameRegistry {} + +/** + * Agent name type - uses registry keys if augmented, otherwise string. + */ +export type AgentName = keyof AgentNameRegistry extends never + ? string + : keyof AgentNameRegistry; + /** * Reasoning information for an agent message. * @@ -135,7 +148,7 @@ export interface AgentMessage { */ export interface CreateConversationParams { /** The name of the agent to create a conversation with. */ - agent_name: string; + agent_name: AgentName; /** Optional metadata to attach to the conversation. */ metadata?: Record; } @@ -370,5 +383,5 @@ export interface AgentsModule { * // User can open this URL to start a WhatsApp conversation * ``` */ - getWhatsAppConnectURL(agentName: string): string; + getWhatsAppConnectURL(agentName: AgentName): string; } diff --git a/src/modules/entities.types.ts b/src/modules/entities.types.ts index 7460bd0..fbcc0a6 100644 --- a/src/modules/entities.types.ts +++ b/src/modules/entities.types.ts @@ -80,6 +80,37 @@ export type SortField = | `+${keyof T & string}` | `-${keyof T & string}`; +/** + * Fields added by the server to every entity record (id, dates, created_by, etc.). + */ +interface ServerEntityFields { + /** Unique identifier of the record */ + id: string; + /** ISO 8601 timestamp when the record was created */ + created_date: string; + /** ISO 8601 timestamp when the record was last updated */ + updated_date: string; + /** Email of the user who created the record (may be hidden in some responses) */ + created_by?: string | null; + /** ID of the user who created the record */ + created_by_id?: string | null; + /** Whether the record is sample/seed data */ + is_sample?: boolean; +} + +/** + * Registry mapping entity names to their TypeScript types. + * Augment this interface with your entity schema (user-defined fields only). + */ +export interface EntityTypeRegistry {} + +/** + * Full record type for each entity: schema fields + server-injected fields (id, created_date, etc.). + */ +export type EntityRecord = { + [K in keyof EntityTypeRegistry]: EntityTypeRegistry[K] & ServerEntityFields; +}; + /** * Entity handler providing CRUD operations for a specific entity type. * @@ -303,7 +334,7 @@ export interface EntityHandler { * status: 'completed', * priority: 'low' * }); - * console.log('Deleted:', result); + * console.log('Deleted:', result.deleted); * ``` */ deleteMany(query: Partial): Promise; @@ -382,6 +413,20 @@ export interface EntityHandler { subscribe(callback: RealtimeCallback): () => void; } +/** + * Typed entities module - maps registry keys to typed handlers (full record type). + */ +type TypedEntitiesModule = { + [K in keyof EntityTypeRegistry]: EntityHandler; +}; + +/** + * Dynamic entities module - allows any entity name with untyped handler. + */ +type DynamicEntitiesModule = { + [entityName: string]: EntityHandler; +}; + /** * Entities module for managing app data. * @@ -415,18 +460,4 @@ export interface EntityHandler { * const allUsers = await base44.asServiceRole.entities.User.list(); * ``` */ -export interface EntitiesModule { - /** - * Access any entity by name. - * - * Use this to access entities defined in the app. - * - * @example - * ```typescript - * // Access entities dynamically - * base44.entities.MyEntity - * base44.entities.AnotherEntity - * ``` - */ - [entityName: string]: EntityHandler; -} +export type EntitiesModule = TypedEntitiesModule & DynamicEntitiesModule; diff --git a/src/modules/functions.types.ts b/src/modules/functions.types.ts index cdc91a2..95dd123 100644 --- a/src/modules/functions.types.ts +++ b/src/modules/functions.types.ts @@ -1,3 +1,16 @@ +/** + * Registry of function names. + * Augment this interface to enable autocomplete for function names. + */ +export interface FunctionNameRegistry {} + +/** + * Function name type - uses registry keys if augmented, otherwise string. + */ +export type FunctionName = keyof FunctionNameRegistry extends never + ? string + : keyof FunctionNameRegistry; + /** * Functions module for invoking custom backend functions. * @@ -46,5 +59,5 @@ export interface FunctionsModule { * }; * ``` */ - invoke(functionName: string, data: Record): Promise; + invoke(functionName: FunctionName, data?: Record): Promise; } diff --git a/tests/unit/entities.test.ts b/tests/unit/entities.test.ts index 904587f..2a94e40 100644 --- a/tests/unit/entities.test.ts +++ b/tests/unit/entities.test.ts @@ -12,10 +12,10 @@ interface Todo { completed: boolean; } -// Declaration merging: extend EntitiesModule with typed Todo handler +// Module augmentation: register Todo type in EntityTypeRegistry declare module "../../src/modules/entities.types.ts" { - interface EntitiesModule { - Todo: EntityHandler; + interface EntityTypeRegistry { + Todo: Todo; } } diff --git a/tests/unit/functions.test.ts b/tests/unit/functions.test.ts index 3cd7d59..f886d30 100644 --- a/tests/unit/functions.test.ts +++ b/tests/unit/functions.test.ts @@ -2,6 +2,15 @@ import { describe, test, expect, beforeEach, afterEach } from "vitest"; import nock from "nock"; import { createClient } from "../../src/index.ts"; +// Module augmentation: register function names in FunctionNameRegistry +declare module "../../src/modules/functions.types.ts" { + interface FunctionNameRegistry { + sendNotification: true; + processOrder: true; + generateReport: true; + } +} + describe("Functions Module", () => { let base44: ReturnType; let scope;