/** * Products Resource * * CRUD operations, filtering, pagination, and upsert. * * This is the base (unscoped) resource. For scope-scoped SDKs, use: * - MexProductsResource - Mexico-scoped with flattened MX fields * - ARIProductsResource - Mexico ARI-scoped with flattened ARI fields * - AVIProductsResource - Mexico AVI-scoped with flattened AVI fields * - JYSProductsResource - Mexico JYS-scoped with flattened JYS fields * - MJRProductsResource - Mexico MJR-scoped with flattened MJR fields * - TSCProductsResource - Mexico TSC-scoped with flattened TSC fields * - TransmisorProductsResource - Mexico Transmisor-scoped with flattened Transmisor fields */ import type { CreateProductInput, ListOptions, PaginatedResponse, ProductFilter, ProductSort, ResourceTagResponse, UpdateProductInput, UpsertProductInput, UpsertResult } from "@artu-ai/shared"; import { Product, type ProductData } from "../models"; import { BaseResource } from "./base"; /** * Base resource manager for product operations. * * Provides: * - CRUD operations (create, retrieve, update, delete) * - Filtering and pagination * - Upsert by externalId * * @example * ```typescript * // Create a product with full nested format * const product = await sdk.products.create({ * name: "Premium Plan", * scopes: ["MX:AV:ARI"], * scopeData: { * MX: { actividadVulnerable: { ARI: { ... } } }, * }, * }); * * // List with filtering * const { data, pagination } = await sdk.products.list({ * filter: { name: { contains: "Premium" } }, * limit: 20, * }); * ``` */ export declare class ProductsResource extends BaseResource { protected scopeFilterKey: "scope" | "scopes" | null; /** * Creates a new product. * * @param data - Product creation data in nested format * @returns The created product model */ create(data: CreateProductInput): Promise; /** * Retrieves a product by ID. */ retrieve(id: string, opts?: { crossScope?: boolean; }): Promise; /** * Retrieves the raw, un-instantiated product 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 - Product ID * @returns The raw API payload (`ProductData`) — not a model instance */ retrieveRaw(id: string): Promise; /** * Retrieves a product by externalId. */ retrieveByExternalId(externalId: string, opts?: { crossScope?: boolean; }): Promise; /** * Updates a product. * * @param id - Product ID * @param data - Update data * @param options - Optional settings * @param options.propagateToTransactions - If true, updates all linked * transactions with the product's new scope data */ update(id: string, data: UpdateProductInput, options?: { propagateToTransactions?: boolean; }): Promise; /** * Propagates the product's scope data to all linked transactions. * Product values override transaction values; transaction-only fields are preserved. * * @param id - Product ID * @returns The number of transactions updated */ propagateToTransactions(id: string): Promise<{ count: number; }>; /** * Deletes a product (soft delete). */ delete(id: string): Promise; /** * Lists products with optional filtering and pagination. */ list(options?: ListOptions & { crossScope?: boolean; }): Promise>; /** * Counts products matching the given filter. * * @param filter - Optional filter criteria * @returns The count of matching products */ count(filter?: ProductFilter, options?: { crossScope?: boolean; }): Promise; /** * Returns an async iterator over all products matching the filter. */ iterate(options?: { filter?: ProductFilter; sort?: TSort; pageSize?: number; crossScope?: boolean; }): AsyncGenerator; /** * Creates or updates a product by externalId. * * If a product with the given externalId exists, it will be updated. * Otherwise, a new product will be created. * * @param data - Product upsert data (must include externalId) * @returns The created or updated product with action indicator */ upsertByExternalId(data: UpsertProductInput): Promise>; /** * Adds tags to a product. */ addTags(id: string, tagIds: string[]): Promise; /** * Removes tags from a product. */ removeTags(id: string, tagIds: string[]): Promise; /** * Replaces all tags on a product. */ setTags(id: string, tagIds: string[]): Promise; /** * Lists all tags on a product. */ listTags(id: string): Promise; /** * Instantiates a Product model from API response data. * Subclasses override this to return their specific model type. */ protected instantiate(data: ProductData): Product; /** * Public, pure transform from a raw product 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: ProductData): Product; }