zinkee 0.1.11 → 0.1.15
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/AGENTS.md +42 -0
- package/README.md +7 -0
- package/dist/index.js +268 -59
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/api/records.ts +7 -0
- package/src/cli-examples.ts +18 -36
- package/src/cli-runner.ts +10 -2
- package/src/command-registry.ts +7 -0
- package/src/commands/automations.test.ts +5 -5
- package/src/commands/displays.test.ts +2 -2
- package/src/commands/records.test.ts +58 -0
- package/src/commands/records.ts +19 -0
- package/src/index.test.ts +52 -0
- package/src/utils/argv-rewrite.test.ts +149 -0
- package/src/utils/argv-rewrite.ts +269 -0
- package/src/utils/examples.ts +32 -21
- package/src/utils/schema-fields.ts +11 -9
package/AGENTS.md
CHANGED
|
@@ -50,3 +50,45 @@ Use this order when reasoning about behavior:
|
|
|
50
50
|
## Testing
|
|
51
51
|
|
|
52
52
|
Prefer focused command tests and parser/client unit tests.
|
|
53
|
+
|
|
54
|
+
> **Unit tests use `fetchMock` and never hit the real API.** When changing the
|
|
55
|
+
> shape of a payload (enum values, property names, structure), unit tests will
|
|
56
|
+
> still pass even if the real API would reject the request with `400`. For
|
|
57
|
+
> shape-sensitive changes — especially edits to strings in `src/utils/examples.ts`
|
|
58
|
+
> — also run the resulting command against a real workspace and confirm the API
|
|
59
|
+
> accepts it.
|
|
60
|
+
|
|
61
|
+
## Contributing
|
|
62
|
+
|
|
63
|
+
### Branches
|
|
64
|
+
|
|
65
|
+
- `feature/eng-<ticket>-<slug>` for Linear-tracked work
|
|
66
|
+
- `fix/<slug>` / `chore/<slug>` / `docs/<slug>` for untracked work
|
|
67
|
+
- Never push to `main` directly; always open a PR
|
|
68
|
+
|
|
69
|
+
### Commits
|
|
70
|
+
|
|
71
|
+
- Conventional Commits format: `<type>(<scope>): <subject>` (e.g.
|
|
72
|
+
`fix(displays): correct chart-type values in widget examples`)
|
|
73
|
+
- Subject in imperative mood, under ~72 chars, no trailing period
|
|
74
|
+
- Body explains the *why*, not the *what* — the diff already shows what changed
|
|
75
|
+
- Stage files explicitly (`git add <path>`); never `git add -A`
|
|
76
|
+
- Don't add `Co-Authored-By:` trailers; existing history doesn't use them
|
|
77
|
+
|
|
78
|
+
### Before committing
|
|
79
|
+
|
|
80
|
+
1. `npm run typecheck` — must pass
|
|
81
|
+
2. `npm test` — must pass
|
|
82
|
+
3. For changes that affect runtime behaviour or `--example` output, also
|
|
83
|
+
exercise the affected commands against a live workspace (see Testing note
|
|
84
|
+
above).
|
|
85
|
+
|
|
86
|
+
### Versioning
|
|
87
|
+
|
|
88
|
+
- Versioning is patch-only today (`0.1.x`). Bump the patch number unless the
|
|
89
|
+
team decides to move to a different scheme.
|
|
90
|
+
- Every PR that ships user-visible changes (new commands, fixed examples,
|
|
91
|
+
behaviour changes) bumps `package.json` version in the same PR — not in a
|
|
92
|
+
separate "release" PR.
|
|
93
|
+
- Before bumping, fetch `origin/main` to make sure the version you pick isn't
|
|
94
|
+
already taken by another PR that merged ahead of yours.
|
package/README.md
CHANGED
|
@@ -273,10 +273,17 @@ zinkee records update projects <record-uuid> --set status=2
|
|
|
273
273
|
|
|
274
274
|
# Delete
|
|
275
275
|
zinkee records delete projects <record-uuid>
|
|
276
|
+
|
|
277
|
+
# Clear all records from a schema (destructive — irreversible)
|
|
278
|
+
zinkee records clear projects
|
|
276
279
|
```
|
|
277
280
|
|
|
278
281
|
Option values are written as numbers (`--set status=1`) but returned as strings (`"1"`). Number values are stored and returned as strings.
|
|
279
282
|
|
|
283
|
+
`records clear` removes every record from the schema's table. Heritage rules
|
|
284
|
+
(`CASCADE` / `SET NULL`) propagate to child schemas asynchronously through the
|
|
285
|
+
CDC pipeline, so related tables converge eventually. Blocked by `--read-only`.
|
|
286
|
+
|
|
280
287
|
---
|
|
281
288
|
|
|
282
289
|
## Files
|
package/dist/index.js
CHANGED
|
@@ -660,6 +660,13 @@ var commandRegistry = {
|
|
|
660
660
|
supportsRaw: false,
|
|
661
661
|
output: writeOutput
|
|
662
662
|
},
|
|
663
|
+
"records clear": {
|
|
664
|
+
command: "records clear",
|
|
665
|
+
accessLevel: "destructive",
|
|
666
|
+
supportsExample: true,
|
|
667
|
+
supportsRaw: false,
|
|
668
|
+
output: writeOutput
|
|
669
|
+
},
|
|
663
670
|
"comments list": {
|
|
664
671
|
command: "comments list",
|
|
665
672
|
accessLevel: "read",
|
|
@@ -732,6 +739,197 @@ var commandRegistry = {
|
|
|
732
739
|
}
|
|
733
740
|
};
|
|
734
741
|
|
|
742
|
+
// src/utils/argv-rewrite.ts
|
|
743
|
+
var HOISTABLE_GLOBAL_FLAGS = {
|
|
744
|
+
"--profile": "value",
|
|
745
|
+
"--base-url": "value",
|
|
746
|
+
"--api-key": "value",
|
|
747
|
+
"--read-only": "boolean",
|
|
748
|
+
"--json": "boolean"
|
|
749
|
+
};
|
|
750
|
+
function isHoistableFlag(flagName) {
|
|
751
|
+
return Object.hasOwn(HOISTABLE_GLOBAL_FLAGS, flagName);
|
|
752
|
+
}
|
|
753
|
+
function getCommandPath(command) {
|
|
754
|
+
const parts = [];
|
|
755
|
+
let cursor = command;
|
|
756
|
+
while (cursor && cursor.parent) {
|
|
757
|
+
parts.unshift(cursor.name());
|
|
758
|
+
cursor = cursor.parent;
|
|
759
|
+
}
|
|
760
|
+
return parts.join(" ");
|
|
761
|
+
}
|
|
762
|
+
function buildOptionMetadata(program) {
|
|
763
|
+
const valueFlags = /* @__PURE__ */ new Set();
|
|
764
|
+
const booleanFlags = /* @__PURE__ */ new Set();
|
|
765
|
+
const localOptionsByCommand = /* @__PURE__ */ new Map();
|
|
766
|
+
function visit(command, isRoot) {
|
|
767
|
+
const localFlags = /* @__PURE__ */ new Set();
|
|
768
|
+
for (const option of command.options) {
|
|
769
|
+
if (!option.long) continue;
|
|
770
|
+
if (option.required || option.optional) {
|
|
771
|
+
valueFlags.add(option.long);
|
|
772
|
+
} else {
|
|
773
|
+
booleanFlags.add(option.long);
|
|
774
|
+
}
|
|
775
|
+
if (!isRoot) {
|
|
776
|
+
localFlags.add(option.long);
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
if (!isRoot) {
|
|
780
|
+
localOptionsByCommand.set(getCommandPath(command), localFlags);
|
|
781
|
+
}
|
|
782
|
+
for (const sub of command.commands) {
|
|
783
|
+
visit(sub, false);
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
visit(program, true);
|
|
787
|
+
return { valueFlags, booleanFlags, localOptionsByCommand };
|
|
788
|
+
}
|
|
789
|
+
function createDefaultOptionMetadata() {
|
|
790
|
+
return {
|
|
791
|
+
valueFlags: /* @__PURE__ */ new Set([
|
|
792
|
+
"--profile",
|
|
793
|
+
"--base-url",
|
|
794
|
+
"--api-key",
|
|
795
|
+
"--install-completion",
|
|
796
|
+
"--show-completion"
|
|
797
|
+
]),
|
|
798
|
+
booleanFlags: /* @__PURE__ */ new Set([
|
|
799
|
+
"--read-only",
|
|
800
|
+
"--json",
|
|
801
|
+
"--example",
|
|
802
|
+
"--help"
|
|
803
|
+
]),
|
|
804
|
+
localOptionsByCommand: /* @__PURE__ */ new Map()
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
function isFlagToken(token) {
|
|
808
|
+
return token.length > 1 && token.startsWith("-");
|
|
809
|
+
}
|
|
810
|
+
function splitFlagToken(token) {
|
|
811
|
+
if (token.startsWith("--") && token.includes("=")) {
|
|
812
|
+
const eqIdx = token.indexOf("=");
|
|
813
|
+
return {
|
|
814
|
+
flagName: token.slice(0, eqIdx),
|
|
815
|
+
inlineValue: token.slice(eqIdx + 1)
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
return { flagName: token, inlineValue: void 0 };
|
|
819
|
+
}
|
|
820
|
+
function flagConsumesValue(flagName, optionMeta) {
|
|
821
|
+
if (optionMeta.valueFlags.has(flagName)) {
|
|
822
|
+
return true;
|
|
823
|
+
}
|
|
824
|
+
if (optionMeta.booleanFlags.has(flagName)) {
|
|
825
|
+
return false;
|
|
826
|
+
}
|
|
827
|
+
return true;
|
|
828
|
+
}
|
|
829
|
+
function collectOperandTokens(userArgs, optionMeta, options = {}) {
|
|
830
|
+
const operands = [];
|
|
831
|
+
let i = 0;
|
|
832
|
+
while (i < userArgs.length) {
|
|
833
|
+
const token = userArgs[i];
|
|
834
|
+
if (token === "--") {
|
|
835
|
+
break;
|
|
836
|
+
}
|
|
837
|
+
if (isFlagToken(token)) {
|
|
838
|
+
const { flagName, inlineValue } = splitFlagToken(token);
|
|
839
|
+
if (options.skipFlag !== void 0 && flagName === options.skipFlag) {
|
|
840
|
+
i += 1;
|
|
841
|
+
continue;
|
|
842
|
+
}
|
|
843
|
+
if (inlineValue !== void 0) {
|
|
844
|
+
i += 1;
|
|
845
|
+
continue;
|
|
846
|
+
}
|
|
847
|
+
const consumes = flagConsumesValue(flagName, optionMeta);
|
|
848
|
+
const next = userArgs[i + 1];
|
|
849
|
+
if (consumes && next !== void 0 && !isFlagToken(next)) {
|
|
850
|
+
i += 2;
|
|
851
|
+
} else {
|
|
852
|
+
i += 1;
|
|
853
|
+
}
|
|
854
|
+
continue;
|
|
855
|
+
}
|
|
856
|
+
operands.push({ index: i, token });
|
|
857
|
+
i += 1;
|
|
858
|
+
}
|
|
859
|
+
return operands;
|
|
860
|
+
}
|
|
861
|
+
function findCommandPath(operands, registry) {
|
|
862
|
+
if (operands.length === 0) return null;
|
|
863
|
+
const commandsByLength = Object.keys(registry).sort(
|
|
864
|
+
(left, right) => right.split(" ").length - left.split(" ").length
|
|
865
|
+
);
|
|
866
|
+
for (let start = 0; start < operands.length; start += 1) {
|
|
867
|
+
for (const commandName of commandsByLength) {
|
|
868
|
+
const parts = commandName.split(" ");
|
|
869
|
+
if (start + parts.length > operands.length) continue;
|
|
870
|
+
let matches = true;
|
|
871
|
+
for (let j = 0; j < parts.length; j += 1) {
|
|
872
|
+
if (operands[start + j].token !== parts[j]) {
|
|
873
|
+
matches = false;
|
|
874
|
+
break;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
if (matches) {
|
|
878
|
+
return {
|
|
879
|
+
commandName,
|
|
880
|
+
firstArgvIndex: operands[start].index,
|
|
881
|
+
lastArgvIndex: operands[start + parts.length - 1].index
|
|
882
|
+
};
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
}
|
|
886
|
+
return null;
|
|
887
|
+
}
|
|
888
|
+
function hoistGlobalOptions(argv, optionMeta, registry) {
|
|
889
|
+
if (argv.length < 3) return [...argv];
|
|
890
|
+
const userArgs = argv.slice(2);
|
|
891
|
+
const operands = collectOperandTokens(userArgs, optionMeta);
|
|
892
|
+
const cmdPath = findCommandPath(operands, registry);
|
|
893
|
+
if (!cmdPath) return [...argv];
|
|
894
|
+
const localOptions = optionMeta.localOptionsByCommand.get(cmdPath.commandName) ?? /* @__PURE__ */ new Set();
|
|
895
|
+
const hoisted = [];
|
|
896
|
+
const remaining = [];
|
|
897
|
+
let i = 0;
|
|
898
|
+
while (i < userArgs.length) {
|
|
899
|
+
const token = userArgs[i];
|
|
900
|
+
if (token === "--") {
|
|
901
|
+
remaining.push(...userArgs.slice(i));
|
|
902
|
+
break;
|
|
903
|
+
}
|
|
904
|
+
if (!isFlagToken(token)) {
|
|
905
|
+
remaining.push(token);
|
|
906
|
+
i += 1;
|
|
907
|
+
continue;
|
|
908
|
+
}
|
|
909
|
+
const { flagName, inlineValue } = splitFlagToken(token);
|
|
910
|
+
if (!isHoistableFlag(flagName)) {
|
|
911
|
+
remaining.push(token);
|
|
912
|
+
i += 1;
|
|
913
|
+
continue;
|
|
914
|
+
}
|
|
915
|
+
const isAfterCommandPath = i > cmdPath.lastArgvIndex;
|
|
916
|
+
const collidesWithLocal = localOptions.has(flagName);
|
|
917
|
+
const target = isAfterCommandPath && collidesWithLocal ? remaining : hoisted;
|
|
918
|
+
target.push(token);
|
|
919
|
+
const spec = HOISTABLE_GLOBAL_FLAGS[flagName];
|
|
920
|
+
if (spec === "value" && inlineValue === void 0) {
|
|
921
|
+
const next = userArgs[i + 1];
|
|
922
|
+
if (next !== void 0 && !isFlagToken(next)) {
|
|
923
|
+
target.push(next);
|
|
924
|
+
i += 2;
|
|
925
|
+
continue;
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
i += 1;
|
|
929
|
+
}
|
|
930
|
+
return [argv[0], argv[1], ...hoisted, ...remaining];
|
|
931
|
+
}
|
|
932
|
+
|
|
735
933
|
// src/client.ts
|
|
736
934
|
var ApiClientError = class extends Error {
|
|
737
935
|
name = "ApiClientError";
|
|
@@ -1998,17 +2196,17 @@ var fieldTypeDefinitions = [
|
|
|
1998
2196
|
className: "FormulaField",
|
|
1999
2197
|
aliases: ["formula", "FormulaField"],
|
|
2000
2198
|
description: "Calculated field from a formula.",
|
|
2001
|
-
rawShape:
|
|
2199
|
+
rawShape: '{"type":"FormulaField","slug":"formula-code","label":"Formula Code","config":{"formulaText":"concat(\\"CUST-\\", f1e1d000-0000-0000-0000-000000000005)","uiFormatKind":"none"}}',
|
|
2002
2200
|
examplePayloads: [
|
|
2003
2201
|
{
|
|
2004
2202
|
name: "Formula field (none)",
|
|
2005
2203
|
payload: {
|
|
2006
2204
|
type: "FormulaField",
|
|
2007
|
-
slug: "formula-
|
|
2008
|
-
label: "Formula
|
|
2205
|
+
slug: "formula-code",
|
|
2206
|
+
label: "Formula Code",
|
|
2009
2207
|
required: false,
|
|
2010
2208
|
config: {
|
|
2011
|
-
formulaText:
|
|
2209
|
+
formulaText: 'concat("CUST-", f1e1d000-0000-0000-0000-000000000005)',
|
|
2012
2210
|
uiFormatKind: "none",
|
|
2013
2211
|
status: "ACTIVE",
|
|
2014
2212
|
conditionalFormatting: []
|
|
@@ -2023,7 +2221,7 @@ var fieldTypeDefinitions = [
|
|
|
2023
2221
|
label: "Formula Total",
|
|
2024
2222
|
required: false,
|
|
2025
2223
|
config: {
|
|
2026
|
-
formulaText: "
|
|
2224
|
+
formulaText: "c52efe3f-2825-4c60-a7e3-34dd4c1ce043 * 1.21",
|
|
2027
2225
|
uiFormatKind: "number",
|
|
2028
2226
|
status: "ACTIVE",
|
|
2029
2227
|
numberFormatOptions: {
|
|
@@ -2039,11 +2237,11 @@ var fieldTypeDefinitions = [
|
|
|
2039
2237
|
name: "Formula field (date)",
|
|
2040
2238
|
payload: {
|
|
2041
2239
|
type: "FormulaField",
|
|
2042
|
-
slug: "formula-
|
|
2043
|
-
label: "
|
|
2240
|
+
slug: "formula-period",
|
|
2241
|
+
label: "Formula Period",
|
|
2044
2242
|
required: false,
|
|
2045
2243
|
config: {
|
|
2046
|
-
formulaText:
|
|
2244
|
+
formulaText: 'date_format(d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90, "AAAA-MM")',
|
|
2047
2245
|
uiFormatKind: "date",
|
|
2048
2246
|
status: "ACTIVE",
|
|
2049
2247
|
dateFormatOptions: {
|
|
@@ -2063,7 +2261,7 @@ var fieldTypeDefinitions = [
|
|
|
2063
2261
|
label: "Computed Assignee",
|
|
2064
2262
|
required: false,
|
|
2065
2263
|
config: {
|
|
2066
|
-
formulaText: "
|
|
2264
|
+
formulaText: "a7b8c9d0-e1f2-3a4b-5c6d-7e8f90123456",
|
|
2067
2265
|
uiFormatKind: "member",
|
|
2068
2266
|
status: "ACTIVE",
|
|
2069
2267
|
conditionalFormatting: []
|
|
@@ -2800,11 +2998,11 @@ var specificExamples = {
|
|
|
2800
2998
|
},
|
|
2801
2999
|
{
|
|
2802
3000
|
description: "Patch formula field (formula text).",
|
|
2803
|
-
command: `zinkee --json schemas fields update contacts formula-total --raw '{"type":"FormulaField","config":{"formulaText":"
|
|
3001
|
+
command: `zinkee --json schemas fields update contacts formula-total --raw '{"type":"FormulaField","config":{"formulaText":"c52efe3f-2825-4c60-a7e3-34dd4c1ce043 * 1.10","uiFormatKind":"number","status":"ACTIVE","numberFormatOptions":{"format":"number","decimals":2,"thousandsSeparator":true},"conditionalFormatting":[]}}'`,
|
|
2804
3002
|
raw: `{
|
|
2805
3003
|
"type": "FormulaField",
|
|
2806
3004
|
"config": {
|
|
2807
|
-
"formulaText": "
|
|
3005
|
+
"formulaText": "c52efe3f-2825-4c60-a7e3-34dd4c1ce043 * 1.10",
|
|
2808
3006
|
"uiFormatKind": "number",
|
|
2809
3007
|
"status": "ACTIVE",
|
|
2810
3008
|
"numberFormatOptions": {
|
|
@@ -3715,8 +3913,8 @@ var specificExamples = {
|
|
|
3715
3913
|
}`
|
|
3716
3914
|
},
|
|
3717
3915
|
{
|
|
3718
|
-
description: "Create a
|
|
3719
|
-
command: `zinkee --json displays widgets create 0f6f062f-1478-4df2-96a1-c495d037d260 --type CHART --name "Revenue by month" --origin-resource 2eb8bdcf-6d9c-4fbb-9018-7fa8180f4c5e --layout '{"x":0,"y":0,"w":8,"h":6}' --chart-type
|
|
3916
|
+
description: "Create a bars CHART widget with a time-serie x-axis and two y-axis series.",
|
|
3917
|
+
command: `zinkee --json displays widgets create 0f6f062f-1478-4df2-96a1-c495d037d260 --type CHART --name "Revenue by month" --origin-resource 2eb8bdcf-6d9c-4fbb-9018-7fa8180f4c5e --layout '{"x":0,"y":0,"w":8,"h":6}' --chart-type bars --x-axis-field due-date --x-axis-date-format MONTH --x-axis-time-series --y-axis-serie '{"typeCalc":"SUM","fieldCalc":"amount","color":"#4B9CD3","axisType":"PRIMARY"}' --y-axis-serie '{"typeCalc":"COUNT","fieldCalc":"id","color":"#E57373","axisType":"SECONDARY"}' --legend '{"position":"bottom"}'`,
|
|
3720
3918
|
raw: `{
|
|
3721
3919
|
"type": "CHART",
|
|
3722
3920
|
"source": {
|
|
@@ -3728,7 +3926,7 @@ var specificExamples = {
|
|
|
3728
3926
|
},
|
|
3729
3927
|
"presentation": { "name": "Revenue by month" },
|
|
3730
3928
|
"chart": {
|
|
3731
|
-
"chartType": "
|
|
3929
|
+
"chartType": "bars",
|
|
3732
3930
|
"xAxisFieldId": "due-date",
|
|
3733
3931
|
"xAxisDateFormat": "MONTH",
|
|
3734
3932
|
"xAxisAsTimeSerie": true,
|
|
@@ -3737,13 +3935,13 @@ var specificExamples = {
|
|
|
3737
3935
|
"typeCalc": "SUM",
|
|
3738
3936
|
"fieldCalc": "amount",
|
|
3739
3937
|
"color": "#4B9CD3",
|
|
3740
|
-
"axisType": "
|
|
3938
|
+
"axisType": "PRIMARY"
|
|
3741
3939
|
},
|
|
3742
3940
|
{
|
|
3743
3941
|
"typeCalc": "COUNT",
|
|
3744
3942
|
"fieldCalc": "id",
|
|
3745
3943
|
"color": "#E57373",
|
|
3746
|
-
"axisType": "
|
|
3944
|
+
"axisType": "SECONDARY"
|
|
3747
3945
|
}
|
|
3748
3946
|
],
|
|
3749
3947
|
"legend": { "position": "bottom" }
|
|
@@ -3889,11 +4087,11 @@ var specificExamples = {
|
|
|
3889
4087
|
}`
|
|
3890
4088
|
},
|
|
3891
4089
|
{
|
|
3892
|
-
description: "Replace the chart series with
|
|
3893
|
-
command: `zinkee --json displays widgets update 0f6f062f-1478-4df2-96a1-c495d037d260 22222222-2222-4222-a222-222222222222 --chart-type
|
|
4090
|
+
description: "Replace the chart series with weekly lines.",
|
|
4091
|
+
command: `zinkee --json displays widgets update 0f6f062f-1478-4df2-96a1-c495d037d260 22222222-2222-4222-a222-222222222222 --chart-type lines --x-axis-field due-date --x-axis-date-format WEEK --x-axis-time-series --y-axis-serie '{"typeCalc":"SUM","fieldCalc":"amount","color":"#2E7D32","axisType":"PRIMARY"}'`,
|
|
3894
4092
|
raw: `{
|
|
3895
4093
|
"chart": {
|
|
3896
|
-
"chartType": "
|
|
4094
|
+
"chartType": "lines",
|
|
3897
4095
|
"xAxisFieldId": "due-date",
|
|
3898
4096
|
"xAxisDateFormat": "WEEK",
|
|
3899
4097
|
"xAxisAsTimeSerie": true,
|
|
@@ -3902,7 +4100,7 @@ var specificExamples = {
|
|
|
3902
4100
|
"typeCalc": "SUM",
|
|
3903
4101
|
"fieldCalc": "amount",
|
|
3904
4102
|
"color": "#2E7D32",
|
|
3905
|
-
"axisType": "
|
|
4103
|
+
"axisType": "PRIMARY"
|
|
3906
4104
|
}
|
|
3907
4105
|
]
|
|
3908
4106
|
}
|
|
@@ -4230,7 +4428,7 @@ var specificExamples = {
|
|
|
4230
4428
|
"required": false,
|
|
4231
4429
|
"system": false,
|
|
4232
4430
|
"config": {
|
|
4233
|
-
"formulaText": "
|
|
4431
|
+
"formulaText": "c52efe3f-2825-4c60-a7e3-34dd4c1ce043 * 1.21",
|
|
4234
4432
|
"uiFormatKind": "number",
|
|
4235
4433
|
"status": "ACTIVE",
|
|
4236
4434
|
"defaultValue": null,
|
|
@@ -4245,12 +4443,12 @@ var specificExamples = {
|
|
|
4245
4443
|
{
|
|
4246
4444
|
"id": "6d7e8f90-1234-5678-9abc-def012345678",
|
|
4247
4445
|
"type": "FormulaField",
|
|
4248
|
-
"slug": "formula-
|
|
4249
|
-
"label": "
|
|
4446
|
+
"slug": "formula-period",
|
|
4447
|
+
"label": "Formula Period",
|
|
4250
4448
|
"required": false,
|
|
4251
4449
|
"system": false,
|
|
4252
4450
|
"config": {
|
|
4253
|
-
"formulaText": "
|
|
4451
|
+
"formulaText": "date_format(d4e5f6a7-b8c9-0d1e-2f3a-4b5c6d7e8f90, "AAAA-MM")",
|
|
4254
4452
|
"uiFormatKind": "date",
|
|
4255
4453
|
"status": "ACTIVE",
|
|
4256
4454
|
"defaultValue": null,
|
|
@@ -4532,6 +4730,16 @@ var specificExamples = {
|
|
|
4532
4730
|
response: `{
|
|
4533
4731
|
"recordId": "550e8400-e29b-41d4-a716-446655440000",
|
|
4534
4732
|
"deleted": true
|
|
4733
|
+
}`
|
|
4734
|
+
}
|
|
4735
|
+
]),
|
|
4736
|
+
"records clear": buildCommandExamples([
|
|
4737
|
+
{
|
|
4738
|
+
description: "Delete every record from a schema's table. Heritage rules (CASCADE / SET NULL) propagate to child schemas asynchronously via the CDC pipeline.",
|
|
4739
|
+
command: "zinkee --json records clear contacts",
|
|
4740
|
+
response: `{
|
|
4741
|
+
"schemaId": "2eb8bdcf-6d9c-4fbb-9018-7fa8180f4c5e",
|
|
4742
|
+
"cleared": true
|
|
4535
4743
|
}`
|
|
4536
4744
|
}
|
|
4537
4745
|
]),
|
|
@@ -5613,7 +5821,7 @@ var specificExamples = {
|
|
|
5613
5821
|
},
|
|
5614
5822
|
{
|
|
5615
5823
|
description: "Add a search-records action whose condition pulls its value from the trigger payload using --condition-json.",
|
|
5616
|
-
command: `zinkee --json automations actions add automation-1 --type search_records --name "Find duplicates" --target-schema followups --condition-json '{"field":"email","comparator":"eq","values":[{"rawValue":null,"source":{"type":"TRIGGER","id":"
|
|
5824
|
+
command: `zinkee --json automations actions add automation-1 --type search_records --name "Find duplicates" --target-schema followups --condition-json '{"field":"email","comparator":"eq","values":[{"rawValue":null,"source":{"type":"TRIGGER","id":"f1e1d000-0000-0000-0000-000000000005"}}]}'`,
|
|
5617
5825
|
raw: `{
|
|
5618
5826
|
"type": "search_records",
|
|
5619
5827
|
"name": "Find duplicates",
|
|
@@ -5628,7 +5836,7 @@ var specificExamples = {
|
|
|
5628
5836
|
"rawValue": null,
|
|
5629
5837
|
"source": {
|
|
5630
5838
|
"type": "TRIGGER",
|
|
5631
|
-
"id": "
|
|
5839
|
+
"id": "f1e1d000-0000-0000-0000-000000000005"
|
|
5632
5840
|
}
|
|
5633
5841
|
}
|
|
5634
5842
|
]
|
|
@@ -6137,7 +6345,7 @@ async function buildDynamicAutomationExamples(commandName, options = {}) {
|
|
|
6137
6345
|
return buildCommandExamples([
|
|
6138
6346
|
{
|
|
6139
6347
|
description: `Add a create-record action with literal and trigger-based mappings targeting ${schemaField.schemaRef}.`,
|
|
6140
|
-
command: `zinkee --json automations actions add ${automationId} --type create_record --name "Create follow-up order" --target-schema ${schemaField.schemaRef} --map ${schemaField.fieldRef}=pending --map-json owner='{"rawValue":null,"source":{"type":"TRIGGER","id":"
|
|
6348
|
+
command: `zinkee --json automations actions add ${automationId} --type create_record --name "Create follow-up order" --target-schema ${schemaField.schemaRef} --map ${schemaField.fieldRef}=pending --map-json owner='{"rawValue":null,"source":{"type":"TRIGGER","id":"${schemaField.fieldId}"}}'`,
|
|
6141
6349
|
raw: `{
|
|
6142
6350
|
"type": "create_record",
|
|
6143
6351
|
"name": "Create follow-up order",
|
|
@@ -6152,7 +6360,7 @@ async function buildDynamicAutomationExamples(commandName, options = {}) {
|
|
|
6152
6360
|
"rawValue": null,
|
|
6153
6361
|
"source": {
|
|
6154
6362
|
"type": "TRIGGER",
|
|
6155
|
-
"id": "
|
|
6363
|
+
"id": "${schemaField.fieldId}"
|
|
6156
6364
|
}
|
|
6157
6365
|
}
|
|
6158
6366
|
}
|
|
@@ -6179,7 +6387,7 @@ async function buildDynamicAutomationExamples(commandName, options = {}) {
|
|
|
6179
6387
|
},
|
|
6180
6388
|
{
|
|
6181
6389
|
description: `Add a search-records action with a trigger-based condition on ${schemaField.schemaRef}.`,
|
|
6182
|
-
command: `zinkee --json automations actions add ${automationId} --type search_records --name "Find duplicates" --target-schema ${schemaField.schemaRef} --condition-json '{"field":"${schemaField.fieldRef}","comparator":"eq","values":[{"rawValue":null,"source":{"type":"TRIGGER","id":"
|
|
6390
|
+
command: `zinkee --json automations actions add ${automationId} --type search_records --name "Find duplicates" --target-schema ${schemaField.schemaRef} --condition-json '{"field":"${schemaField.fieldRef}","comparator":"eq","values":[{"rawValue":null,"source":{"type":"TRIGGER","id":"${schemaField.fieldId}"}}]}'`,
|
|
6183
6391
|
raw: `{
|
|
6184
6392
|
"type": "search_records",
|
|
6185
6393
|
"name": "Find duplicates",
|
|
@@ -6194,7 +6402,7 @@ async function buildDynamicAutomationExamples(commandName, options = {}) {
|
|
|
6194
6402
|
"rawValue": null,
|
|
6195
6403
|
"source": {
|
|
6196
6404
|
"type": "TRIGGER",
|
|
6197
|
-
"id": "
|
|
6405
|
+
"id": "${schemaField.fieldId}"
|
|
6198
6406
|
}
|
|
6199
6407
|
}
|
|
6200
6408
|
]
|
|
@@ -6392,26 +6600,6 @@ async function getResolvedCommandExamples(commandName, filters = {}, options = {
|
|
|
6392
6600
|
function getStdout(stdout) {
|
|
6393
6601
|
return stdout ?? process.stdout;
|
|
6394
6602
|
}
|
|
6395
|
-
function resolveExampleCommand(tokens) {
|
|
6396
|
-
const commands = Object.keys(commandRegistry).sort(
|
|
6397
|
-
(left, right) => right.split(" ").length - left.split(" ").length
|
|
6398
|
-
);
|
|
6399
|
-
for (const commandName of commands) {
|
|
6400
|
-
const commandTokens2 = commandName.split(" ");
|
|
6401
|
-
const matches = commandTokens2.every((token, index) => tokens[index] === token);
|
|
6402
|
-
if (matches) {
|
|
6403
|
-
return {
|
|
6404
|
-
commandName,
|
|
6405
|
-
remainingTokens: tokens.slice(commandTokens2.length)
|
|
6406
|
-
};
|
|
6407
|
-
}
|
|
6408
|
-
}
|
|
6409
|
-
const commandTokens = tokens.filter((token) => !token.startsWith("-"));
|
|
6410
|
-
return {
|
|
6411
|
-
commandName: commandTokens.join(" "),
|
|
6412
|
-
remainingTokens: []
|
|
6413
|
-
};
|
|
6414
|
-
}
|
|
6415
6603
|
function extractExampleFilters(tokens) {
|
|
6416
6604
|
const filters = {};
|
|
6417
6605
|
for (let index = 0; index < tokens.length; index += 1) {
|
|
@@ -6451,18 +6639,19 @@ function extractExampleOverrides(tokens) {
|
|
|
6451
6639
|
}
|
|
6452
6640
|
return overrides;
|
|
6453
6641
|
}
|
|
6454
|
-
function extractExampleRequest(argv) {
|
|
6455
|
-
|
|
6456
|
-
if (exampleIndex === -1) {
|
|
6642
|
+
function extractExampleRequest(argv, optionMeta = createDefaultOptionMetadata()) {
|
|
6643
|
+
if (!argv.includes("--example")) {
|
|
6457
6644
|
return null;
|
|
6458
6645
|
}
|
|
6459
|
-
const
|
|
6460
|
-
const
|
|
6461
|
-
|
|
6646
|
+
const userArgs = argv.slice(2);
|
|
6647
|
+
const operands = collectOperandTokens(userArgs, optionMeta, { skipFlag: "--example" });
|
|
6648
|
+
const cmdPath = findCommandPath(operands, commandRegistry);
|
|
6649
|
+
if (!cmdPath) {
|
|
6462
6650
|
throw new CliError("invalid_cli_usage", 'Provide a command after "--example".');
|
|
6463
6651
|
}
|
|
6652
|
+
const remainingTokens = userArgs.slice(cmdPath.lastArgvIndex + 1);
|
|
6464
6653
|
return {
|
|
6465
|
-
commandName,
|
|
6654
|
+
commandName: cmdPath.commandName,
|
|
6466
6655
|
filters: extractExampleFilters(remainingTokens),
|
|
6467
6656
|
overrides: extractExampleOverrides(argv),
|
|
6468
6657
|
json: argv.includes("--json")
|
|
@@ -9601,6 +9790,12 @@ var RecordsApi = class {
|
|
|
9601
9790
|
{ method: "DELETE" }
|
|
9602
9791
|
);
|
|
9603
9792
|
}
|
|
9793
|
+
clearRecords(schema) {
|
|
9794
|
+
return this.client.requestJson(
|
|
9795
|
+
`/api/v2/schemas/${selectorValue8(schema)}/records:clear`,
|
|
9796
|
+
{ method: "DELETE" }
|
|
9797
|
+
);
|
|
9798
|
+
}
|
|
9604
9799
|
normalizeQueryInput(query) {
|
|
9605
9800
|
const where = query.where?.map((expression) => ({
|
|
9606
9801
|
field: expression.field,
|
|
@@ -10127,6 +10322,17 @@ function registerRecordsCommands(program, options = {}) {
|
|
|
10127
10322
|
}
|
|
10128
10323
|
writeLine9(stdout, `Deleted record "${record.value}" from schema "${schema.value}".`);
|
|
10129
10324
|
});
|
|
10325
|
+
records.command("clear").description("Delete all records from a schema's table").argument("<schema>", "schema uuid or slug", parseUuidOrSlugSelector7).action(async function action(schema) {
|
|
10326
|
+
const { api, schemasApi, json, readOnly } = createRecordsApi(this, filePath);
|
|
10327
|
+
ensureWritable6("records clear", readOnly, "destructive");
|
|
10328
|
+
const resolvedSchema = await resolveSchemaSelector(schemasApi, schema);
|
|
10329
|
+
const data = await api.clearRecords(resolvedSchema);
|
|
10330
|
+
if (json) {
|
|
10331
|
+
emitJson9(stdout, "records clear", data, filePath);
|
|
10332
|
+
return;
|
|
10333
|
+
}
|
|
10334
|
+
writeLine9(stdout, `Cleared all records from schema "${schema.value}".`);
|
|
10335
|
+
});
|
|
10130
10336
|
}
|
|
10131
10337
|
|
|
10132
10338
|
// src/commands/schemas.ts
|
|
@@ -11541,7 +11747,9 @@ async function runCli(argv) {
|
|
|
11541
11747
|
process.exitCode = exitCode;
|
|
11542
11748
|
return;
|
|
11543
11749
|
}
|
|
11544
|
-
const
|
|
11750
|
+
const program = buildProgram();
|
|
11751
|
+
const optionMeta = buildOptionMetadata(program);
|
|
11752
|
+
const exampleRequest = extractExampleRequest(argv, optionMeta);
|
|
11545
11753
|
if (exampleRequest) {
|
|
11546
11754
|
await showExamples(
|
|
11547
11755
|
exampleRequest.commandName,
|
|
@@ -11555,7 +11763,8 @@ async function runCli(argv) {
|
|
|
11555
11763
|
);
|
|
11556
11764
|
throw new ExampleDisplayed();
|
|
11557
11765
|
}
|
|
11558
|
-
|
|
11766
|
+
const rewrittenArgv = hoistGlobalOptions(argv, optionMeta, commandRegistry);
|
|
11767
|
+
await program.parseAsync(rewrittenArgv);
|
|
11559
11768
|
} catch (error) {
|
|
11560
11769
|
if (error instanceof ExampleDisplayed) {
|
|
11561
11770
|
process.exitCode = 0;
|