feat(data-fabric): add folderKey support to entities.getAll and ChoiceSets surface#504
Conversation
…eSets surface entities.getAll now accepts an optional folderKey to retrieve folder-scoped entities; the API filters exclusively (tenant scope vs folder scope are disjoint), confirmed against the live API. ChoiceSets methods all accept folderKey and forward it as the X-UIPATH-FolderKey header. Critically, insertValueById and updateValueById hard-fail on folder-scoped choice sets without the header — and their internal name resolver (resolveChoiceSetName) now scopes its getAll lookup by the same folderKey so the path stops throwing NotFoundError before the API call. Adds folder-scoped @example blocks to JSDoc on every Entities method that already supported folderKey but didn't document it, integration coverage for the new getAll filter, and a skipped folder-scoped ChoiceSets block mirroring the existing OAuth-scope-gated value-CRUD pattern. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
| expect(mockApiClient.get).toHaveBeenCalledWith( | ||
| DATA_FABRIC_ENDPOINTS.ENTITY.GET_ALL, | ||
| {}, | ||
| { headers: {} }, |
There was a problem hiding this comment.
This test covers getAll() with no options ({ headers: {} }), but there's no test for getAll({ folderKey: '...' }) verifying the X-UIPATH-FolderKey header is set. Every other Entities method that gained folderKey support already has a matching "should pass folderKey via X-UIPATH-FolderKey header" test (e.g. getById at line 129, getAllRecords at line 488). getAll should follow the same pattern:
it('should pass X-UIPATH-FolderKey header when folderKey is provided', async () => {
mockApiClient.get.mockResolvedValue([]);
await entityService.getAll({ folderKey: ENTITY_TEST_CONSTANTS.FIELD_ID });
expect(mockApiClient.get).toHaveBeenCalledWith(
DATA_FABRIC_ENDPOINTS.ENTITY.GET_ALL,
{ headers: { 'X-UIPATH-FolderKey': ENTITY_TEST_CONSTANTS.FIELD_ID } },
);
});
Review findingsTwo missing unit tests for the new
Everything else (implementation, type definitions, JSDoc, integration tests structure) looks correct. |
… header tests - Sync ChoiceSetServiceModel JSDoc with service-class JSDoc on getById, deleteById, and deleteValuesById (model is the docs source of truth). - Service-class JSDoc on the same three methods updated with @param options and folder-scoped @example blocks for parity. - Consolidate folder-scoped choice-set integration cleanup into the file-level afterAll (removes the duplicate afterAll inside the describe.skip block per the rules.md convention). - Add unit tests asserting X-UIPATH-FolderKey forwarding for every choice-set method that gained folderKey support (getAll, getById, create, updateById, deleteById, insertValueById, updateValueById, deleteValuesById) and for entities.getAll, matching the pattern already used on other Entities methods. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
✅ No issues found. Checked for bugs and CLAUDE.md compliance. |
…egration tests
Adds an opt-in `referenceFolderKey` on EntityCreateFieldOptions so callers can
create entities whose RELATIONSHIP / CHOICE_SET fields point at targets in a
different folder (or the tenant SYSTEM scope). The SDK assembles the minimum
payload each API path needs:
- Relationship targets: { id, folderId } — both come straight from caller inputs,
no extra round-trip. Verified against alpha: the relationship endpoint
resolves by folderId.
- Choice-set targets: { id, name, folderId, entityType, entityTypeId } — the
CS endpoint resolves by name, so the SDK does one GET on the target to fetch
it (parallelized across fields). Verified against alpha: bare {id} or
{id, folderId} both 403 with empty target name; {id, name} succeeds.
Tenant marker (DATA_FABRIC_TENANT_FOLDER_ID, all-zeros) is supported as a
referenceFolderKey value — the SDK looks up the target at tenant scope (no
folder header) and emits folderId: '00000000-...'.
Integration tests:
- Folder-scoped record CRUD (insert/get/update/delete + batch variants, plus
queryRecordsById) — runs in CI against DATA_FABRIC_TEST_FOLDER_ENTITY_ID
+ INTEGRATION_TEST_FOLDER_KEY.
- Folder-scoped Choice value CRUD — describe.skip'd alongside the other
schema-write blocks (requires DataFabric.Schema.Write OAuth scope); the
block locates its target CS by name (`aIntegrationTestFolderScoped`)
via getAll({ folderKey }) so it doesn't need a CS-ID env var.
- buildDummyRecord helper now threads folderKey into getChoiceSetValues so
folder-scoped ChoiceSetSingle/Multiple fields get populated correctly.
Unit tests:
- 3 new tests covering the new opt-in path: cross-folder relationship
(no GET, embeds {id, folderId}), tenant-marker CS lookup (no folder header
on the GET), folder-UUID CS lookup (sends X-UIPATH-FolderKey).
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Reverts the prior commit's accidental check-in of tenant-specific test config and a personal PAT into the example file. The example should only carry placeholder values; live config belongs in the gitignored .env.integration. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Review findingsOne new finding this run:
Everything else — implementation, type definitions, JSDoc, and all unit test coverage for the folderKey header paths — looks correct. |
|
✅ No issues found. Checked for bugs and CLAUDE.md compliance. |
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Review findingsOne new finding this run:
|
…l constants Replaces inline 'ChoiceSet' / 1 literals in buildReferenceMeta with the existing EntityType.ChoiceSet enum and a new ENTITY_TYPE_IDS map. Pairs the two values that travel together in reference payloads. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Review findingsOne new finding this run:
|
) Add an optional `includeAllFolders` flag to `EntityGetAllOptions`. When true (and no `folderKey` is provided), `getAll` lists tenant-level and folder-level entities together via the v2 entity endpoint. Existing behavior is unchanged: no flag lists only tenant entities, and a `folderKey` always wins — scoping to that single folder and ignoring `includeAllFolders`. Documents the additional `OR.Users` scope required for folder-scoped entity operations and the combined listing. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…n entities.getAll The flag returns BOTH tenant-level and folder-level entities together — "all folders" was misleading on two counts: it sounded folder-only (excluding tenant entities), and tenant isn't a "folder." "Scopes" is the right abstraction since Data Fabric entities have two scopes (tenant + folder) and the flag toggles "give me everything regardless of scope." Renames across types, service implementation, JSDoc, unit + integration tests, endpoint comment, and oauth-scopes docs. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Review findingsOne new finding this run:
|
…erKey JSDoc DATA_FABRIC_TENANT_FOLDER_ID is an internal endpoint constant not exported through the public API barrel, so users had no way to resolve the reference. Inlines the literal '00000000-0000-0000-0000-000000000000' so the JSDoc is self-contained. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
| @@ -469,6 +506,14 @@ export class EntityService extends BaseService implements EntityServiceModel { | |||
| /** | |||
| * Gets all entities in the system | |||
There was a problem hiding this comment.
JSDoc first-line is out of sync with EntityServiceModel. This PR changed the model's summary to "Gets entities in the system" (entities.models.ts:56) but left the implementation unchanged at "Gets all entities in the system". Per conventions: "Keep JSDoc on service class methods in sync with {Entity}ServiceModel — both the models file and the service implementation file must have identical JSDoc for each public method."
| * Gets all entities in the system | |
| * Gets entities in the system |
Review findingsOne new finding this run:
|
|
✅ No issues found. Checked for bugs and CLAUDE.md compliance. |
| * Three call modes: | ||
| * - `getAll({ includeFolderChoiceSets: false })` — default. Returns only tenant-level choice sets. No `OR.Users` scope required. | ||
| * - `getAll({ includeFolderChoiceSets: true })` — returns tenant-level **and** folder-level choice sets together. Requires the `OR.Users` OAuth scope. | ||
| * - `getAll({ includeFolderChoiceSets: false, folderKey: "<uuid>" })` — returns only choice sets in that folder. `folderKey` always wins over `includeFolderChoiceSets`. |
There was a problem hiding this comment.
folderKey is preferred over includeFolderChoiceSets
Folder-scoped Data Fabric is still in preview. Surface that everywhere the SDK exposes it: - Type-level: add @experimental on EntityFolderScopedOptions.folderKey, EntityGetAllOptions.includeFolderEntities, and EntityCreateFieldOptions .referenceFolderKey. TypeDoc renders these as Experimental badges in the generated reference tables. - Method-level: add a "> **Experimental:** ..." blockquote to every Entities method that documents folderKey (getAll, getById, getAllRecords, getRecordById, queryRecordsById, insertRecordById, insertRecordsById, updateRecordById, updateRecordsById, updateById, deleteRecordById, deleteRecordsById, deleteById, uploadAttachment, downloadAttachment, deleteAttachment, importRecordsById, create). - Kept JSDoc in sync between entities.models.ts (TypeDoc source of truth) and entities.ts (service class). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
- "Gets choice sets in the org" → "Gets choice sets in the tenant".
- Default call mode is now shown as `getAll()`, not
`getAll({ includeFolderChoiceSets: false })`.
- Reorder call modes so `folderKey` is presented as the preferred way
to scope to a folder, with `includeFolderChoiceSets` reframed as the
wider tenant + folder option.
Kept the JSDoc in sync between ChoiceSetServiceModel and the
ChoiceSetService class.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Mirror the choicesets.getAll review fixes onto the entities surface:
- "Gets entities in the system" → "Gets entities in the tenant".
- Default call mode is now shown as `getAll()`, not
`getAll({ includeFolderEntities: false })`.
- Reorder call modes so `folderKey` is presented as the preferred way
to scope to a folder, with `includeFolderEntities` reframed as the
wider tenant + folder option.
Kept JSDoc in sync between EntityServiceModel and the EntityService class.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
✅ No issues found. Checked for bugs and CLAUDE.md compliance. |
Review findingsOne new finding this run:
|
Review findingsOne new finding this run:
|
Every Entities and ChoiceSets method that accepts a `folderKey` option now carries the `@experimental` JSDoc tag, so TypeDoc renders an `Experimental` badge directly under the method signature in the generated reference docs — alongside the existing blockquote that calls out `folderKey` specifically as the experimental property. Choicesets also gains the "folder scope is experimental" blockquote on each affected method (entities already had it). Kept JSDoc in sync between the ServiceModel interfaces and the service-class implementations. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
✅ No issues found. Checked for bugs and CLAUDE.md compliance. |
Per PR feedback — remove `OR.Users` references from user-facing JSDoc on the entities and choicesets `getAll` methods and on the related option field comments. Internal code comments that explain endpoint-selection logic stay (they're not rendered in public docs). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
✅ No issues found. Checked for bugs and CLAUDE.md compliance. |
Method-level `@experimental` tags and `> **Experimental:** ...` blockquotes removed from every Entities and ChoiceSets method that takes `folderKey`. The experimental marker now lives only at the argument level: - Type-level: `@experimental` JSDoc tag on the `folderKey` property (already in `EntityFolderScopedOptions`) and `includeFolderChoiceSets` (added here for parity with `includeFolderEntities`). TypeDoc renders these as `Experimental` badges on the property rows of every linked options-type page. - Method-level: each `@param options - ...` line now ends with `The \`folderKey\` property is **experimental**.` — visible directly in the rendered parameter table of every folderKey-bearing method. `updateValueById` (ChoiceSets) previously had no `@param options` line; added one so the marker reaches that method too. ServiceModel ↔ service class JSDoc kept in sync per project convention. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
✅ No issues found. Checked for bugs and CLAUDE.md compliance. |
…scopes Removes the two leftover blockquote notes in docs/oauth-scopes.md that called out `OR.Users` for folder-scoped Entities and ChoiceSets. The remaining `OR.Users` rows in that file are unrelated (User Settings service endpoints). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Review findingsOne new finding this run:
|
Addresses outstanding Claude bot review feedback on PR #504: - Drop the `as unknown as ChoiceSetGetResponse` intermediate cast in `getById`'s `transformFn` — a single `as ChoiceSetGetResponse` is sufficient when `pascalToCamelCaseKeys()` precedes `transformData()` in the pipeline (returns `any`). - Remove the `as any` cast on the `PaginationHelpers.getAll()` return in `getById` — TypeScript infers the conditional return type correctly without it. - Use typed `EntityType.ChoiceSet` + `ENTITY_TYPE_IDS[…]` in `entities.test.ts` instead of raw `"ChoiceSet"` / `1` literals so the assertion stays in sync if the enum or type-id mapping changes. Also fixes a follow-on `entityType: 0` literal that the new enum import surfaced. - Fix the double `@track('Choicesets.GetAll')` telemetry from `resolveChoiceSetName` calling `this.getAll()`: extract an un-tracked `fetchAllChoiceSets` helper that both `getAll()` and `resolveChoiceSetName` call directly. - Extract `EntityFolderScopedOptions` into a new shared `src/models/data-fabric/data-fabric.types.ts` so `choicesets.types` no longer imports across service domains from `entities.types`. `entities.types` re-exports for backward compatibility with the public barrel. Also: reword the `folderKey` precedence note from "folderKey (when provided) always wins over this flag" to "folderKey is preferred over includeFolder{Entities,ChoiceSets} when both are set" everywhere it appears (model JSDoc, service JSDoc, type-level field JSDoc, inline implementation comments). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Review findingsOne new finding this run:
|
… OR.Users from DF source - `ReferenceEntityPayload.entityType` was typed `string`, losing type safety and autocomplete. The `EntityType` enum already covers every valid value, and the only call site (`buildReferenceMeta`) already passes `EntityType.ChoiceSet`. Narrow to `entityType?: EntityType`. - Remove the last three `OR.Users` references from Data Fabric source files (endpoint comment for `GET_ALL_V2`, inline `getAll` comment in the entity service, inline `fetchAllChoiceSets` comment). The remaining `OR.Users` mentions in the repo are unrelated SDK auth examples and the User Settings service rows in oauth-scopes.md. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Review findingsUnresolved thread:
|
|



Summary
entities.getAllnow accepts an optionalfolderKey. The Data Fabric entity list filter is exclusive: omittingfolderKeyreturns only tenant entities; passingfolderKeyreturns only entities in that folder. Verified against alpha.folderKeythrough every public method and sendsX-UIPATH-FolderKey. Two endpoints —insertValueByIdandupdateValueById— hard-fail with 400 "Entity not found at tenant level" on folder-scoped choice sets without the header. Confirmed against alpha.ChoiceSetService.resolveChoiceSetNamenow scopes itsgetAlllookup by the suppliedfolderKey, fixing a path that previously threwNotFoundErrorfor folder-scoped choice sets before the API call was even reached.@exampleblocks updated on everyEntitiesmethod that already supportedfolderKeybut didn't show it (getAllRecords,getRecordById,insertRecord*,updateRecord*,deleteRecordsById,queryRecordsById).Behavior table — verified against alpha
X-UIPATH-FolderKeyEntities.getAllChoiceSets.getAllChoiceSets.insertValueByIdChoiceSets.updateValueByIdEntities/ChoiceSetsby-ID endpointsTest plan
npm run typecheckcleannpm run lint0 warnings / 0 errorsnpm run test:unit— 1728/1728 passing (updated 10 assertions to expect the new{ headers: {} }shape on the calls that gained the third arg)entities.getAllfolder filter — runs wheneverINTEGRATION_TEST_FOLDER_KEYis set; throws (not silent-skips) if missingdescribe.skip('Folder-scoped operations')block tochoicesets.integration.test.tscovering create/list/value-CRUD/delete withfolderKey— skipped for the sameDataFabric.Schema.WriteOAuth scope reason that gates the existing tenant-scope value-CRUD blockINTEGRATION_TEST_FOLDER_KEYset against a tenant that has folder-scoped DF entities🤖 Generated with Claude Code