import { c as CorsairEntity, a as CorsairAccount, d as CorsairEvent, b as CorsairIntegration } from './index-eydqYIn0.js'; export { f as CorsairAccountsSchema, g as CorsairEntitiesSchema, h as CorsairEventsSchema, e as CorsairIntegrationsSchema } from './index-eydqYIn0.js'; import { ZodTypeAny, z } from 'zod'; import { CorsairDatabase } from './db.js'; import 'kysely'; import 'pg'; import 'postgres'; type CorsairOrmDatabase = { corsair_integrations: CorsairIntegration; corsair_accounts: CorsairAccount; corsair_entities: CorsairEntity; corsair_events: CorsairEvent; }; type CorsairOrmTableName = keyof CorsairOrmDatabase; /** * Input type for creating a new row (without auto-generated fields). */ type CreateInput = Omit & { id?: string; }; /** * Input type for updating an existing row. */ type UpdateInput = Partial>; /** * Where clause builder for type-safe filtering. */ type WhereClause = { [K in keyof T]?: T[K] | { in: T[K][]; } | { like: string; }; }; /** * Base table ORM client with common CRUD operations. */ type CorsairTableClient = { findById: (id: string) => Promise; findOne: (where: WhereClause) => Promise; findMany: (options?: { where?: WhereClause; limit?: number; offset?: number; }) => Promise; create: (data: CreateInput) => Promise; update: (id: string, data: UpdateInput) => Promise; updateMany: (where: WhereClause, data: UpdateInput) => Promise; delete: (id: string) => Promise; deleteMany: (where: WhereClause) => Promise; count: (where?: WhereClause) => Promise; }; type CorsairIntegrationsClient = CorsairTableClient & { findByName: (name: string) => Promise; upsertByName: (name: string, data: Omit, 'name'>) => Promise; }; type CorsairAccountsClient = CorsairTableClient & { findByTenantAndIntegration: (tenantId: string, integrationName: string) => Promise; listByTenant: (tenantId: string, options?: { limit?: number; offset?: number; }) => Promise; upsertByTenantAndIntegration: (tenantId: string, integrationId: string, data: Omit, 'tenant_id' | 'integration_id'>) => Promise; }; type CorsairEntitiesClient = CorsairTableClient & { findByEntityId: (options: { accountId: string; entityType: string; entityId: string; }) => Promise; findManyByEntityIds: (options: { accountId: string; entityType: string; entityIds: string[]; }) => Promise; listByScope: (options: { accountId: string; entityType: string; limit?: number; offset?: number; }) => Promise; searchByEntityId: (options: { accountId: string; entityType: string; query: string; limit?: number; offset?: number; }) => Promise; upsertByEntityId: (options: { accountId: string; entityType: string; entityId: string; version: string; data: Record; }) => Promise; deleteByEntityId: (options: { accountId: string; entityType: string; entityId: string; }) => Promise; }; type CorsairEventsClient = CorsairTableClient & { listByAccount: (accountId: string, options?: { limit?: number; offset?: number; }) => Promise; listByStatus: (status: 'pending' | 'processing' | 'completed' | 'failed', options?: { accountId?: string; limit?: number; offset?: number; }) => Promise; listPending: (options?: { accountId?: string; limit?: number; }) => Promise; updateStatus: (id: string, status: 'pending' | 'processing' | 'completed' | 'failed') => Promise; }; type CorsairOrm = { integrations: CorsairIntegrationsClient; accounts: CorsairAccountsClient; entities: CorsairEntitiesClient; events: CorsairEventsClient; }; /** * Creates the base Corsair ORM with all table clients. */ declare function createCorsairOrm(database: CorsairDatabase | undefined): CorsairOrm; /** * Plugin schema definition - maps entity type names to their Zod data schemas. */ type CorsairPluginSchema> = { version: string; entities: Entities; }; /** * Typed entity with plugin-specific data type. */ type TypedEntity = Omit & { data: z.infer; }; /** * Filter value for entity table columns (e.g., entity_id, version). * Supports exact matches, string operations (for string fields), and array membership. * * @example * // Exact match (shorthand) * { entity_id: "C0123456789" } * * @example * // Explicit equals * { entity_id: { equals: "C0123456789" } } * * @example * // String contains (LIKE '%value%') * { entity_id: { contains: "C012" } } * * @example * // String starts with (LIKE 'value%') * { entity_id: { startsWith: "C012" } } * * @example * // String ends with (LIKE '%value') * { entity_id: { endsWith: "6789" } } * * @example * // Match any value in array (IN clause) * { entity_id: { in: ["C0123456789", "C9876543210"] } } */ type SearchFilterValue = T | { /** Exact match. Equivalent to passing the value directly. */ equals?: T; /** String contains (LIKE '%value%'). Only available for string fields. */ contains?: T extends string ? string : never; /** String starts with (LIKE 'value%'). Only available for string fields. */ startsWith?: T extends string ? string : never; /** String ends with (LIKE '%value'). Only available for string fields. */ endsWith?: T extends string ? string : never; /** Match any value in array (IN clause). */ in?: T[]; }; /** * Filter for string fields in JSONB data. * Supports exact matches, substring search, prefix/suffix matching, and array membership. * * @example * // Exact match (shorthand) * { data: { name: "general" } } * * @example * // Explicit equals * { data: { name: { equals: "general" } } } * * @example * // Contains substring (LIKE '%value%') * { data: { name: { contains: "gen" } } } * * @example * // Starts with prefix (LIKE 'value%') * { data: { name: { startsWith: "gen" } } } * * @example * // Ends with suffix (LIKE '%value') * { data: { name: { endsWith: "eral" } } } * * @example * // Match any value in array (IN clause) * { data: { name: { in: ["general", "random", "announcements"] } } } */ type StringDataFilter = string | { /** Exact match. Equivalent to passing the string directly. */ equals?: string; /** Contains substring (LIKE '%value%'). Case-sensitive. */ contains?: string; /** Starts with prefix (LIKE 'value%'). Case-sensitive. */ startsWith?: string; /** Ends with suffix (LIKE '%value'). Case-sensitive. */ endsWith?: string; /** Match any value in array (IN clause). */ in?: string[]; }; /** * Filter for number fields in JSONB data. * Supports exact matches, range comparisons, and array membership. * * @example * // Exact match (shorthand) * { data: { count: 42 } } * * @example * // Explicit equals * { data: { count: { equals: 42 } } } * * @example * // Greater than * { data: { count: { gt: 10 } } } * * @example * // Greater than or equal * { data: { count: { gte: 10 } } } * * @example * // Less than * { data: { count: { lt: 100 } } } * * @example * // Less than or equal * { data: { count: { lte: 100 } } } * * @example * // Match any value in array (IN clause) * { data: { count: { in: [10, 20, 30] } } } */ type NumberDataFilter = number | { /** Exact match. Equivalent to passing the number directly. */ equals?: number; /** Greater than (>). */ gt?: number; /** Greater than or equal (>=). */ gte?: number; /** Less than (<). */ lt?: number; /** Less than or equal (<=). */ lte?: number; /** Match any value in array (IN clause). */ in?: number[]; }; /** * Filter for boolean fields in JSONB data. * Supports exact matches only. * * @example * // Exact match (shorthand) * { data: { is_private: true } } * * @example * // Explicit equals * { data: { is_private: { equals: false } } } */ type BooleanDataFilter = boolean | { /** Exact match. Equivalent to passing the boolean directly. */ equals?: boolean; }; /** * Filter for date fields in JSONB data. * Supports exact matches, before/after comparisons, and date ranges. * * @example * // Exact match (shorthand) * { data: { created_at: new Date("2024-01-01") } } * * @example * // Explicit equals * { data: { created_at: { equals: new Date("2024-01-01") } } } * * @example * // Before date (<) * { data: { created_at: { before: new Date("2024-12-31") } } } * * @example * // After date (>) * { data: { created_at: { after: new Date("2024-01-01") } } } * * @example * // Between two dates (inclusive) * { data: { created_at: { between: [new Date("2024-01-01"), new Date("2024-12-31")] } } } */ type DateDataFilter = Date | { /** Exact match. Equivalent to passing the Date directly. */ equals?: Date; /** Before date (<). */ before?: Date; /** After date (>). */ after?: Date; /** Between two dates (inclusive). First element is start, second is end. */ between?: [Date, Date]; }; /** * Filter value for JSONB data fields, automatically selected based on field type. * Supports different filter operations depending on the data type: * - String: exact match, contains, startsWith, endsWith, in * - Number: exact match, gt, gte, lt, lte, in * - Boolean: exact match only * - Date: exact match, before, after, between * * @example * // String field * { data: { name: { contains: "test" } } } * * @example * // Number field * { data: { count: { gt: 10 } } } * * @example * // Boolean field * { data: { is_private: true } } * * @example * // Date field * { data: { created_at: { after: new Date("2024-01-01") } } } */ type DataFilterValue = T extends Date ? DateDataFilter : T extends number ? NumberDataFilter : T extends boolean ? BooleanDataFilter : T extends string ? StringDataFilter : never; /** * Fields that are automatically filtered by the ORM (not user-searchable). */ type AutoFilteredFields = 'account_id' | 'entity_type'; /** * Fields that require special handling (pagination, data). */ type SpecialFields = 'data' | 'created_at' | 'updated_at'; /** * Searchable entity fields derived from CorsairEntity. * Excludes auto-filtered fields and special fields. */ type SearchableEntityFields = Omit; /** * Search filter for entity table columns (derived from CorsairEntity). * Maps each searchable field to SearchFilterValue. */ type EntityFieldsFilter = { [K in keyof SearchableEntityFields]?: SearchFilterValue; }; /** * Search filter for JSONB data fields. * Only supports top-level fields. Nested objects (like topic, purpose) are excluded. * Each field uses the appropriate filter type based on its data type. * * @example * // Filter by multiple data fields * { * data: { * name: { contains: "general" }, * is_private: false, * member_count: { gte: 10 } * } * } * * @example * // String field with contains * { * data: { * name: { contains: "test" } * } * } * * @example * // Number field with range * { * data: { * count: { gt: 5, lt: 100 } * } * } * * @example * // Date field with range * { * data: { * created_at: { between: [new Date("2024-01-01"), new Date("2024-12-31")] } * } * } */ type DataSearchFilter = { [K in keyof z.infer]?: z.infer[K] extends string | number | boolean | Date | null | undefined ? DataFilterValue[K]>> : never; }; /** * Search options for querying entities. * Supports filtering by entity table columns (entity_id, version, etc.) and JSONB data fields. * All filters are combined with AND logic. * * @example * // Search by entity_id (exact match) * await tenant.slack.db.channels.search({ * entity_id: "C0123456789" * }); * * @example * // Search by entity_id with contains * await tenant.slack.db.channels.search({ * entity_id: { contains: "C012" } * }); * * @example * // Search by JSONB data field (exact match) * await tenant.slack.db.channels.search({ * data: { name: "general" } * }); * * @example * // Search by JSONB data field with contains * await tenant.slack.db.channels.search({ * data: { name: { contains: "gen" } } * }); * * @example * // Search with multiple filters * await tenant.slack.db.channels.search({ * entity_id: { startsWith: "C" }, * data: { * name: { contains: "test" }, * is_private: false, * member_count: { gte: 10 } * }, * limit: 20, * offset: 0 * }); * * @example * // Search with number range * await tenant.slack.db.channels.search({ * data: { * member_count: { gt: 5, lt: 100 } * } * }); * * @example * // Search with date range * await tenant.slack.db.channels.search({ * data: { * created_at: { between: [new Date("2024-01-01"), new Date("2024-12-31")] } * } * }); * * @example * // Search with pagination * await tenant.slack.db.channels.search({ * data: { name: { contains: "test" } }, * limit: 50, * offset: 100 * }); */ type EntitySearchOptions = EntityFieldsFilter & { /** * Filter by JSONB data fields. * Supports top-level fields only. Each field type has specific filter options. * * @example * { data: { name: { contains: "test" } } } * * @example * { data: { count: { gt: 10 } } } * * @example * { data: { is_private: false } } */ data?: DataSearchFilter; /** * Maximum number of results to return. * * @example * { limit: 50 } */ limit?: number; /** * Number of results to skip (for pagination). * * @example * { offset: 100 } */ offset?: number; }; /** * Entity client for a specific plugin entity type (e.g., slack.messages). * Provides typed access to entities with the entity type's data schema. */ type PluginEntityClient = { /** Find by external entity ID (e.g., Slack message ts). */ findByEntityId: (entityId: string) => Promise | null>; /** Check if an entity exists by external entity ID without loading payload data. */ existsByEntityId: (entityId: string) => Promise; /** Find internal UUID by external entity ID without loading payload data. */ findIdByEntityId: (entityId: string) => Promise; /** Find by internal UUID. */ findById: (id: string) => Promise | null>; /** Find multiple by external entity IDs. */ findManyByEntityIds: (entityIds: string[]) => Promise[]>; /** List all entities for this entity type. */ list: (options?: { limit?: number; offset?: number; }) => Promise[]>; /** * Search entities with typed filters. * Supports filtering by entity table columns and JSONB data fields with various operators. * All filters are combined with AND logic. * * @example * // Search by entity_id (exact match) * await tenant.slack.db.channels.search({ * entity_id: "C0123456789" * }); * * @example * // Search by entity_id with contains (LIKE '%value%') * await tenant.slack.db.channels.search({ * entity_id: { contains: "C012" } * }); * * @example * // Search by entity_id with startsWith (LIKE 'value%') * await tenant.slack.db.channels.search({ * entity_id: { startsWith: "C" } * }); * * @example * // Search by JSONB data field (exact match) * await tenant.slack.db.channels.search({ * data: { name: "general" } * }); * * @example * // Search by JSONB string field with contains * await tenant.slack.db.channels.search({ * data: { name: { contains: "gen" } } * }); * * @example * // Search by JSONB number field with range * await tenant.slack.db.channels.search({ * data: { member_count: { gt: 10, lt: 100 } } * }); * * @example * // Search by JSONB boolean field * await tenant.slack.db.channels.search({ * data: { is_private: false } * }); * * @example * // Search by JSONB date field with range * await tenant.slack.db.channels.search({ * data: { created_at: { between: [new Date("2024-01-01"), new Date("2024-12-31")] } } * }); * * @example * // Search with multiple filters and pagination * await tenant.slack.db.channels.search({ * entity_id: { startsWith: "C" }, * data: { * name: { contains: "test" }, * is_private: false, * member_count: { gte: 10 } * }, * limit: 20, * offset: 0 * }); */ search: (options: EntitySearchOptions) => Promise[]>; /** Create or update by external entity ID. */ upsertByEntityId: (entityId: string, data: z.input) => Promise>; /** Delete by internal UUID. */ deleteById: (id: string) => Promise; /** Delete by external entity ID. */ deleteByEntityId: (entityId: string) => Promise; /** Count entities for this entity type. */ count: () => Promise; }; /** * Maps a plugin schema to its typed entity clients. */ type PluginEntityClients> = { [K in keyof Entities]: PluginEntityClient; }; /** * Context for tenant-scoped operations. * This is set synchronously and used to filter all subsequent operations. */ type TenantContext = { tenantId: string; }; /** * Context for plugin operations. * Includes tenant and integration info for account-scoped filtering. */ type PluginContext = { tenantId: string; integrationName: string; }; /** * Full plugin ORM with typed entity clients + access to base tables. */ type CorsairPluginOrm> = PluginEntityClients & { /** Access to the base ORM for raw table operations. */ $orm: CorsairOrm; /** The integration name this ORM is scoped to. */ $integrationName: string; /** The tenant ID this ORM is scoped to. */ $tenantId: string; /** Get the account ID (async, fetches from DB). */ $getAccountId: () => Promise; }; /** * Tenant-scoped ORM that filters all operations by tenant. */ type TenantScopedOrm = { /** The tenant ID this ORM is scoped to. */ $tenantId: string; /** Access to the base ORM. */ $orm: CorsairOrm; /** List all accounts for this tenant. */ listAccounts: (options?: { limit?: number; offset?: number; }) => Promise; /** Find an account by integration name for this tenant. */ findAccountByIntegration: (integrationName: string) => Promise; /** List all entities for this tenant (across all accounts). */ listEntities: (options?: { entityType?: string; limit?: number; offset?: number; }) => Promise; /** List all events for this tenant (across all accounts). */ listEvents: (options?: { status?: 'pending' | 'processing' | 'completed' | 'failed'; limit?: number; offset?: number; }) => Promise; /** Create a plugin ORM scoped to this tenant and an integration. */ forIntegration: >(config: { integrationName: string; schema: CorsairPluginSchema; }) => CorsairPluginOrm; }; /** * Creates a plugin ORM with typed entity clients. * * @example * ```ts * const SlackSchema = { * version: '1.0.0', * entities: { * messages: SlackMessageSchema, * channels: SlackChannelSchema, * users: SlackUserSchema, * }, * } as const; * * const slackOrm = createPluginOrm(database, { * integrationName: 'slack', * schema: SlackSchema, * tenantId: 'tenant-123', * }); * * // Typed entity access * const message = await slackOrm.messages.findByEntityId('1234567890.123456'); * // message.data is typed as SlackMessage * * await slackOrm.channels.upsertByEntityId('C123', { * id: 'C123', * name: 'general', * is_private: false, * }); * * // Access base ORM for raw operations * const allAccounts = await slackOrm.$orm.accounts.listByTenant('tenant-123'); * ``` */ declare function createPluginOrm>(config: { database: CorsairDatabase | undefined; integrationName: string; schema: CorsairPluginSchema; tenantId: string; }): CorsairPluginOrm; /** * Creates a tenant-scoped ORM that filters all operations by tenant. * This is a synchronous operation - the tenant context is just stored * and used when actual database operations are performed. * * @example * ```ts * const tenantOrm = createTenantScopedOrm(database, 'tenant-123'); * * // List all accounts for this tenant * const accounts = await tenantOrm.listAccounts(); * * // Create a plugin ORM for a specific integration * const slackOrm = tenantOrm.forIntegration({ * integrationName: 'slack', * schema: SlackSchema, * }); * * // All operations are scoped to tenant-123 and the slack integration * const messages = await slackOrm.messages.list(); * ``` */ declare function createTenantScopedOrm(database: CorsairDatabase | undefined, tenantId: string): TenantScopedOrm; /** * Creates a plugin ORM factory for a specific integration. * Useful when you need to switch tenants frequently. * * @example * ```ts * const slackOrmFactory = createPluginOrmFactory(database, { * integrationName: 'slack', * schema: SlackSchema, * }); * * const tenant1Orm = slackOrmFactory.forTenant('tenant-1'); * const tenant2Orm = slackOrmFactory.forTenant('tenant-2'); * ``` */ declare function createPluginOrmFactory>(database: CorsairDatabase | undefined, config: { integrationName: string; schema: CorsairPluginSchema; }): { forTenant: (tenantId: string) => CorsairPluginOrm; }; export { CorsairAccount, CorsairAccount as CorsairAccountRow, type CorsairAccountsClient, type CorsairEntitiesClient, CorsairEntity, CorsairEntity as CorsairEntityRow, CorsairEvent, CorsairEvent as CorsairEventRow, type CorsairEventsClient, CorsairIntegration, CorsairIntegration as CorsairIntegrationRow, type CorsairIntegrationsClient, type CorsairOrm, type CorsairOrmDatabase, type CorsairOrmTableName, type CorsairPluginOrm, type CorsairPluginSchema, type CorsairTableClient, type PluginContext, type PluginEntityClient, type PluginEntityClients, type TenantContext, type TenantScopedOrm, type TypedEntity, createCorsairOrm, createPluginOrm, createPluginOrmFactory, createTenantScopedOrm };