feat(entities): add Data Fabric Entity v3 (composite entity) service#586
feat(entities): add Data Fabric Entity v3 (composite entity) service#586RohanKharvi1211 wants to merge 1 commit into
Conversation
Adds the full v3 Entity API as a new modular service EntityV3Service, exposed via the @uipath/uipath-typescript/entities-v3 subpath. Additive — the existing v1/v2 Entities service is unchanged. v3 introduces composite entities (a logical entity backed by multiple related "member" tables). Every read/query resolves to EntityV3WriteResponse records and every write returns an EntityV3WriteResponse; composite children are keyed by member instance name. Record field values are returned untransformed (Data Fabric schema contract). Surface (~43 methods): name-addressed data plane (read/query/query_expansion/ insert/insert-batch/insert_bulk/upsert/update/updateByKey/update-batch/ update-where/delete/delete-batch), id-addressed schema (getById/getMetadata/ create[single+composite]/deleteById/updateMetadata/field CUD), composite members (query/read/readByKey/delete + member field CUD), attachments, and autopilot manage + streaming. Adds a general RESPONSE_TYPES.STREAM path to ApiClient for the SSE stream endpoint. Verified offline: typecheck, lint, unit tests (154 new v3 tests), build. NOT yet live-validated (no PAT): the composite create + schema-write request body shapes are derived from backend source + LLD + swagger and must be confirmed against a live tenant before release. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| DOWNLOAD: (entityName: string, recordId: string, fieldName: string) => | ||
| `${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`, | ||
| UPLOAD: (entityName: string, recordId: string, fieldName: string) => | ||
| `${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`, | ||
| DELETE: (entityName: string, recordId: string, fieldName: string) => | ||
| `${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`, |
There was a problem hiding this comment.
Per convention, duplicate URL-pattern constants must either be collapsed or carry an explicit comment explaining the intentional duplication. There are four sets of duplicates in this file that need it:
ENTITY.LISTandENTITY.CREATE— both equalV3_BASEENTITY.GET_BY_IDandENTITY.DELETE_BY_ID— both produce${V3_BASE}/${entityId}ENTITY.FIELD.UPDATEandENTITY.FIELD.DELETE— both produce${V3_BASE}/${entityId}/field/${fieldId}- These three attachment constants — all produce the same
${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}URL
For attachment-group (and the field pair), distinct names aid readability, so a comment is the right fix. For example:
| DOWNLOAD: (entityName: string, recordId: string, fieldName: string) => | |
| `${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`, | |
| UPLOAD: (entityName: string, recordId: string, fieldName: string) => | |
| `${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`, | |
| DELETE: (entityName: string, recordId: string, fieldName: string) => | |
| `${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`, | |
| // Attachments (by entity name) — DOWNLOAD, UPLOAD, and DELETE share the same URL path; | |
| // the HTTP method (GET / POST / DELETE) is resolved at the call site. | |
| ATTACHMENT: { | |
| DOWNLOAD: (entityName: string, recordId: string, fieldName: string) => | |
| `${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`, | |
| UPLOAD: (entityName: string, recordId: string, fieldName: string) => | |
| `${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`, | |
| DELETE: (entityName: string, recordId: string, fieldName: string) => | |
| `${V3_BASE}/${entityName}/records/${recordId}/attachments/${fieldName}`, | |
| }, |
Apply equivalent comments at the other three duplicate sites (lines 80–85 and 110–111).
| * @returns Promise resolving to the new entity id (single) or composite descriptor {@link EntityV3CreateResponse} | ||
| * @example | ||
| * ```typescript | ||
| * import { EntityFieldDataType } from '@uipath/uipath-typescript/entities'; |
There was a problem hiding this comment.
Per convention, @example imports must be self-contained and copy-pasteable — they should import from the same subpath the user would already have imported. EntityFieldDataType is re-exported from @uipath/uipath-typescript/entities-v3 (see src/services/data-fabric/entities-v3/index.ts), so the example import should use that path, not entities.
| * import { EntityFieldDataType } from '@uipath/uipath-typescript/entities'; | |
| * import { EntityFieldDataType } from '@uipath/uipath-typescript/entities-v3'; |
The same fix applies to four other occurrences in this file:
- Line 207 (
EntityFieldDataTypeincreateFieldexample) - Line 302 (
LogicalOperator,QueryFilterOperatorinqueryexample) - Line 454 (
QueryFilterOperatorinupdateWhereexample) - Line 615 (
EntityFieldDataTypeincreateMemberFieldexample)
In each case, replace '@uipath/uipath-typescript/entities' with '@uipath/uipath-typescript/entities-v3'.
|
Two findings this run. 1. Duplicate endpoint constants without comments in data-fabric.ts (lines 116-121): Four sets of constants share identical URL patterns. Convention requires either collapsing them or adding an explanatory comment that HTTP-method differences are resolved at the call site. 2. JSDoc examples use wrong subpath in entities-v3.models.ts (line 157 + 4 others): Five examples import EntityFieldDataType, LogicalOperator, or QueryFilterOperator from entities instead of entities-v3 where they are already re-exported. Examples must be importable from the subpath the user is already using. |
Summary
Adds the full v3 Data Fabric Entity API as a new modular service,
EntityV3Service, exposed via the@uipath/uipath-typescript/entities-v3subpath (aliasEntitiesV3). Additive — the existing v1/v2Entitiesservice is untouched.v3 introduces composite entities: a logical business entity backed by multiple related member tables (a tree linked by FKs). Every read/query resolves to
EntityV3WriteResponserecords and every write returns anEntityV3WriteResponse; composite child records are keyed by member instance name underchildren. Non-composite entities return an emptychildrenmap, so callers use one record model everywhere. Record field values are returned exactly as the API sends them (Data Fabric schema columns are user-defined — casing is part of the schema contract and is never transformed).Methods Added
New service
EntitiesV3(@uipath/uipath-typescript/entities-v3). Data ops are addressed by entity name; schema ops by entity id.getAll,getAllWithChoiceSets,getFolderEntities,getById,getMetadatacreate(single + composite),deleteById,updateMetadata,createField,updateField,deleteFieldgetRecords,getRecord,getRecordByKey,query,queryWithExpansioninsert,insertRecords,insertBulk,upsert,update,updateByKey,updateRecords,updateWhere,deleteRecord,deleteRecords,deleteRecordsBatchqueryMember,getMemberRecords,getMemberRecord,getMemberRecordByKey,deleteMemberRecord,deleteMemberRecords,createMemberField,updateMemberField,deleteMemberField,deleteMemberFieldHarddownloadAttachment,uploadAttachment,deleteAttachmentmanageWithAutopilot,manageWithAutopilotStream(SSE)getById/getMetadatareturn an entity with bound operation methods (entity.getRecords(),entity.query(),entity.insert(),entity.delete(), …) capturing the entity's name (data ops) and id (schema ops).Endpoints
All under base
…/dataservice_/api/v3/entities(DATA_FABRIC_V3_ENDPOINTS). OAuth scopes: data opsDataFabric.Data.Read/Write; schema opsDataFabric.Schema.Read/Write(full table indocs/oauth-scopes.md).query/api/v3/entities/{entityName}/querygetRecords/api/v3/entities/{entityName}/readinsert/api/v3/entities/{entityName}/insertqueryMember/api/v3/entities/{compositeName}/members/{memberName}/querygetById/api/v3/entities/{entityId}create/api/v3/entitiesmanageWithAutopilotStream/api/v3/entities/autopilot/manage/streamExample Usage
Response model
EntityV3WriteResponserecords (value/totalRecordCountenvelope unwrapped by the pagination layer).getRecords/query/queryMember/getMemberRecordssupport SDK pagination (offset-based,limit/start).EntityV3WriteResponse(root fields flattened +childrenmap). Batch ops →EntityV3BatchResponse(per-record success/failure). Member deletes →EntityV3MemberDeleteResponse(with cascade counts).EntityV3Metadata,compositeInfo) is returned wire-close.Composition / infra notes
childrenare keyed by member instance name; each block carriesrecords,hasMore, and a server-providedreffor paging remaining children.manageWithAutopilotStreamreturns aReadableStream<Uint8Array>— enabled by a new generalRESPONSE_TYPES.STREAMpath added toApiClient(returns the raw body without buffering; sits after the 204 short-circuit).async(guards reject, matching the v1 pattern) and use directreturn(noawait).Files
src/utils/constants/endpoints/data-fabric.ts(DATA_FABRIC_V3_ENDPOINTS)src/models/data-fabric/entities-v3.types.tssrc/models/data-fabric/entities-v3.models.ts(EntityV3ServiceModel,EntityV3Methods, factory)src/services/data-fabric/entities-v3.tssrc/services/data-fabric/entities-v3/index.ts,src/models/data-fabric/index.ts,package.json,rollup.config.jssrc/core/http/api-client.ts,src/utils/constants/headers.ts(RESPONSE_TYPES.STREAM)tests/unit/services/data-fabric/entities-v3.test.ts(89),tests/unit/models/data-fabric/entities-v3.test.ts(65)tests/integration/shared/data-fabric/entities-v3.integration.test.ts(v1-only),tests/integration/config/unified-setup.tsdocs/oauth-scopes.md,mkdocs.ymlFollow-ups before release
create+ schema-write (createField/updateField/updateMetadata/member field) request bodies against a tenant withDataFabric.Schema.Write./api/v3/entitiesroutes in Cloudflare Workers (apps-dev-tools— not accessible in the authoring environment; pattern:new RegExp('^\\/${DATAFABRIC_BASE}\\/api\\/v3\\/entities')and sub-paths).🤖 Auto-generated using onboarding skills