Skip to content

Preserve typed service names and paths in one schema - #107

Merged
KidkArolis merged 7 commits into
masterfrom
codex/preserve-service-path-types
Aug 26, 2026
Merged

Preserve typed service names and paths in one schema#107
KidkArolis merged 7 commits into
masterfrom
codex/preserve-service-path-types

Conversation

@KidkArolis

@KidkArolis KidkArolis commented Aug 17, 2026

Copy link
Copy Markdown
Collaborator

What changed

  • preserve both the literal schema name and literal transport path on every materialized Service
  • make service<T>() return an unbound declaration whose path defaults to its eventual schema key
  • add service<T>().at('api/path') for handwritten aliases without repeating the path in a generic and a value
  • add service.from<ApiSchemaTypes>() for generated, path-keyed service catalogs, where the selected path determines both the runtime path and service contract
  • model default-path and path-bound declarations as separate states, without nullable path generics or constructor casts
  • make createSchema() the sole materialization boundary and reject empty or duplicate transport paths
  • keep name and path namespaces explicit: builders, relationships, and current mutation APIs use schema names; descriptors, raw Feathers access, and deprecated hooks use transport paths
  • expose explicit ServiceByName, ServiceByPath, and ServiceDefinitionByPath utilities instead of an ambiguous name-or-path lookup
  • retain support for a schema name matching another service's transport path because the calling API determines the namespace
  • make schema-bound useFeathers() return the actual underlying client with path-derived types, without a pass-through proxy

API

Handwritten schemas:

const schema = createSchema({
  services: {
    tasks: service<TaskService>(),
    people: service<PersonService>().at('api/people'),
  },
})

Generated path catalogs:

const apiService = service.from<ApiSchemaTypes>()

const schema = createSchema({
  services: {
    people: apiService('api/people'),
    companies: apiService('api/companies'),
  },
})

The object key supplies the Figbird name. The explicit path or catalog selection supplies the transport path. createSchema() produces one materialized schema carrying both.

Why

Applications migrating gradually to named Figbird APIs should not need a parallel "legacy schema" for path-based hooks. The previous PR iteration preserved paths, but declaring one required repeating the same literal in a generic and at runtime, and the generic ServiceByIdentifier utility became ambiguous when the name and path namespaces overlapped.

This version makes the two namespaces first-class and deliberately separate while keeping a single source of service types. It also gives schema generators a compact, checked API: unknown catalog paths fail at compile time and automatically select the matching backend contract.

Validation

  • npm run tsc
  • npm run lint
  • npm run build
  • npx ava test/type-inference.test.ts test/schema.test.tsx — 12 tests passed
  • npm test — type-checking, lint, formatting, coverage, and all 359 tests passed

@KidkArolis
KidkArolis force-pushed the codex/preserve-service-path-types branch from 50e2ee5 to 36405e8 Compare August 26, 2026 20:26
@KidkArolis KidkArolis changed the title Preserve service path types across schema APIs Preserve typed service names and paths in one schema Aug 26, 2026
@KidkArolis
KidkArolis marked this pull request as ready for review August 26, 2026 21:09
@KidkArolis
KidkArolis merged commit 4148388 into master Aug 26, 2026
1 check passed
@KidkArolis
KidkArolis deleted the codex/preserve-service-path-types branch August 26, 2026 21:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant