Services
Service<DocType> (src/services/service.ts) is the base class. Its call surface is
frozen by the service-seam contract snapshot — the same signatures the platform used
pre-Convex — while each service delegates to a ServiceBackend that translates the
filter/update vocabulary into calls against the deployed Convex db/* functions:
import type { BaseDocument } from '../db';
export class Service<DocType extends BaseDocument> {
create(input: Omit<DocType, keyof BaseDocument>): Promise<DocType>;
find(args: { id: string; count?: 1; /* … */ }): Promise<DocType>;
find(args: { filter?: QueryFilter; count?: 1; /* … */ }): Promise<DocType>;
find(args: { filter?: QueryFilter; count?: number; /* … */ }): Promise<DocType[]>;
findById(id: string, projection?, options?): Promise<DocType | null>;
findOneAndUpdate(filter, update?, options?): Promise<DocType | null>;
}The find overload picks the return type from the arguments:
idorcount: 1→ returns a singleDocType(throwsNotFoundErroron a miss).- otherwise → returns
DocType[].
QueryFilter / ProjectionType are local structural aliases (src/models/query-types.ts)
accepting the frozen call-site shapes — plain field filters, $elemMatch/$push
operator objects, dotted projection paths. Backends throw on filter shapes no caller
uses, so an unsupported translation fails loudly instead of returning wrong rows.
Per-service helpers extend this with domain-specific lookups (e.g.
ShopService.findByDomain, ShopService.findByCollaborator). Shop writes funnel
through the atomic db/shop_write:upsertShop Convex mutation.
Usage
import { Shop, User } from '@nordcom/commerce-db';
const shop = await Shop.findByDomain('nordcom-demo-shop.com');
const user = await User.find({ id: someId });
const shops = await Shop.findByCollaborator({ collaboratorId: user.id });Sensitive data
By default, sensitive fields (e.g. collaborators, provider tokens) are absent from
find results — credentials are stored split-out in the Convex shopCredentials
table. Opt in explicitly when you need them:
const shop = await Shop.findByDomain(domain, { sensitiveData: true });Never expose the result of a sensitiveData: true call to client components.