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' }(whereuserIdsisArray<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' } }foritems: Array<{ productId: ... }>
Output shape (T / Ts)
For a field x:
- If
xis a single ref ID (string | null | undefined), the resolved value is added atxT. - If
xis an array of ref IDs (Array<string | null | undefined>), the resolved values are added atxTs.
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 correspondingxT/xTs[i]isnull. - 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.