/** * Transactions Resource * * CRUD operations, filtering, pagination, and client relationships. * * This is the base (unscoped) resource. For scope-scoped SDKs, use: * - MexTransactionsResource - Mexico-scoped with flattened MX fields * - AVITransactionsResource - Mexico AVI-scoped with flattened AVI fields * - JYSTransactionsResource - Mexico JYS-scoped with flattened JYS fields * - TSCTransactionsResource - Mexico TSC-scoped with flattened TSC fields */ import type { AtomicBatchResult, Checklist, CreateTransactionInput, ListOptions, MigrationPreview, MigrationResult, migrateTransactionInputSchema, PaginatedResponse, PartialBatchResult, RelatedClient, ResourceTagResponse, RiskAssessmentInfo, Scope, TransactionFilter, TransactionSort, UpdateTransactionInput, UpsertResult, UpsertTransactionInput } from "@artu-ai/shared"; import { ClientRole } from "@artu-ai/shared"; import { z } from "zod"; import { Transaction, type TransactionData } from "../models"; import { Evidence } from "../models/Evidence"; import { BaseResource } from "./base"; /** * Options for `transactions.migrate` / `transactions.migratePreview`. The * source-row `id` is supplied as the first argument, so it is omitted here. */ export type MigrateTransactionOptions = Omit, "id">; /** * Base resource manager for transaction operations. * * Provides: * - CRUD operations (create, retrieve, update, delete) * - Filtering and pagination * - Client relationship management (linkClient, unlinkClient) * * @example * ```typescript * // Create a transaction with full nested format * const txn = await sdk.transactions.create({ * amount: 50000, * currency: "MXN", * scopes: ["MX"], * relatedClientIds: ["client_sender"], * timestamp: new Date(), * scopeData: { * MX: { actividadVulnerable: { AVI: { ... } } }, * }, * }); * * // List with filtering * const { data, pagination } = await sdk.transactions.list({ * filter: { status: "completed" }, * limit: 20, * }); * ``` */ export declare class TransactionsResource extends BaseResource { protected scopeFilterKey: "scope" | "scopes" | null; /** * Fetches a product by ID and caches it for the duration of a batch. * Subclasses can override for scope-specific product resources. */ private fetchProduct; /** * Merges product scope data into nested transaction input. * Used by the base (unscoped) resource. User-provided values take precedence. */ protected mergeProductData>(data: T): Promise; /** * Merges product data into flat (scoped) transaction input. * Extracts the scope-specific fields from the product and merges at root level. * * @param scopePath - Path to the scope data in the product scopeData * e.g., ["MX", "actividadVulnerable", "ARI"] */ protected mergeProductDataFlat>(data: T, scopePath: string[]): Promise; /** * Batch version for nested format: fetches all unique products, * then merges into each item. */ protected mergeProductDataBatch>(items: T[]): Promise; /** * Batch version for flat (scoped) format. */ protected mergeProductDataFlatBatch>(items: T[], scopePath: string[]): Promise; /** * Fetches all unique products referenced by a batch of items. * Returns null if no products to fetch. */ private fetchProductsBatch; /** * Creates a new transaction. * * @param data - Transaction creation data in nested format * @returns The created transaction model */ create(data: CreateTransactionInput): Promise; /** * Retrieves a transaction by ID. */ retrieve(id: string, opts?: { crossScope?: boolean; }): Promise; /** * Retrieves the raw, un-instantiated transaction payload by ID. * * The API call is identical across every scope; only the client-side * reshape differs. The React SDK caches this single scope-agnostic payload * and lets each scope derive its own shape via `materialize`, avoiding N * redundant fetches in nested scope-overview components. * * Intentionally does NOT pass `requireScope` (unlike `retrieve`): that is a * client-supplied optional narrowing filter, not the authorization boundary. * Tenant isolation is enforced server-side by RLS and applies identically * here. A shared, id-keyed payload cannot carry a per-scope filter without * leaking one scope's narrowing onto the others sharing the cache entry. * * @param id - Transaction ID * @returns The raw API payload (`TransactionData`) — not a model instance */ retrieveRaw(id: string): Promise; /** * Retrieves a transaction by metadata key/value. */ retrieveByMetadata(key: string, value: string, opts?: { crossScope?: boolean; }): Promise; /** * Retrieves a transaction by externalId. */ retrieveByExternalId(externalId: string, opts?: { crossScope?: boolean; }): Promise; /** * Get the compliance checklist for a transaction in a given scope. * * @param id - The transaction's UUID * @param opts.scope - The scope to evaluate (e.g., "MX:AV:AVI") * @param opts.includeChildren - When true, rollup items include * per-child item arrays. Defaults to true; pass false to receive * only the rollup summaries (useful for list views). */ checklist(id: string, opts: { scope: Scope; includeChildren?: boolean; }): Promise; /** * Updates a transaction. */ update(id: string, data: UpdateTransactionInput): Promise; /** * Deletes a transaction (soft delete). */ delete(id: string): Promise; /** * Lists transactions with optional filtering and pagination. */ list(options?: ListOptions & { crossScope?: boolean; }): Promise>; /** * Counts transactions matching the given filter. * * @param filter - Optional filter criteria * @returns The count of matching transactions */ count(filter?: TransactionFilter, options?: { crossScope?: boolean; }): Promise; /** * Lists all transactions for a specific client. * * @param clientId - The client ID * @param options - Optional pagination options * @returns Paginated list of Transactions */ listByClient(clientId: string, options?: { cursor?: string; limit?: number; }): Promise>; /** * Returns distinct risk assessment names and their display settings. * * @param query - Optional search string to filter assessment names * @returns Array of risk assessment info objects */ getRiskAssessments(query?: string): Promise; /** * Returns an async iterator over all transactions matching the filter. */ iterate(options?: { filter?: TransactionFilter; sort?: TSort; pageSize?: number; crossScope?: boolean; }): AsyncGenerator; /** * Links a client to a transaction with an optional role. */ linkClient(transactionId: string, clientId: string, role?: ClientRole): Promise; /** * Unlinks a client from a transaction. */ unlinkClient(transactionId: string, clientId: string): Promise; /** * Replaces all clients related to a transaction. */ setClients(transactionId: string, clients: RelatedClient[]): Promise; /** * Creates multiple transactions in a single request. * * @param transactions - Array of transaction creation data * @param options - Batch options (atomic: true by default) * @returns Atomic result with data array, or partial result with succeeded/failed */ createMany(transactions: CreateTransactionInput[], options?: { atomic?: true; }): Promise>; createMany(transactions: CreateTransactionInput[], options: { atomic: false; }): Promise>; /** * Updates multiple transactions in a single request. * * @param updates - Array of { id, data } updates * @param options - Batch options (atomic: true by default) * @returns Atomic result with data array, or partial result with succeeded/failed */ updateMany(updates: { id: string; data: UpdateTransactionInput; }[], options?: { atomic?: true; }): Promise>; updateMany(updates: { id: string; data: UpdateTransactionInput; }[], options: { atomic: false; }): Promise>; /** * Creates or updates a transaction by externalId. * * If a transaction with the given externalId exists, it will be updated. * Otherwise, a new transaction will be created. * * @param data - Transaction upsert data (must include externalId) * @returns The created or updated transaction with action indicator */ upsertByExternalId(data: UpsertTransactionInput): Promise>; /** * Creates or updates multiple transactions by externalId in a single request. * * @param transactions - Array of transaction upsert data (each must include externalId) * @param options - Batch options (atomic: true by default) * @returns Atomic result with data array, or partial result with succeeded/failed */ upsertManyByExternalId(transactions: UpsertTransactionInput[], options?: { atomic?: true; }): Promise>>; upsertManyByExternalId(transactions: UpsertTransactionInput[], options: { atomic: false; }): Promise>>; /** * Links an evidence record to a transaction. * * @param input - Transaction ID and evidence ID to link */ linkEvidence(input: { transactionId: string; evidenceId: string; }): Promise; /** * Unlinks an evidence record from a transaction. * * @param input - Transaction ID and evidence ID to unlink */ unlinkEvidence(input: { transactionId: string; evidenceId: string; }): Promise; /** * Lists all evidence records linked to a transaction. * * @param transactionId - Transaction ID * @returns Paginated list of evidence records */ listEvidence(transactionId: string): Promise>; /** * Adds tags to a transaction. */ addTags(id: string, tagIds: string[]): Promise; /** * Removes tags from a transaction. */ removeTags(id: string, tagIds: string[]): Promise; /** * Replaces all tags on a transaction. */ setTags(id: string, tagIds: string[]): Promise; /** * Lists all tags on a transaction. */ listTags(id: string): Promise; /** * Copies this transaction into the other environment (test ↔ live), * upserting it and the selected subresources (evidence, related clients) by * externalId. * * The whole graph is migrated atomically: nothing is written unless every * resource can be matched by externalId. When any resource in the graph * lacks an externalId the call throws {@link MigrationBlockedError} (whose * `blockers` lists the offending resources) and nothing is written — assign * the missing externalIds and retry. * * @param id - Source-environment transaction id * @param options - Target environment, precedence, and subresource selection * @returns The completed migration result (target id, action, per-resource counts) * @throws {MigrationBlockedError} when resources in the graph lack an externalId * * @example * ```typescript * const result = await sdk.transactions.migrate(transactionId, { to: "live" }); * console.log(result.action, result.targetId); * ``` */ migrate(id: string, options: MigrateTransactionOptions): Promise>; /** * Dry-run of {@link migrate}: reports what would be created/updated in the * target environment and any blockers, without writing anything. * * @param id - Source-environment transaction id * @param options - Target environment, precedence, and subresource selection * @returns The migration preview (target action, blockers, per-resource counts) */ migratePreview(id: string, options: MigrateTransactionOptions): Promise; /** * Instantiates a Transaction model from API response data. * Subclasses override this to return their specific model type. */ protected instantiate(data: TransactionData): Transaction; /** * Public, pure transform from a raw transaction payload to this scope's model. * Wraps the protected `instantiate` so the React SDK can apply it inside a * TanStack Query `select`. Subclasses override `instantiate` (and `materialize`), * so each scope materializes its own model type. */ materialize(data: TransactionData): Transaction; }