zinkee 0.1.28 → 0.1.30
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/.claude/settings.local.json +13 -1
- package/AGENTS.md +13 -0
- package/dist/index.js +27 -32
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/api/records.ts +0 -1
- package/src/api/schemas.ts +2 -0
- package/src/commands/records.test.ts +79 -14
- package/src/commands/records.ts +5 -39
- package/src/commands/schemas.test.ts +80 -0
- package/src/commands/schemas.ts +16 -1
- package/src/utils/examples.ts +10 -0
package/package.json
CHANGED
package/src/api/records.ts
CHANGED
package/src/api/schemas.ts
CHANGED
|
@@ -17,6 +17,7 @@ export interface ApiSchema {
|
|
|
17
17
|
slug?: string;
|
|
18
18
|
auditable?: boolean;
|
|
19
19
|
commentable?: boolean;
|
|
20
|
+
highlightedField?: string;
|
|
20
21
|
fields?: ApiSchemaField[];
|
|
21
22
|
}
|
|
22
23
|
|
|
@@ -32,6 +33,7 @@ export interface UpdateSchemaInput {
|
|
|
32
33
|
slug?: string;
|
|
33
34
|
auditable?: boolean;
|
|
34
35
|
commentable?: boolean;
|
|
36
|
+
highlightedField?: string;
|
|
35
37
|
}
|
|
36
38
|
|
|
37
39
|
export interface CreateSchemaFieldInput {
|
|
@@ -412,7 +412,7 @@ describe("records commands", () => {
|
|
|
412
412
|
});
|
|
413
413
|
});
|
|
414
414
|
|
|
415
|
-
it("
|
|
415
|
+
it("wraps raw-file fields into the set payload", async () => {
|
|
416
416
|
const configPath = createApiConfig();
|
|
417
417
|
const output = createStdoutBuffer();
|
|
418
418
|
const fetchMock = createFetchMock();
|
|
@@ -423,15 +423,9 @@ describe("records commands", () => {
|
|
|
423
423
|
writeFileSync(
|
|
424
424
|
rawFile,
|
|
425
425
|
JSON.stringify({
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
imported: true,
|
|
430
|
-
},
|
|
431
|
-
},
|
|
432
|
-
unset: ["legacyCode"],
|
|
433
|
-
audit: {
|
|
434
|
-
reason: "sync",
|
|
426
|
+
status: "inactive",
|
|
427
|
+
metadata: {
|
|
428
|
+
imported: true,
|
|
435
429
|
},
|
|
436
430
|
}),
|
|
437
431
|
"utf8",
|
|
@@ -472,9 +466,6 @@ describe("records commands", () => {
|
|
|
472
466
|
);
|
|
473
467
|
expect(init?.method).toBe("PATCH");
|
|
474
468
|
expect(JSON.parse(String(init?.body))).toEqual({
|
|
475
|
-
audit: {
|
|
476
|
-
reason: "sync",
|
|
477
|
-
},
|
|
478
469
|
set: {
|
|
479
470
|
status: "active",
|
|
480
471
|
metadata: {
|
|
@@ -484,7 +475,81 @@ describe("records commands", () => {
|
|
|
484
475
|
tier: "gold",
|
|
485
476
|
},
|
|
486
477
|
},
|
|
487
|
-
unset: ["
|
|
478
|
+
unset: ["tempField"],
|
|
479
|
+
});
|
|
480
|
+
});
|
|
481
|
+
|
|
482
|
+
it("wraps bare raw fields into the set payload", async () => {
|
|
483
|
+
const configPath = createApiConfig();
|
|
484
|
+
const output = createStdoutBuffer();
|
|
485
|
+
const fetchMock = createFetchMock();
|
|
486
|
+
mockSchemaLookup(fetchMock);
|
|
487
|
+
fetchMock.mockResolvedValueOnce(
|
|
488
|
+
jsonResponse({
|
|
489
|
+
id: "550e8400-e29b-41d4-a716-446655440001",
|
|
490
|
+
uno: "prueba mod",
|
|
491
|
+
}),
|
|
492
|
+
);
|
|
493
|
+
const program = buildProgram({ configPath, stdout: output.stdout });
|
|
494
|
+
|
|
495
|
+
await program.parseAsync([
|
|
496
|
+
"node",
|
|
497
|
+
"zinkee",
|
|
498
|
+
"--json",
|
|
499
|
+
"records",
|
|
500
|
+
"update",
|
|
501
|
+
"contacts",
|
|
502
|
+
"550E8400-E29B-41D4-A716-446655440001",
|
|
503
|
+
"--raw",
|
|
504
|
+
'{"uno":"prueba mod"}',
|
|
505
|
+
]);
|
|
506
|
+
|
|
507
|
+
const init = fetchMock.mock.calls[1]?.[1];
|
|
508
|
+
|
|
509
|
+
expect(fetchMock.mock.calls[1]?.[0]).toBe(
|
|
510
|
+
"https://api.zinkee.test/api/v2/schemas/schema-1/records/550e8400-e29b-41d4-a716-446655440001",
|
|
511
|
+
);
|
|
512
|
+
expect(init?.method).toBe("PATCH");
|
|
513
|
+
expect(JSON.parse(String(init?.body))).toEqual({
|
|
514
|
+
set: {
|
|
515
|
+
uno: "prueba mod",
|
|
516
|
+
},
|
|
517
|
+
});
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
it("lets --set override raw fields with the same key", async () => {
|
|
521
|
+
const configPath = createApiConfig();
|
|
522
|
+
const output = createStdoutBuffer();
|
|
523
|
+
const fetchMock = createFetchMock();
|
|
524
|
+
mockSchemaLookup(fetchMock);
|
|
525
|
+
fetchMock.mockResolvedValueOnce(
|
|
526
|
+
jsonResponse({
|
|
527
|
+
id: "550e8400-e29b-41d4-a716-446655440001",
|
|
528
|
+
}),
|
|
529
|
+
);
|
|
530
|
+
const program = buildProgram({ configPath, stdout: output.stdout });
|
|
531
|
+
|
|
532
|
+
await program.parseAsync([
|
|
533
|
+
"node",
|
|
534
|
+
"zinkee",
|
|
535
|
+
"--json",
|
|
536
|
+
"records",
|
|
537
|
+
"update",
|
|
538
|
+
"contacts",
|
|
539
|
+
"550E8400-E29B-41D4-A716-446655440001",
|
|
540
|
+
"--raw",
|
|
541
|
+
'{"uno":"raw value"}',
|
|
542
|
+
"--set",
|
|
543
|
+
"uno=set value",
|
|
544
|
+
]);
|
|
545
|
+
|
|
546
|
+
const init = fetchMock.mock.calls[1]?.[1];
|
|
547
|
+
|
|
548
|
+
expect(init?.method).toBe("PATCH");
|
|
549
|
+
expect(JSON.parse(String(init?.body))).toEqual({
|
|
550
|
+
set: {
|
|
551
|
+
uno: "set value",
|
|
552
|
+
},
|
|
488
553
|
});
|
|
489
554
|
});
|
|
490
555
|
|
package/src/commands/records.ts
CHANGED
|
@@ -421,50 +421,16 @@ function buildRecordCreateInput(
|
|
|
421
421
|
return { values };
|
|
422
422
|
}
|
|
423
423
|
|
|
424
|
-
function readRawSetPayload(raw: JsonObject): Record<string, unknown> {
|
|
425
|
-
const setValue = raw.set;
|
|
426
|
-
|
|
427
|
-
if (setValue === undefined) {
|
|
428
|
-
return {};
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
if (!isJsonObject(setValue)) {
|
|
432
|
-
throw new CliError(
|
|
433
|
-
"invalid_cli_usage",
|
|
434
|
-
'Expected raw update payload field "set" to be a JSON object.',
|
|
435
|
-
);
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
return { ...setValue };
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
function readRawUnsetPayload(raw: JsonObject): string[] {
|
|
442
|
-
const unsetValue = raw.unset;
|
|
443
|
-
|
|
444
|
-
if (unsetValue === undefined) {
|
|
445
|
-
return [];
|
|
446
|
-
}
|
|
447
|
-
|
|
448
|
-
if (!Array.isArray(unsetValue) || !unsetValue.every((value) => typeof value === "string")) {
|
|
449
|
-
throw new CliError(
|
|
450
|
-
"invalid_cli_usage",
|
|
451
|
-
'Expected raw update payload field "unset" to be an array of strings.',
|
|
452
|
-
);
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
return [...unsetValue];
|
|
456
|
-
}
|
|
457
|
-
|
|
458
424
|
function buildRecordUpdateInput(
|
|
459
425
|
options: RecordsUpdateCommandOptions,
|
|
460
426
|
): UpdateRecordInput {
|
|
461
427
|
const raw = readRawObject(options.raw, options.rawFile);
|
|
462
|
-
const input: UpdateRecordInput = {
|
|
428
|
+
const input: UpdateRecordInput = {};
|
|
463
429
|
const setPayload = {
|
|
464
|
-
...
|
|
430
|
+
...raw,
|
|
465
431
|
...buildAssignmentObject(options.set, options.setJson),
|
|
466
432
|
};
|
|
467
|
-
const unsetPayload = [...
|
|
433
|
+
const unsetPayload = [...(options.unset ?? [])];
|
|
468
434
|
|
|
469
435
|
for (const key of Object.keys(setPayload)) {
|
|
470
436
|
const unsetIndex = unsetPayload.indexOf(key);
|
|
@@ -684,8 +650,8 @@ export function registerRecordsCommands(
|
|
|
684
650
|
.option("--set <field=value>", "set a string field", collectKeyValueAssignments, [])
|
|
685
651
|
.option("--set-json <field=json>", "set a structured field", collectJsonAssignments, [])
|
|
686
652
|
.option("--unset <field>", "unset a field", collectStringValues, [])
|
|
687
|
-
.option("--raw <json>", "raw JSON object
|
|
688
|
-
.option("--raw-file <path>", "path to a
|
|
653
|
+
.option("--raw <json>", "raw JSON object of fields to set")
|
|
654
|
+
.option("--raw-file <path>", "path to a JSON object of fields to set")
|
|
689
655
|
.action(async function action(
|
|
690
656
|
this: Command,
|
|
691
657
|
schema: NormalizedUuidOrSlug,
|
|
@@ -968,4 +968,84 @@ describe("schemas commands", () => {
|
|
|
968
968
|
},
|
|
969
969
|
});
|
|
970
970
|
});
|
|
971
|
+
|
|
972
|
+
it("updates a schema highlighted field by slug after resolving the field id", async () => {
|
|
973
|
+
const configPath = createApiConfig();
|
|
974
|
+
const output = createStdoutBuffer();
|
|
975
|
+
const fetchMock = createFetchMock();
|
|
976
|
+
mockSchemaLookup(fetchMock);
|
|
977
|
+
fetchMock.mockResolvedValueOnce(
|
|
978
|
+
jsonResponse({
|
|
979
|
+
id: "schema-1",
|
|
980
|
+
slug: "contacts",
|
|
981
|
+
fields: [
|
|
982
|
+
{
|
|
983
|
+
id: "550e8400-e29b-41d4-a716-446655440001",
|
|
984
|
+
slug: "email",
|
|
985
|
+
type: "TextField",
|
|
986
|
+
label: "Email",
|
|
987
|
+
},
|
|
988
|
+
],
|
|
989
|
+
}),
|
|
990
|
+
);
|
|
991
|
+
fetchMock.mockResolvedValueOnce(
|
|
992
|
+
jsonResponse({
|
|
993
|
+
id: "schema-1",
|
|
994
|
+
slug: "contacts",
|
|
995
|
+
highlightedField: "550e8400-e29b-41d4-a716-446655440001",
|
|
996
|
+
}),
|
|
997
|
+
);
|
|
998
|
+
const program = buildProgram({ configPath, stdout: output.stdout });
|
|
999
|
+
|
|
1000
|
+
await program.parseAsync([
|
|
1001
|
+
"node",
|
|
1002
|
+
"zinkee",
|
|
1003
|
+
"--json",
|
|
1004
|
+
"schemas",
|
|
1005
|
+
"update",
|
|
1006
|
+
"contacts",
|
|
1007
|
+
"--highlighted-field",
|
|
1008
|
+
"email",
|
|
1009
|
+
]);
|
|
1010
|
+
|
|
1011
|
+
expect(fetchMock.mock.calls[2]?.[0]).toBe("https://api.zinkee.test/api/v2/schemas/schema-1");
|
|
1012
|
+
expect(fetchMock.mock.calls[2]?.[1]?.method).toBe("PATCH");
|
|
1013
|
+
expect(JSON.parse(String(fetchMock.mock.calls[2]?.[1]?.body))).toEqual({
|
|
1014
|
+
highlightedField: "550e8400-e29b-41d4-a716-446655440001",
|
|
1015
|
+
});
|
|
1016
|
+
});
|
|
1017
|
+
|
|
1018
|
+
it("updates a schema highlighted field by uuid without extra lookups", async () => {
|
|
1019
|
+
const configPath = createApiConfig();
|
|
1020
|
+
const output = createStdoutBuffer();
|
|
1021
|
+
const fetchMock = createFetchMock();
|
|
1022
|
+
fetchMock.mockResolvedValueOnce(
|
|
1023
|
+
jsonResponse({
|
|
1024
|
+
id: "550e8400-e29b-41d4-a716-446655440000",
|
|
1025
|
+
slug: "contacts",
|
|
1026
|
+
highlightedField: "550e8400-e29b-41d4-a716-446655440001",
|
|
1027
|
+
}),
|
|
1028
|
+
);
|
|
1029
|
+
const program = buildProgram({ configPath, stdout: output.stdout });
|
|
1030
|
+
|
|
1031
|
+
await program.parseAsync([
|
|
1032
|
+
"node",
|
|
1033
|
+
"zinkee",
|
|
1034
|
+
"--json",
|
|
1035
|
+
"schemas",
|
|
1036
|
+
"update",
|
|
1037
|
+
"550e8400-e29b-41d4-a716-446655440000",
|
|
1038
|
+
"--highlighted-field",
|
|
1039
|
+
"550e8400-e29b-41d4-a716-446655440001",
|
|
1040
|
+
]);
|
|
1041
|
+
|
|
1042
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
1043
|
+
expect(fetchMock.mock.calls[0]?.[0]).toBe(
|
|
1044
|
+
"https://api.zinkee.test/api/v2/schemas/550e8400-e29b-41d4-a716-446655440000",
|
|
1045
|
+
);
|
|
1046
|
+
expect(fetchMock.mock.calls[0]?.[1]?.method).toBe("PATCH");
|
|
1047
|
+
expect(JSON.parse(String(fetchMock.mock.calls[0]?.[1]?.body))).toEqual({
|
|
1048
|
+
highlightedField: "550e8400-e29b-41d4-a716-446655440001",
|
|
1049
|
+
});
|
|
1050
|
+
});
|
|
971
1051
|
});
|
package/src/commands/schemas.ts
CHANGED
|
@@ -56,6 +56,7 @@ interface SchemaUpdateCommandOptions {
|
|
|
56
56
|
slug?: string;
|
|
57
57
|
auditable?: boolean;
|
|
58
58
|
commentable?: boolean;
|
|
59
|
+
highlightedField?: NormalizedUuidOrSlug;
|
|
59
60
|
}
|
|
60
61
|
|
|
61
62
|
interface FieldCreateCommandOptions {
|
|
@@ -568,6 +569,11 @@ export function registerSchemasCommands(
|
|
|
568
569
|
.option("--slug <slug>", "schema slug")
|
|
569
570
|
.option("--auditable <bool>", "auditable flag", parseBooleanFlag)
|
|
570
571
|
.option("--commentable <bool>", "commentable flag", parseBooleanFlag)
|
|
572
|
+
.option(
|
|
573
|
+
"--highlighted-field <field>",
|
|
574
|
+
"highlighted (main) field uuid or slug",
|
|
575
|
+
parseUuidOrSlugSelector,
|
|
576
|
+
)
|
|
571
577
|
.action(async function action(
|
|
572
578
|
this: Command,
|
|
573
579
|
schema: NormalizedUuidOrSlug,
|
|
@@ -579,10 +585,19 @@ export function registerSchemasCommands(
|
|
|
579
585
|
|
|
580
586
|
const input = buildSchemaUpdateInput(commandOptions);
|
|
581
587
|
|
|
588
|
+
if (commandOptions.highlightedField !== undefined) {
|
|
589
|
+
const resolvedField = await resolveFieldSelector(
|
|
590
|
+
api,
|
|
591
|
+
resolvedSchema,
|
|
592
|
+
commandOptions.highlightedField,
|
|
593
|
+
);
|
|
594
|
+
input.highlightedField = resolvedField.value;
|
|
595
|
+
}
|
|
596
|
+
|
|
582
597
|
if (isEmptyObject(input)) {
|
|
583
598
|
throw new CliError(
|
|
584
599
|
"invalid_cli_usage",
|
|
585
|
-
'Provide at least one schema field to update via "--name", "--slug", "--auditable", or "--
|
|
600
|
+
'Provide at least one schema field to update via "--name", "--slug", "--auditable", "--commentable", or "--highlighted-field".',
|
|
586
601
|
);
|
|
587
602
|
}
|
|
588
603
|
|
package/src/utils/examples.ts
CHANGED
|
@@ -228,6 +228,7 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
|
|
|
228
228
|
},
|
|
229
229
|
"auditable": true,
|
|
230
230
|
"commentable": true,
|
|
231
|
+
"highlightedField": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
231
232
|
"fields": [
|
|
232
233
|
{
|
|
233
234
|
"id": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
@@ -259,6 +260,14 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
|
|
|
259
260
|
command: 'zinkee --json schemas update contacts --auditable true',
|
|
260
261
|
raw: `{
|
|
261
262
|
"auditable": true
|
|
263
|
+
}`,
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
description: "Set the highlighted (main) field of a schema.",
|
|
267
|
+
command:
|
|
268
|
+
'zinkee --json schemas update contacts --highlighted-field contact-name',
|
|
269
|
+
raw: `{
|
|
270
|
+
"highlightedField": "c60b8526-5835-4c9f-aecd-9a16c7704a34"
|
|
262
271
|
}`,
|
|
263
272
|
},
|
|
264
273
|
]),
|
|
@@ -1904,6 +1913,7 @@ const specificExamples: Record<string, readonly CommandExample[]> = {
|
|
|
1904
1913
|
},
|
|
1905
1914
|
"auditable": true,
|
|
1906
1915
|
"commentable": true,
|
|
1916
|
+
"highlightedField": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
|
|
1907
1917
|
"fields": [
|
|
1908
1918
|
{
|
|
1909
1919
|
"id": "c60b8526-5835-4c9f-aecd-9a16c7704a34",
|