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:

  • id or count: 1 → returns a single DocType (throws NotFoundError on 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.

On this page