Write an adapter

An adapter connects one point-of-sale system. Orderable handles hours, lead times, zones, quotes, policy, idempotency and storage, so the adapter only translates.

interface Adapter {
  readonly name: string;
  listBusinesses(): Promise<Business[]>;
  listLocations(): Promise<Location[]>;
  getMenu(locationId: string): Promise<Menu>;
  getItem(itemId: string): Promise<Item | null>;
  getAvailability(locationId: string, itemIds: string[]): Promise<StockLevel[]>;
  quote(req: PricingRequest): Promise<PricingResult>;
  placeOrder(req: AdapterOrderRequest): Promise<AdapterOrderResult>;
  getOrderStatus(externalId: string, order: Order): Promise<AdapterOrderStatus>;
  cancelOrder(externalId: string, reason: string, order: Order): Promise<{ cancelled: boolean }>;
}

Rules

  1. Map, don't invent. No allergen data in the POS means all unknown. Untracked stock means status: "unknown".
  2. Be honest about freshness. as_of is when the POS last confirmed the data, not when you read your cache.
  3. Money in minor units with an explicit currency.
  4. Throw OrderableError for expected failures; anything else becomes ADAPTER_ERROR.
  5. Use Orderable's order_id as the POS idempotency key so a retried send never duplicates there either.

Start from

Planned: Square (finish), Toast, Clover, Shopify, Lightspeed. Tell us which one you need.