Skip to content

How Resolution Works

Resolution pipeline

When you call refs.inline(data, { fields }), here's what happens:

Each source collects all needed IDs across the entire tree before fetching. If the same user ID appears as an assignee and a watcher, it's fetched once. IDs not returned by the source are cached as negatives — subsequent resolutions won't re-fetch them until TTL expires.

Fields config

Resolution is driven by a fields object that mirrors the shape of your data:

  • Direct ref: { userId: 'User' }
  • Direct ref array: { userIds: 'User' } (where userIds is Array<string | null | undefined>)
  • Nested ref: { permissionId: { source: 'Permission', fields: { userId: 'User' } } }
  • Structural nesting (into objects/arrays without creating a reference):
    • { profile: { avatarFileId: 'File' } }
    • { items: { productId: 'Product' } } for items: Array<{ productId: ... }>

Output shape (T / Ts)

For a field x:

  • If x is a single ref ID (string | null | undefined), the resolved value is added at xT.
  • If x is an array of ref IDs (Array<string | null | undefined>), the resolved values are added at xTs.

The original ID fields stay as-is; the library returns a cloned object (no mutation).

Null / missing semantics

  • If the ID is null/undefined, the corresponding xT / xTs[i] is null.
  • If the ID is present but not returned by the source, it resolves to null.

Depth limit

Resolution is bounded at 10 levels to prevent infinite loops on circular configs.

Unknown sources

Referencing a source name that doesn't exist at runtime is silently skipped.