@uipath/skills 1.202.1-preview.868 → 1.202.1-preview.894

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uipath/skills",
3
- "version": "1.202.1-preview.868",
3
+ "version": "1.202.1-preview.894",
4
4
  "description": "UiPath agent skills for Claude Code, Codex, Cursor, Copilot, Gemini and OpenCode — RPA, UI automation, UI testing, coded agents/apps/workflows, and troubleshooting. Distributed as the UiPath Claude Code plugin.",
5
5
  "author": {
6
6
  "name": "UiPath"
@@ -2,6 +2,8 @@
2
2
 
3
3
  Signatures/params/examples: `dist/entities/index.d.ts` (trigger-event behavior differs per method — the JSDoc on each insert/update/delete method documents it). Per-method scopes: shipped `docs/oauth-scopes.md`. This file covers only what neither can express.
4
4
 
5
+ > **Record and attachment methods take an entity ref as their first argument** — `{ id: <entityId> }` or `{ name: <entityName> }` (SDK 1.7.1+). The older `insertRecordById` / `updateRecordById` / `updateRecordsById` / `insertRecordsById` / `queryRecordsById` / `importRecordsById` / `deleteRecordsById` methods still work but are deprecated — prefer `insertRecord` / `updateRecord` / `updateRecords` / `insertRecords` / `queryRecords` / `importRecords` / `deleteRecords` with a ref. Reads stay by-id: `getById`, `getAllRecords`, `getRecordById` (their by-name twins are `getByName` / `getRecordsByName` / `getRecordByName`).
6
+
5
7
  > **Scope pairing warning:** schema introspection (`entities.getAll()` / `getById()`) and record I/O sit in different scope pairs — `DataFabric.Schema.Read` vs `DataFabric.Data.Read` / `DataFabric.Data.Write`. This file mandates schema introspection before writes and filters, so an app with only Data scopes 403s on the introspection step. Check the shipped table per method.
6
8
 
7
9
  > **Building a CRUD grid over one entity?** Embed the DataTable widget instead of hand-wiring ag-Grid + record I/O — [../widgets/datatable.md](../widgets/datatable.md). The traps below still apply to any direct SDK calls the host app makes around it.
@@ -10,22 +12,22 @@ Signatures/params/examples: `dist/entities/index.d.ts` (trigger-event behavior d
10
12
 
11
13
  Data Fabric does NOT behave like a typical RDBMS. These server behaviors are invisible to both the types and the JSDoc. Before writing analytics, filters, or update logic, call `entities.getById(id)` and inspect `fields[].name` + `fieldDataType.name`. Pick your data strategy from what's actually there — do NOT assume.
12
14
 
13
- 1. **Choice values come back as `numberId` integers on every read path.** Including ungrouped `getRecordById` / `queryRecordsById` items AND `groupBy` result keys. The SDK does NOT convert to string names. Code like `record.Priority.toLowerCase()` throws or produces `"5"`; `if (record.Status === "Resolved")` is always false because `record.Status` is `5`. Build `numberId → name` maps via `choiceSets.getById(<choiceSetId>)` (get `<choiceSetId>` from `entities.getById(id).fields[].choiceSetId`) and translate every read.
15
+ 1. **Choice values come back as `numberId` integers on every read path.** Including ungrouped `getRecordById` / `queryRecords` items AND `groupBy` result keys. The SDK does NOT convert to string names. Code like `record.Priority.toLowerCase()` throws or produces `"5"`; `if (record.Status === "Resolved")` is always false because `record.Status` is `5`. Build `numberId → name` maps via `choiceSets.getById(<choiceSetId>)` (get `<choiceSetId>` from `entities.getById(id).fields[].choiceSetId`) and translate every read.
14
16
  2. **Choice-set writes and filters take the integer `numberId`, not the value name.** Writes: sending `status: "Open"` fails with `Single choiceset value Open is not integer`. Filters: `{ fieldName: 'Status', operator: Equals, value: 'Resolved' }` matches nothing — use `value: String(numberIdForResolved)` (applies to **every** operator touching a choice field, including `NotEquals`, `In`, `NotIn`). Failure is silent: 0 rows or all rows depending on operator.
15
17
  3. **Record keys must match the schema's exact casing.** The SDK does NOT pascalize keys. If the entity field is `Subject` (PascalCase, the DF UI default), sending `{ subject: … }` fails with `Required field "Subject" is not provided` — DF's required-field check is case-sensitive. Use `field.name` verbatim as the record key.
16
- 4. **Unknown keys on insert/update are silently dropped.** A typo'd field name in `insertRecordsById` does NOT error — the value is discarded without warning. Introspect the schema and validate keys before bulk operations.
18
+ 4. **Unknown keys on insert/update are silently dropped.** A typo'd field name in `insertRecords` does NOT error — the value is discarded without warning. Introspect the schema and validate keys before bulk operations.
17
19
  5. **DF auto-creates audit fields that look like domain fields but aren't.** Every entity has `CreateTime`, `UpdateTime`, `CreatedBy`, `UpdatedBy`, `Id`, `RecordOwner` — **row metadata** (when DF wrote the row), not the business event the row represents. They appear in the schema but are not writable. Need a domain-level "created at" / "owner"? Look for a custom field with a domain-specific name; if none exists, flag it to the user rather than silently using the audit column. Seeding historical timestamps: add a custom `DATETIME_WITH_TZ` field (e.g., `OriginalCreatedTime`) — do NOT name it `CreateTime` / `CreatedTime`, the audit name conflict causes silent drops or schema rejection.
18
20
  6. **No `IsNull` filter operator.** The server can't ask "where field is null" (`QueryFilterOperator` has no such member). Filter client-side after fetching, or design with explicit non-null sentinels.
19
- 7. **Aggregates require server-side `aggregates` + `groupBy`.** Don't fetch raw rows and `.length` / `.reduce` client-side — every list call returns one page (see [pagination.md](pagination.md)), so `result.items.length` after `queryRecordsById({ filter })` returns at most one page's worth, no matter how many rows match. Use `totalCount` for cardinality, `aggregates: [{ function: 'COUNT', field: 'Id' }]` (with `groupBy` for per-bucket counts) for chart data.
20
- 8. **File-type fields (`fieldDisplayType === 'File'`) aren't strings.** The record carries only metadata (`{ id, name, size, contentType }`); stringifying gives `"[object Object]"`. To display, call `entities.downloadAttachment(entityId, recordId, fieldName)` → `Blob` → `URL.createObjectURL` for an `<img src>`. **Neither `contentType` nor filename extension is reliable for detecting kind** — DF often returns `application/octet-stream`, and the stored `name` is frequently a bare UUID with no extension. To decide inline render vs download link, either (a) sniff the blob's magic bytes after download (PNG starts `89 50 4E 47`, JPEG `FF D8 FF`, GIF `47 49 46 38`, PDF `25 50 44 46`), or (b) optimistically attempt `<img src={objectUrl}>` and swap to a download link in `onError`. Writes go through `uploadAttachment(...)`, not `insertRecordById` / `updateRecordById`.
21
- 9. **`MULTILINE_MAX` fields return a size marker on list/query reads.** `getAllRecords` / `queryRecordsById` return a string starting `HasValue=true Length=N` (live form: `"HasValue=true Length=20000 — call Get Entity Record By Id activity to retrieve content"`), never the content — only `getRecordById` returns the full value (SDK 1.5.2+, v2 read endpoint). Never render or persist the marker as data, and never echo it back through `updateRecordById` / `updateRecordsById` — the server accepts it as a normal value and silently destroys the real content; omit the key instead. The type accepts no filters or `sortOptions` (server 400: *"Field '<name>' is of type MULTILINE_MAX and cannot be used in filters."*). `lengthLimit` is a UTF-16 **byte** budget (max 131072 ≈ 65,536 chars).
21
+ 7. **Aggregates require server-side `aggregates` + `groupBy`.** Don't fetch raw rows and `.length` / `.reduce` client-side — every list call returns one page (see [pagination.md](pagination.md)), so `result.items.length` after `queryRecords(entityRef, { filterGroup })` returns at most one page's worth, no matter how many rows match. Use `totalCount` for cardinality, `aggregates: [{ function: 'COUNT', field: 'Id' }]` (with `groupBy` for per-bucket counts) for chart data.
22
+ 8. **File-type fields (`fieldDisplayType === 'File'`) aren't strings.** The record carries only metadata (`{ id, name, size, contentType }`); stringifying gives `"[object Object]"`. To display, call `entities.downloadAttachment({ id: entityId }, recordId, fieldName)` → `Blob` → `URL.createObjectURL` for an `<img src>`. **Neither `contentType` nor filename extension is reliable for detecting kind** — DF often returns `application/octet-stream`, and the stored `name` is frequently a bare UUID with no extension. To decide inline render vs download link, either (a) sniff the blob's magic bytes after download (PNG starts `89 50 4E 47`, JPEG `FF D8 FF`, GIF `47 49 46 38`, PDF `25 50 44 46`), or (b) optimistically attempt `<img src={objectUrl}>` and swap to a download link in `onError`. Writes go through `uploadAttachment({ id: entityId }, ...)`, not `insertRecord` / `updateRecord`.
23
+ 9. **`MULTILINE_MAX` fields return only a preview on list/query reads.** `getAllRecords` / `queryRecords` return either the value truncated to 10,000 characters with a `...[Truncated]` suffix or a size marker starting `HasValue=true Length=N` (sometimes with a trailing hint), depending on the tenant; encrypted fields always return `HasValue=true Encrypted=true`. Only `getRecordById` returns the guaranteed full value (SDK 1.5.2+, v2 read endpoint). Never render or persist a preview as data, and never echo it back through `updateRecord` / `updateRecords` — the server accepts it as a normal value and silently destroys the real content; omit the key instead. The type accepts no filters or `sortOptions` (server 400: *"Field '<name>' is of type MULTILINE_MAX and cannot be used in filters."*). `lengthLimit` is a UTF-16 **byte** budget (max 131072 ≈ 65,536 chars).
22
24
 
23
25
  ## Three paths require choice-value translation — don't miss any
24
26
 
25
27
  | Path | Direction | What to do |
26
28
  |---|---|---|
27
- | Writes (`insertRecordsById`, `updateRecordById`, `updateRecordsById`) | name → `numberId` | translate before sending |
28
- | Filter values (any `queryRecordsById` filter on a choice field) | name → `numberId` (as a string) | translate before sending |
29
+ | Writes (`insertRecords`, `updateRecord`, `updateRecords`) | name → `numberId` | translate before sending |
30
+ | Filter values (any `queryRecords` filter on a choice field) | name → `numberId` (as a string) | translate before sending |
29
31
  | Read results (`groupBy` keys AND ungrouped record items) | `numberId` → name | translate after receiving |
30
32
 
31
33
  Best practice: on app load, fetch each choice set once (`choiceSets.getById` returns values carrying `name` + `numberId`) and build **both** maps (`byName` and `byNumberId`). Reuse across all paths.
@@ -111,7 +111,7 @@ Do not change field types, create federated entities, or write federated records
111
111
 
112
112
  20. **`records import` supports Basic types only.** `CHOICE_SET_*`, `RELATIONSHIP`, `FILE`, `AUTO_NUMBER` columns are ignored on import — optional columns land as `null`; **`isRequired` columns without a `defaultValue` fail the whole row** (`ErrorFileLink` entry per row). Sequence: (1) `entities get` → list unsupported columns; (2) tell the user which columns will be skipped, and which rows will fail because a required unsupported column has no default; (3) offer `records insert --file <json>` (+ `files upload` for FILE) as the alternative; (4) invoke only after explicit confirmation. See [`bulk-import.md` → Complex Field Types Not Supported](bulk-import.md#complex-field-types-not-supported).
113
113
 
114
- 21. **`MULTILINE_MAX` — marker reads, no filter/sort.** `records list` / `records query` return a size marker (`HasValue=true Length=N`) — full value only via `records get`. Never echo the marker back through `records update` — the server accepts it as a normal value and destroys the real content; omit the key instead. No filter/sort support (400). `lengthLimit` is a UTF-16 byte budget (max 131072 ≈ 65,536 chars). Full contract: [`entity-schema.md` → MULTILINE_MAX](entity-schema.md#multiline_max-fields) + [`records-query.md` → MULTILINE_MAX](records-query.md#multiline_max-fields--marker-vs-full-content).
114
+ 21. **`MULTILINE_MAX` — preview reads, no filter/sort.** `records list` / `records query` return a preview, either content truncated to 10,000 characters with a `...[Truncated]` suffix or a size marker (`HasValue=true Length=N`), depending on the tenant; full value only via `records get`. Never echo a preview back through `records update` — the server accepts it as a normal value and destroys the real content; omit the key instead. No filter/sort support (400). `lengthLimit` is a UTF-16 byte budget (max 131072 ≈ 65,536 chars). Full contract: [`entity-schema.md` → MULTILINE_MAX](entity-schema.md#multiline_max-fields) + [`records-query.md` → MULTILINE_MAX](records-query.md#multiline_max-fields--preview-vs-full-content).
115
115
 
116
116
  ---
117
117
 
@@ -32,7 +32,7 @@ Pass the exact `EntityFieldDataType` UPPERCASE string — CLI is case-sensitive.
32
32
  |---|---|---|
33
33
  | `STRING` | NVARCHAR | Short text (≤4000 chars via `lengthLimit`) |
34
34
  | `MULTILINE_TEXT` | NVARCHAR(MAX) | Long text (≤10000 chars via `lengthLimit`) |
35
- | `MULTILINE_MAX` | NVARCHAR(MAX) | Very large text (`lengthLimit` = UTF-16 byte budget, 1–131072; default 128 KB ≈ 65,536 chars max). No filter/sort; list/query reads return a size marker — see [MULTILINE_MAX fields](#multiline_max-fields) |
35
+ | `MULTILINE_MAX` | NVARCHAR(MAX) | Very large text (`lengthLimit` = UTF-16 byte budget, 1–131072; default 128 KB ≈ 65,536 chars max). No filter/sort; list/query reads return a preview, not the guaranteed full value — see [MULTILINE_MAX fields](#multiline_max-fields) |
36
36
  | `DECIMAL` | DECIMAL | All numbers — `decimalPrecision: 0` for whole; `2` for money |
37
37
  | `BOOLEAN` | BIT | true/false |
38
38
  | `DATE` | DATE | Date only |
@@ -80,7 +80,7 @@ If the CLI rejects a `--body` with *"Cannot read properties of undefined (readin
80
80
  Very large text. Contract differs from `MULTILINE_TEXT`:
81
81
 
82
82
  1. **Not filterable, not sortable.** Any `queryFilters` or `sortOptions` entry naming a `MULTILINE_MAX` field → 400: *"Field '<name>' is of type MULTILINE_MAX and cannot be used in filters."* / *"Sort field '<name>' is of type MULTILINE_MAX and cannot be used for sorting."* Never offer the field in filter/sort predicates. See [filter contract](filter-platform-contract.md#operator-support-by-field-type).
83
- 2. **List/query reads return a size marker, not content.** `records list` / `records query` return a string starting `HasValue=true Length=N` (live form: `"HasValue=true Length=20000 — call Get Entity Record By Id activity to retrieve content"`); only `records get <entity-id> <record-id>` returns the full value. Read + write-back rules in [records-query.md → MULTILINE_MAX fields](records-query.md#multiline_max-fields--marker-vs-full-content).
83
+ 2. **List/query reads return a preview, not the guaranteed full value.** Depending on the tenant, `records list` / `records query` return either the value truncated to 10,000 characters with a `...[Truncated]` suffix, or a size marker starting `HasValue=true Length=N` (sometimes with a trailing hint). Encrypted fields always read back `HasValue=true Encrypted=true`. Only `records get <entity-id> <record-id>` returns the full value. Read + write-back rules in [records-query.md → MULTILINE_MAX fields](records-query.md#multiline_max-fields--preview-vs-full-content).
84
84
  3. **On a 400 from `entities create` / `addFields` naming the type**, surface the error verbatim — do NOT retry or silently substitute `MULTILINE_TEXT` (Rule 18).
85
85
 
86
86
  ```bash
@@ -16,16 +16,21 @@ Response wrapper: `{ Result, Code: "RecordList" | "RecordQuery", Data: { Items,
16
16
  - **`Data.NextCursor` is an object `{ "Value": "<base64-string>" }`, not a flat string.** Pass `Data.NextCursor.Value` to `--cursor` on the next call (unwrap one level). Passing the whole `NextCursor` object errors out.
17
17
  - Use `Data.HasNextPage` to check if more records exist. Stop when it's `false`.
18
18
 
19
- ## MULTILINE_MAX Fields — Marker vs Full Content
19
+ ## MULTILINE_MAX Fields — Preview vs Full Content
20
20
 
21
- `records list` and `records query` do NOT return `MULTILINE_MAX` content. Each such field comes back as a size marker string starting `HasValue=true Length=N` — live form: `"HasValue=true Length=20000 — call Get Entity Record By Id activity to retrieve content"`. Only single-record read returns the full content:
21
+ `records list` and `records query` do NOT reliably return `MULTILINE_MAX` content. Each such field comes back as a **preview**, and which form you get depends on the tenant:
22
+
23
+ - the value truncated to 10,000 characters with a `...[Truncated]` suffix (a value at or under 10,000 characters can come back whole), or
24
+ - a size marker starting `HasValue=true Length=N`, sometimes with a trailing hint such as `"HasValue=true Length=20000 — call Get Entity Record By Id activity to retrieve content"`.
25
+
26
+ An encrypted `MULTILINE_MAX` field always reads back as `HasValue=true Encrypted=true` and never returns content. Do not branch on which form you got; treat any of them as a preview. Only the single-record read returns the full value:
22
27
 
23
28
  ```bash
24
29
  uip df records get <entity-id> <record-id> --output json
25
30
  ```
26
31
 
27
- 1. **Never treat the marker as the value.** Don't display, compare, or persist `"HasValue=true Length=N"` as field content — fetch via `records get` first.
28
- 2. **Never write the marker back.** A `records update` body built by echoing a record from `list` / `query` overwrites the real content with the literal marker string — verified: the server accepts it as a normal value, `Result: Success`, content silently destroyed. Omit `MULTILINE_MAX` keys from update bodies unless intentionally replacing the content.
32
+ 1. **Never treat a preview as the value.** Don't display, compare, or persist what `list` / `query` returned for the field; fetch via `records get` first. A truncated preview is the more dangerous form because it looks like ordinary content.
33
+ 2. **Never write a preview back.** A `records update` body built by echoing a record from `list` / `query` overwrites the real content with the preview — verified: the server accepts it as a normal value, `Result: Success`, content silently destroyed. With a truncated preview the stored value keeps its first 10,000 characters and loses the rest, which is far harder to notice than a marker string. Omit `MULTILINE_MAX` keys from update bodies unless intentionally replacing the content.
29
34
  3. **No filter, no sort.** `queryFilters` / `sortOptions` naming a `MULTILINE_MAX` field → 400: *"Field '<name>' is of type MULTILINE_MAX and cannot be used in filters."* / *"Sort field '<name>' is of type MULTILINE_MAX and cannot be used for sorting."* Surface verbatim (data-fabric.md Rule 18); don't retry with other operators. Full type contract: [entity-schema.md → MULTILINE_MAX fields](entity-schema.md#multiline_max-fields).
30
35
 
31
36
  ## Pagination
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "schemaVersion": 2,
3
- "skillsVersion": "1.202.1-preview.868",
3
+ "skillsVersion": "1.202.1-preview.894",
4
4
  "targetCli": "^1.202.0"
5
5
  }