@uipath/data-fabric-tool 1.0.1 → 1.1.0
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/browser.json +3 -0
- package/dist/index.js +21 -43170
- package/dist/tool.js +24432 -24133
- package/package.json +5 -13
- package/src/commands/choice-sets.spec.ts +394 -0
- package/src/commands/choice-sets.ts +286 -0
- package/src/commands/entities.spec.ts +361 -0
- package/src/commands/entities.ts +33 -5
- package/src/commands/files.ts +10 -3
- package/src/commands/records.spec.ts +69 -0
- package/src/commands/records.ts +42 -18
- package/src/index.ts +5 -10
- package/src/tool.ts +2 -0
- package/src/utils/pagination.ts +10 -0
package/src/commands/entities.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type CommandExample,
|
|
3
3
|
catchError,
|
|
4
|
+
createHiddenDeprecatedTenantOption,
|
|
4
5
|
extractErrorMessage,
|
|
5
6
|
OutputFormatter,
|
|
6
7
|
processContext,
|
|
@@ -130,6 +131,22 @@ const ENTITIES_DELETE_EXAMPLES: CommandExample[] = [
|
|
|
130
131
|
},
|
|
131
132
|
];
|
|
132
133
|
|
|
134
|
+
const ENTITIES_CREATE_EXAMPLES: CommandExample[] = [
|
|
135
|
+
{
|
|
136
|
+
Description:
|
|
137
|
+
"Create an entity with a choice-set field (single-select and multi-select) and a relationship to another entity. " +
|
|
138
|
+
"CHOICE_SET_SINGLE/CHOICE_SET_MULTIPLE require 'choiceSetId' (from 'df choice-sets list'). " +
|
|
139
|
+
"RELATIONSHIP requires 'referenceEntityName' (target entity) and 'referenceFieldName' (the field used to resolve joins on read; e.g. 'Id' or a unique key like 'Email'). " +
|
|
140
|
+
"Note: regardless of 'referenceFieldName', a relationship column on a record always stores the target record's UUID 'Id' — see 'df records insert' for how to write the value.",
|
|
141
|
+
Command:
|
|
142
|
+
'uip df entities create Expense --body \'{"displayName":"Expense","fields":[{"fieldName":"category","type":"CHOICE_SET_SINGLE","choiceSetId":"c1d2e3f4-0000-0000-0000-000000000001","isRequired":true},{"fieldName":"tags","type":"CHOICE_SET_MULTIPLE","choiceSetId":"c1d2e3f4-0000-0000-0000-000000000002"},{"fieldName":"submitter","type":"RELATIONSHIP","referenceEntityName":"Employee","referenceFieldName":"Id","isRequired":true}]}\'',
|
|
143
|
+
Output: {
|
|
144
|
+
Code: "EntityCreated",
|
|
145
|
+
Data: { ID: "a1b2c3d4-0000-0000-0000-000000000004" },
|
|
146
|
+
},
|
|
147
|
+
},
|
|
148
|
+
];
|
|
149
|
+
|
|
133
150
|
const VALID_FIELD_TYPES = new Set(Object.values(EntityFieldDataType));
|
|
134
151
|
const VALID_FIELD_TYPES_LIST = [...VALID_FIELD_TYPES].join(", ");
|
|
135
152
|
|
|
@@ -170,7 +187,9 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
170
187
|
entities
|
|
171
188
|
.command("list")
|
|
172
189
|
.description("List all Data Fabric entities")
|
|
173
|
-
.
|
|
190
|
+
.addOption(
|
|
191
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
192
|
+
)
|
|
174
193
|
.option(
|
|
175
194
|
"--native-only",
|
|
176
195
|
"Show only native entities (exclude federated entities with external connections)",
|
|
@@ -237,7 +256,9 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
237
256
|
.command("get")
|
|
238
257
|
.description("Get schema details of a Data Fabric entity")
|
|
239
258
|
.argument("<id>", "Entity ID")
|
|
240
|
-
.
|
|
259
|
+
.addOption(
|
|
260
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
261
|
+
)
|
|
241
262
|
.examples(ENTITIES_GET_EXAMPLES)
|
|
242
263
|
.trackedAction(
|
|
243
264
|
processContext,
|
|
@@ -315,12 +336,15 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
315
336
|
"<name>",
|
|
316
337
|
"Entity name (must start with a letter; letters, numbers, and underscores only)",
|
|
317
338
|
)
|
|
318
|
-
.
|
|
339
|
+
.addOption(
|
|
340
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
341
|
+
)
|
|
319
342
|
.option(
|
|
320
343
|
"-f, --file <path>",
|
|
321
344
|
"Path to JSON file with entity definition (fields array required; displayName, description, isRbacEnabled optional)",
|
|
322
345
|
)
|
|
323
346
|
.option("--body <json>", "Inline JSON entity definition")
|
|
347
|
+
.examples(ENTITIES_CREATE_EXAMPLES)
|
|
324
348
|
.trackedAction(
|
|
325
349
|
processContext,
|
|
326
350
|
async (name: string, options: CreateOptions) => {
|
|
@@ -457,7 +481,9 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
457
481
|
.command("update")
|
|
458
482
|
.description("Update schema or metadata of a Data Fabric entity")
|
|
459
483
|
.argument("<id>", "Entity ID")
|
|
460
|
-
.
|
|
484
|
+
.addOption(
|
|
485
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
486
|
+
)
|
|
461
487
|
.option(
|
|
462
488
|
"-f, --file <path>",
|
|
463
489
|
"Path to JSON file with update options (addFields, updateFields, removeFields, displayName, description, isRbacEnabled)",
|
|
@@ -739,7 +765,9 @@ export const registerEntitiesCommand = (program: Command) => {
|
|
|
739
765
|
.command("delete")
|
|
740
766
|
.description("Delete a Data Fabric entity (irreversible)")
|
|
741
767
|
.argument("<id>", "Entity ID")
|
|
742
|
-
.
|
|
768
|
+
.addOption(
|
|
769
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
770
|
+
)
|
|
743
771
|
.option("--confirm", "Acknowledge this is an irreversible operation")
|
|
744
772
|
.option(
|
|
745
773
|
"--reason <reason>",
|
package/src/commands/files.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type CommandExample,
|
|
3
3
|
catchError,
|
|
4
|
+
createHiddenDeprecatedTenantOption,
|
|
4
5
|
extractErrorMessage,
|
|
5
6
|
OutputFormatter,
|
|
6
7
|
processContext,
|
|
@@ -86,7 +87,9 @@ export const registerFilesCommand = (program: Command) => {
|
|
|
86
87
|
.argument("<entity-id>", "Entity ID")
|
|
87
88
|
.argument("<record-id>", "Record ID")
|
|
88
89
|
.argument("<field-name>", "Name of the file field (case-sensitive)")
|
|
89
|
-
.
|
|
90
|
+
.addOption(
|
|
91
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
92
|
+
)
|
|
90
93
|
.option("-f, --file <path>", "Path to the file to upload")
|
|
91
94
|
.examples(FILES_UPLOAD_EXAMPLES)
|
|
92
95
|
.trackedAction(
|
|
@@ -179,7 +182,9 @@ export const registerFilesCommand = (program: Command) => {
|
|
|
179
182
|
.argument("<entity-id>", "Entity ID")
|
|
180
183
|
.argument("<record-id>", "Record ID")
|
|
181
184
|
.argument("<field-name>", "Name of the file field (case-sensitive)")
|
|
182
|
-
.
|
|
185
|
+
.addOption(
|
|
186
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
187
|
+
)
|
|
183
188
|
.option(
|
|
184
189
|
"--destination <path>",
|
|
185
190
|
"Output file path (defaults to <record-id>_<field-name>.bin)",
|
|
@@ -275,7 +280,9 @@ export const registerFilesCommand = (program: Command) => {
|
|
|
275
280
|
.argument("<entity-id>", "Entity ID")
|
|
276
281
|
.argument("<record-id>", "Record ID")
|
|
277
282
|
.argument("<field-name>", "Name of the file field (case-sensitive)")
|
|
278
|
-
.
|
|
283
|
+
.addOption(
|
|
284
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
285
|
+
)
|
|
279
286
|
.examples(FILES_DELETE_EXAMPLES)
|
|
280
287
|
.trackedAction(
|
|
281
288
|
processContext,
|
|
@@ -701,6 +701,75 @@ describe("records insert", () => {
|
|
|
701
701
|
expect(process.exitCode).toBe(1);
|
|
702
702
|
});
|
|
703
703
|
|
|
704
|
+
it("should pass choice-set NumberId integers and a relationship UUID through to the SDK on single insert", async () => {
|
|
705
|
+
const sdk = mockSdk();
|
|
706
|
+
vi.mocked(sdk.entities.insertRecordById).mockResolvedValue({
|
|
707
|
+
Id: "new-rec",
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
const program = buildProgram();
|
|
711
|
+
await program.parseAsync([
|
|
712
|
+
"node",
|
|
713
|
+
"test",
|
|
714
|
+
"records",
|
|
715
|
+
"insert",
|
|
716
|
+
"entity-id",
|
|
717
|
+
"--body",
|
|
718
|
+
'{"title":"Flight to NYC","amount":420.5,"opType":0,"multiOpType":[0,1],"assignee":"AEDE69C3-EFD1-4897-B216-019E1A7E9269","rel1":"B065E2A8-F33B-4721-8228-019DE0C593AF"}',
|
|
719
|
+
]);
|
|
720
|
+
|
|
721
|
+
expect(sdk.entities.insertRecordById).toHaveBeenCalledWith(
|
|
722
|
+
"entity-id",
|
|
723
|
+
expect.objectContaining({
|
|
724
|
+
opType: 0,
|
|
725
|
+
multiOpType: [0, 1],
|
|
726
|
+
assignee: "AEDE69C3-EFD1-4897-B216-019E1A7E9269",
|
|
727
|
+
rel1: "B065E2A8-F33B-4721-8228-019DE0C593AF",
|
|
728
|
+
}),
|
|
729
|
+
);
|
|
730
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
731
|
+
expect.objectContaining({ Code: "RecordInserted" }),
|
|
732
|
+
);
|
|
733
|
+
});
|
|
734
|
+
|
|
735
|
+
it("should pass choice-set and relationship values through unchanged on batch insert", async () => {
|
|
736
|
+
const sdk = mockSdk();
|
|
737
|
+
vi.mocked(sdk.entities.insertRecordsById).mockResolvedValue({
|
|
738
|
+
successRecords: [{ Id: "rec-a" }, { Id: "rec-b" }],
|
|
739
|
+
failureRecords: [],
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
const program = buildProgram();
|
|
743
|
+
await program.parseAsync([
|
|
744
|
+
"node",
|
|
745
|
+
"test",
|
|
746
|
+
"records",
|
|
747
|
+
"insert",
|
|
748
|
+
"entity-id",
|
|
749
|
+
"--body",
|
|
750
|
+
'[{"opType":0,"multiOpType":[0],"assignee":"AEDE69C3-EFD1-4897-B216-019E1A7E9269"},{"opType":1,"multiOpType":[0,1],"assignee":"2481A9F6-E0F7-4996-8446-019E1A7E926A"}]',
|
|
751
|
+
]);
|
|
752
|
+
|
|
753
|
+
expect(sdk.entities.insertRecordsById).toHaveBeenCalledWith(
|
|
754
|
+
"entity-id",
|
|
755
|
+
expect.arrayContaining([
|
|
756
|
+
expect.objectContaining({
|
|
757
|
+
opType: 0,
|
|
758
|
+
multiOpType: [0],
|
|
759
|
+
assignee: "AEDE69C3-EFD1-4897-B216-019E1A7E9269",
|
|
760
|
+
}),
|
|
761
|
+
expect.objectContaining({
|
|
762
|
+
opType: 1,
|
|
763
|
+
multiOpType: [0, 1],
|
|
764
|
+
assignee: "2481A9F6-E0F7-4996-8446-019E1A7E926A",
|
|
765
|
+
}),
|
|
766
|
+
]),
|
|
767
|
+
);
|
|
768
|
+
expect(OutputFormatter.success).toHaveBeenCalledWith(
|
|
769
|
+
expect.objectContaining({ Code: "RecordsBatchInserted" }),
|
|
770
|
+
);
|
|
771
|
+
});
|
|
772
|
+
|
|
704
773
|
it("should error on partial batch insert failure (FailureCount > 0)", async () => {
|
|
705
774
|
const sdk = mockSdk();
|
|
706
775
|
vi.mocked(sdk.entities.insertRecordsById).mockResolvedValue({
|
package/src/commands/records.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
type CommandExample,
|
|
3
3
|
catchError,
|
|
4
|
+
createHiddenDeprecatedTenantOption,
|
|
4
5
|
extractErrorMessage,
|
|
5
6
|
OutputFormatter,
|
|
6
7
|
processContext,
|
|
@@ -10,6 +11,7 @@ import { getFileSystem } from "@uipath/filesystem";
|
|
|
10
11
|
import type { EntityRecord } from "@uipath/uipath-typescript";
|
|
11
12
|
import type { Command } from "commander";
|
|
12
13
|
import { readFileBinary, readJsonInput } from "../utils/input";
|
|
14
|
+
import { extractCursorValue } from "../utils/pagination";
|
|
13
15
|
import { createDataFabricClient } from "../utils/sdk-client";
|
|
14
16
|
|
|
15
17
|
interface ListOptions {
|
|
@@ -113,6 +115,25 @@ const RECORDS_INSERT_EXAMPLES: CommandExample[] = [
|
|
|
113
115
|
},
|
|
114
116
|
},
|
|
115
117
|
},
|
|
118
|
+
{
|
|
119
|
+
Description:
|
|
120
|
+
"Insert a record into an entity that has choice-set and relationship fields. " +
|
|
121
|
+
"CHOICE_SET_SINGLE → pass the choice value's 'NumberId' (integer, NOT the Name string — look it up via 'df choice-sets get <id>'). " +
|
|
122
|
+
"CHOICE_SET_MULTIPLE → pass an array of NumberId integers. " +
|
|
123
|
+
"RELATIONSHIP → always pass the target record's Id (UUID), even if the field was declared with a 'referenceFieldName' other than 'Id' (the referenceFieldName configures the join, not the stored value).",
|
|
124
|
+
Command:
|
|
125
|
+
'uip df records insert a1b2c3d4-0000-0000-0000-000000000004 --body \'{"category":0,"tags":[1,3],"submitter":"e1f2a3b4-0000-0000-0000-000000000001","amount":250}\'',
|
|
126
|
+
Output: {
|
|
127
|
+
Code: "RecordInserted",
|
|
128
|
+
Data: {
|
|
129
|
+
Id: "b2c3d4e5-0000-0000-0000-000000000020",
|
|
130
|
+
category: 0,
|
|
131
|
+
tags: [1, 3],
|
|
132
|
+
submitter: "e1f2a3b4-0000-0000-0000-000000000001",
|
|
133
|
+
amount: 250,
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
},
|
|
116
137
|
];
|
|
117
138
|
|
|
118
139
|
const RECORDS_UPDATE_EXAMPLES: CommandExample[] = [
|
|
@@ -158,7 +179,9 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
158
179
|
.command("list")
|
|
159
180
|
.description("List records in a Data Fabric entity")
|
|
160
181
|
.argument("<id>", "Entity ID")
|
|
161
|
-
.
|
|
182
|
+
.addOption(
|
|
183
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
184
|
+
)
|
|
162
185
|
.option(
|
|
163
186
|
"-l, --limit <number>",
|
|
164
187
|
"Number of records to return per page",
|
|
@@ -287,7 +310,9 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
287
310
|
.description("Get a single record by ID")
|
|
288
311
|
.argument("<id>", "Entity ID")
|
|
289
312
|
.argument("<key>", "Record ID")
|
|
290
|
-
.
|
|
313
|
+
.addOption(
|
|
314
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
315
|
+
)
|
|
291
316
|
.examples(RECORDS_GET_EXAMPLES)
|
|
292
317
|
.trackedAction(
|
|
293
318
|
processContext,
|
|
@@ -343,7 +368,9 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
343
368
|
.command("insert")
|
|
344
369
|
.description("Insert records into a Data Fabric entity")
|
|
345
370
|
.argument("<id>", "Entity ID")
|
|
346
|
-
.
|
|
371
|
+
.addOption(
|
|
372
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
373
|
+
)
|
|
347
374
|
.option(
|
|
348
375
|
"-f, --file <path>",
|
|
349
376
|
"Path to JSON file with record data (object or array of objects)",
|
|
@@ -449,7 +476,9 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
449
476
|
.command("update")
|
|
450
477
|
.description("Update records in a Data Fabric entity")
|
|
451
478
|
.argument("<id>", "Entity ID")
|
|
452
|
-
.
|
|
479
|
+
.addOption(
|
|
480
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
481
|
+
)
|
|
453
482
|
.option(
|
|
454
483
|
"-f, --file <path>",
|
|
455
484
|
"Path to JSON file with record data (must include Id field)",
|
|
@@ -595,7 +624,9 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
595
624
|
"aggregates (function: COUNT/SUM/AVG/MIN/MAX, field, alias?), groupBy.",
|
|
596
625
|
)
|
|
597
626
|
.argument("<id>", "Entity ID")
|
|
598
|
-
.
|
|
627
|
+
.addOption(
|
|
628
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
629
|
+
)
|
|
599
630
|
.option(
|
|
600
631
|
"-f, --file <path>",
|
|
601
632
|
"Path to JSON file with query options (filterGroup, selectedFields, sortOptions, aggregates, groupBy)",
|
|
@@ -766,7 +797,9 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
766
797
|
.command("import")
|
|
767
798
|
.description("Import records from a CSV file into a Data Fabric entity")
|
|
768
799
|
.argument("<id>", "Entity ID")
|
|
769
|
-
.
|
|
800
|
+
.addOption(
|
|
801
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
802
|
+
)
|
|
770
803
|
.option("-f, --file <path>", "Path to the CSV file to import")
|
|
771
804
|
.trackedAction(
|
|
772
805
|
processContext,
|
|
@@ -855,7 +888,9 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
855
888
|
.description("Delete records from a Data Fabric entity")
|
|
856
889
|
.argument("<id>", "Entity ID")
|
|
857
890
|
.argument("<key...>", "Record IDs to delete")
|
|
858
|
-
.
|
|
891
|
+
.addOption(
|
|
892
|
+
createHiddenDeprecatedTenantOption("-t, --tenant <tenant-name>"),
|
|
893
|
+
)
|
|
859
894
|
.examples(RECORDS_DELETE_EXAMPLES)
|
|
860
895
|
.trackedAction(
|
|
861
896
|
processContext,
|
|
@@ -911,17 +946,6 @@ export const registerRecordsCommand = (program: Command) => {
|
|
|
911
946
|
);
|
|
912
947
|
};
|
|
913
948
|
|
|
914
|
-
/** Normalises the SDK cursor to a plain string for CLI output.
|
|
915
|
-
* The SDK returns `PaginationCursor = { value: string }` but we want
|
|
916
|
-
* to expose just the string so the user can pass it directly to --cursor. */
|
|
917
|
-
function extractCursorValue(cursor: unknown): string | undefined {
|
|
918
|
-
if (cursor === undefined || cursor === null) return undefined;
|
|
919
|
-
if (typeof cursor === "string") return cursor;
|
|
920
|
-
const c = cursor as Record<string, unknown>;
|
|
921
|
-
if (typeof c.value === "string") return c.value;
|
|
922
|
-
return undefined;
|
|
923
|
-
}
|
|
924
|
-
|
|
925
949
|
const isRecordObject = (value: unknown): value is Record<string, unknown> =>
|
|
926
950
|
typeof value === "object" && value !== null && !Array.isArray(value);
|
|
927
951
|
|
package/src/index.ts
CHANGED
|
@@ -1,17 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
import { Command } from "commander";
|
|
3
|
-
import
|
|
4
|
-
import { registerEntitiesCommand } from "./commands/entities";
|
|
5
|
-
import { registerFilesCommand } from "./commands/files";
|
|
6
|
-
import { registerRecordsCommand } from "./commands/records";
|
|
3
|
+
import { metadata, registerCommands } from "./tool.js";
|
|
7
4
|
|
|
8
5
|
const program = new Command();
|
|
9
6
|
program
|
|
10
|
-
.name(
|
|
11
|
-
.description(
|
|
12
|
-
.version(
|
|
7
|
+
.name(metadata.name)
|
|
8
|
+
.description(metadata.description)
|
|
9
|
+
.version(metadata.version);
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
registerRecordsCommand(program);
|
|
16
|
-
registerFilesCommand(program);
|
|
11
|
+
await registerCommands(program);
|
|
17
12
|
await program.parseAsync(process.argv);
|
package/src/tool.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
2
|
import pkg from "../package.json" with { type: "json" };
|
|
3
|
+
import { registerChoiceSetsCommand } from "./commands/choice-sets";
|
|
3
4
|
import { registerEntitiesCommand } from "./commands/entities";
|
|
4
5
|
import { registerFilesCommand } from "./commands/files";
|
|
5
6
|
import { registerRecordsCommand } from "./commands/records";
|
|
@@ -16,4 +17,5 @@ export const registerCommands = async (program: Command): Promise<void> => {
|
|
|
16
17
|
registerEntitiesCommand(program);
|
|
17
18
|
registerRecordsCommand(program);
|
|
18
19
|
registerFilesCommand(program);
|
|
20
|
+
registerChoiceSetsCommand(program);
|
|
19
21
|
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Normalises an SDK pagination cursor to a plain string for CLI output.
|
|
2
|
+
* The SDK returns `PaginationCursor = { value: string }` but we want
|
|
3
|
+
* to expose just the string so the user can pass it directly to --cursor. */
|
|
4
|
+
export function extractCursorValue(cursor: unknown): string | undefined {
|
|
5
|
+
if (cursor === undefined || cursor === null) return undefined;
|
|
6
|
+
if (typeof cursor === "string") return cursor;
|
|
7
|
+
const c = cursor as Record<string, unknown>;
|
|
8
|
+
if (typeof c.value === "string") return c.value;
|
|
9
|
+
return undefined;
|
|
10
|
+
}
|