Skip to content

feat: add apiSurface / camelCase input-shape generator for API consumers #20

Description

@stackbilt-admin

Problem

Contracts use snake_case column names aligned to the database (e.g. expiry_date, created_at). FoodFiles API inputs use camelCase (e.g. expiryDate in services/pantry.ts). The package currently has no mechanism to derive a camelCase Zod schema or TypeScript type from a contract definition.

As a result, consumers must hand-roll casing transforms in every service file. This creates a divergence point: the contract schema and the API input schema drift independently, and there is no type-level guarantee that the two shapes agree.

Acceptance Criteria

  • A toApiShape(contract) (or apiSurface(contract)) export returns a Zod schema with camelCase keys derived from the contract's snake_case fields
  • The transform is mechanical (snake_to_camel on field names) so no manual per-field mapping is needed
  • z.infer<ReturnType<typeof toApiShape<typeof PantryItemContract>>> produces the correct camelCase TypeScript type
  • Nested ref() fields are also camelCase in the output (e.g. userId not user_id)
  • Optional: a toDbShape(apiInput) inverse transform is provided for writing validated input back to D1
  • At least one round-trip test: camelCase parse → DB write shape → matches original snake_case contract fields

Context

FoodFiles services/pantry.ts is the concrete failure case: expiryDate in the Zod schema vs expiry_date in PantryItemContract. Resolving this is a prerequisite for collapsing the dual schema sets (the hand-rolled Zod objects in each service file) into contract-derived types.

Ref: CONTRACT-4 gap analysis (phase-0 integration audit)

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions