@datarails-ai/dr-cli 1.6.120 → 1.6.122
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/dist/cli.js
CHANGED
|
@@ -8,7 +8,7 @@ import { fileURLToPath as fileURLToPath3 } from "url";
|
|
|
8
8
|
// package.json
|
|
9
9
|
var package_default = {
|
|
10
10
|
name: "@datarails-ai/dr-cli",
|
|
11
|
-
version: "1.6.
|
|
11
|
+
version: "1.6.122",
|
|
12
12
|
description: "Datarails CLI",
|
|
13
13
|
type: "module",
|
|
14
14
|
engines: {
|
|
@@ -69,7 +69,7 @@ var package_default = {
|
|
|
69
69
|
};
|
|
70
70
|
|
|
71
71
|
// src/buildInfo.ts
|
|
72
|
-
var BUILD_TIME = "2026-10-12T10:
|
|
72
|
+
var BUILD_TIME = "2026-10-12T10:51:59.680Z";
|
|
73
73
|
function formatBuildTime(iso) {
|
|
74
74
|
if (iso === "") return "";
|
|
75
75
|
const d = new Date(iso);
|
|
@@ -31029,6 +31029,96 @@ function formatCalcFieldError(name, preview2, full) {
|
|
|
31029
31029
|
return `${head} looks like placeholder text, not a real expression. The server's ETL compiler rejects formulas with no [field] reference, "quoted" literal, function() call, or numeric value \u2014 replace it before retrying. Common cause: a GET \u2192 PUT round-trip on a pre-kickoff starter mapper carried the placeholder text forward.`;
|
|
31030
31030
|
}
|
|
31031
31031
|
|
|
31032
|
+
// src/commands/_mapperConfigShape.ts
|
|
31033
|
+
var OBJECT_LIST_KEYS = [
|
|
31034
|
+
"header",
|
|
31035
|
+
"dimension",
|
|
31036
|
+
"footer",
|
|
31037
|
+
"attributes",
|
|
31038
|
+
"calculated_fields",
|
|
31039
|
+
"fx_conversions",
|
|
31040
|
+
"table_id"
|
|
31041
|
+
];
|
|
31042
|
+
var GET_HINT = '`dr datamappers get <mapper_id> --json` shows the shape the server expects (a mapper with no anchor carries "table_id": []).';
|
|
31043
|
+
function describeValue(v) {
|
|
31044
|
+
if (v === null) return "null";
|
|
31045
|
+
if (Array.isArray(v)) return "an array";
|
|
31046
|
+
switch (typeof v) {
|
|
31047
|
+
case "number":
|
|
31048
|
+
return `a number (${String(v)})`;
|
|
31049
|
+
case "string":
|
|
31050
|
+
return `a string (${JSON.stringify(v.length > 40 ? `${v.slice(0, 40)}\u2026` : v)})`;
|
|
31051
|
+
case "boolean":
|
|
31052
|
+
return `a boolean (${String(v)})`;
|
|
31053
|
+
case "object":
|
|
31054
|
+
return "an object";
|
|
31055
|
+
default:
|
|
31056
|
+
return typeof v;
|
|
31057
|
+
}
|
|
31058
|
+
}
|
|
31059
|
+
function isPlainObject2(v) {
|
|
31060
|
+
return v !== null && typeof v === "object" && !Array.isArray(v);
|
|
31061
|
+
}
|
|
31062
|
+
function tableIdProblems(value) {
|
|
31063
|
+
if (!Array.isArray(value)) {
|
|
31064
|
+
return [
|
|
31065
|
+
`config.table_id must be an array, got ${describeValue(value)}. It is the table anchor, not the table id: [] for none, or one cell object such as [{"coordinate": "A1", "value": "<text in that cell>", "match_type": "any_text"}]. The table id goes on the command line, not in the body.`
|
|
31066
|
+
];
|
|
31067
|
+
}
|
|
31068
|
+
const out = [];
|
|
31069
|
+
if (value.length > 1) {
|
|
31070
|
+
out.push(
|
|
31071
|
+
`config.table_id holds ${value.length} entries; the server allows at most one anchor ("Only one anchor is allowed").`
|
|
31072
|
+
);
|
|
31073
|
+
}
|
|
31074
|
+
value.forEach((entry, i) => {
|
|
31075
|
+
if (!isPlainObject2(entry)) {
|
|
31076
|
+
out.push(`config.table_id[${i}] must be an object, got ${describeValue(entry)}.`);
|
|
31077
|
+
} else if (typeof entry["match_type"] !== "string") {
|
|
31078
|
+
out.push(
|
|
31079
|
+
`config.table_id[${i}].match_type is required (a string such as "any_text" or "location").`
|
|
31080
|
+
);
|
|
31081
|
+
}
|
|
31082
|
+
});
|
|
31083
|
+
return out;
|
|
31084
|
+
}
|
|
31085
|
+
function validateMapperConfigShape(config) {
|
|
31086
|
+
if (config === void 0) return;
|
|
31087
|
+
if (!isPlainObject2(config)) {
|
|
31088
|
+
throw new Error(`config must be a JSON object, got ${describeValue(config)}. ${GET_HINT}`);
|
|
31089
|
+
}
|
|
31090
|
+
const problems = [];
|
|
31091
|
+
for (const key of OBJECT_LIST_KEYS) {
|
|
31092
|
+
if (!(key in config)) continue;
|
|
31093
|
+
const value = config[key];
|
|
31094
|
+
if (key === "table_id") {
|
|
31095
|
+
problems.push(...tableIdProblems(value));
|
|
31096
|
+
continue;
|
|
31097
|
+
}
|
|
31098
|
+
if (!Array.isArray(value)) {
|
|
31099
|
+
problems.push(`config.${key} must be an array of objects, got ${describeValue(value)}.`);
|
|
31100
|
+
continue;
|
|
31101
|
+
}
|
|
31102
|
+
value.forEach((entry, i) => {
|
|
31103
|
+
if (!isPlainObject2(entry)) {
|
|
31104
|
+
problems.push(`config.${key}[${i}] must be an object, got ${describeValue(entry)}.`);
|
|
31105
|
+
}
|
|
31106
|
+
});
|
|
31107
|
+
}
|
|
31108
|
+
if ("include_sheets" in config && !Array.isArray(config["include_sheets"])) {
|
|
31109
|
+
problems.push(
|
|
31110
|
+
`config.include_sheets must be an array, got ${describeValue(config["include_sheets"])}.`
|
|
31111
|
+
);
|
|
31112
|
+
}
|
|
31113
|
+
if (problems.length > 0) {
|
|
31114
|
+
throw new Error(
|
|
31115
|
+
`invalid datamapper config (the server would answer an unattributed HTTP 500 / "Unknown error"):
|
|
31116
|
+
- ${problems.join("\n - ")}
|
|
31117
|
+
${GET_HINT}`
|
|
31118
|
+
);
|
|
31119
|
+
}
|
|
31120
|
+
}
|
|
31121
|
+
|
|
31032
31122
|
// src/commands/_errorLog.ts
|
|
31033
31123
|
import { promises as fs14 } from "fs";
|
|
31034
31124
|
import * as os3 from "os";
|
|
@@ -31289,6 +31379,7 @@ async function runPreviewData(cfg) {
|
|
|
31289
31379
|
throw new Error("--payload-file is required");
|
|
31290
31380
|
}
|
|
31291
31381
|
let body = await readJsonPayload(payloadFile);
|
|
31382
|
+
validateMapperConfigShape(body["config"]);
|
|
31292
31383
|
const { decoded, changeCount } = decodeBodyEntitiesDeep(body);
|
|
31293
31384
|
if (changeCount > 0) {
|
|
31294
31385
|
body = decoded;
|
|
@@ -31485,7 +31576,12 @@ async function runDatamappersCreate(cfg) {
|
|
|
31485
31576
|
parseKeyEqualsValue(cfg.flags.calcs, "--calc");
|
|
31486
31577
|
parseKeyEqualsValue(cfg.flags.attrs, "--attr");
|
|
31487
31578
|
parseKeyEqualsValue(cfg.flags.dims, "--dim");
|
|
31488
|
-
parseKeyEqualsValue(cfg.flags.tableIdCells ?? [], "--table-id-cell");
|
|
31579
|
+
const tableIdCells = parseKeyEqualsValue(cfg.flags.tableIdCells ?? [], "--table-id-cell");
|
|
31580
|
+
if (tableIdCells.length > 1) {
|
|
31581
|
+
throw new Error(
|
|
31582
|
+
`--table-id-cell takes one cell; got ${tableIdCells.length}. The server allows one table anchor per mapper.`
|
|
31583
|
+
);
|
|
31584
|
+
}
|
|
31489
31585
|
parseKeyEqualsValue(cfg.flags.footers, "--footer");
|
|
31490
31586
|
parseKeyEqualsValue(cfg.flags.renames, "--rename");
|
|
31491
31587
|
}
|
|
@@ -31493,6 +31589,7 @@ async function runDatamappersCreate(cfg) {
|
|
|
31493
31589
|
let body;
|
|
31494
31590
|
if (payloadFile !== "") {
|
|
31495
31591
|
body = await readJsonPayload(payloadFile);
|
|
31592
|
+
validateMapperConfigShape(body["config"]);
|
|
31496
31593
|
} else {
|
|
31497
31594
|
body = await buildConveniencePayload(
|
|
31498
31595
|
cfg.client,
|
|
@@ -31590,6 +31687,7 @@ async function runDatamappersUpdate(cfg) {
|
|
|
31590
31687
|
}
|
|
31591
31688
|
const rescanValue = resolveRescan(cfg.rescan, cfg.noRescan);
|
|
31592
31689
|
let body = await readJsonPayload(payloadFile);
|
|
31690
|
+
validateMapperConfigShape(body["config"]);
|
|
31593
31691
|
if (rescanValue === "") {
|
|
31594
31692
|
delete body["rescan"];
|
|
31595
31693
|
} else {
|
|
@@ -32229,7 +32327,7 @@ function registerDatamappersCommand(root) {
|
|
|
32229
32327
|
addAccountFlag(dimensionCmd);
|
|
32230
32328
|
const multipleCmd = addConvenienceFlags(
|
|
32231
32329
|
createCmd.command("multiple").description(
|
|
32232
|
-
"Create a multiple-tables datamapper (requires --dim \u2265 1 AND --table-id-cell
|
|
32330
|
+
"Create a multiple-tables datamapper (requires --dim \u2265 1 AND one --table-id-cell)"
|
|
32233
32331
|
).argument("<table_id>", "Table ID (positive integer)")
|
|
32234
32332
|
).requiredOption(
|
|
32235
32333
|
"--dim <Coord=Label>",
|
|
@@ -32238,7 +32336,7 @@ function registerDatamappersCommand(root) {
|
|
|
32238
32336
|
[]
|
|
32239
32337
|
).requiredOption(
|
|
32240
32338
|
"--table-id-cell <Coord=Label>",
|
|
32241
|
-
"
|
|
32339
|
+
"The table_id (anchor) cell \u2014 the cell carrying the per-section table identifier. Required; the server allows exactly one.",
|
|
32242
32340
|
collectArrayOpt,
|
|
32243
32341
|
[]
|
|
32244
32342
|
).action(async (tableIdStr, opts) => {
|
|
@@ -37590,6 +37688,34 @@ function requireTagPermission(details, perm, docId, action) {
|
|
|
37590
37688
|
);
|
|
37591
37689
|
}
|
|
37592
37690
|
}
|
|
37691
|
+
var TagWriteRefusedError = class extends Error {
|
|
37692
|
+
constructor(message, reason) {
|
|
37693
|
+
super(message);
|
|
37694
|
+
this.reason = reason;
|
|
37695
|
+
this.name = "TagWriteRefusedError";
|
|
37696
|
+
}
|
|
37697
|
+
reason;
|
|
37698
|
+
};
|
|
37699
|
+
function fullTagSetWith(stored, write) {
|
|
37700
|
+
const kept = [];
|
|
37701
|
+
for (const raw of stored ?? []) {
|
|
37702
|
+
if (typeof raw !== "object" || raw === null) {
|
|
37703
|
+
continue;
|
|
37704
|
+
}
|
|
37705
|
+
const t = raw;
|
|
37706
|
+
const id = typeof t.id === "string" && t.id.trim() !== "" ? Number(t.id) : t.id;
|
|
37707
|
+
if (typeof id !== "number" || !Number.isInteger(id) || id === write.id || kept.some((k) => k.id === id) || t.value === void 0 || t.value === null) {
|
|
37708
|
+
continue;
|
|
37709
|
+
}
|
|
37710
|
+
kept.push({
|
|
37711
|
+
id,
|
|
37712
|
+
value: t.value,
|
|
37713
|
+
...typeof t.name === "string" ? { name: t.name } : {},
|
|
37714
|
+
...typeof t.label === "string" ? { label: t.label } : {}
|
|
37715
|
+
});
|
|
37716
|
+
}
|
|
37717
|
+
return [...kept, write].sort((a, b) => a.id - b.id);
|
|
37718
|
+
}
|
|
37593
37719
|
async function runFileboxSetVersionFileStatus(cfg) {
|
|
37594
37720
|
if (cfg.docId <= 0) {
|
|
37595
37721
|
throw new Error("document id must be positive");
|
|
@@ -37644,6 +37770,8 @@ async function runFileboxSetVersionFileStatus(cfg) {
|
|
|
37644
37770
|
changed: false,
|
|
37645
37771
|
verified: true,
|
|
37646
37772
|
reapplied: false,
|
|
37773
|
+
date_tag_value: target.date_tag_value ?? null,
|
|
37774
|
+
date_tag_value_preserved: true,
|
|
37647
37775
|
demoted_version_ids: [],
|
|
37648
37776
|
rescan_queued: false
|
|
37649
37777
|
});
|
|
@@ -37675,19 +37803,31 @@ async function runFileboxSetVersionFileStatus(cfg) {
|
|
|
37675
37803
|
);
|
|
37676
37804
|
}
|
|
37677
37805
|
}
|
|
37678
|
-
const
|
|
37679
|
-
|
|
37680
|
-
|
|
37806
|
+
const statusWrite = {
|
|
37807
|
+
id: tag.id,
|
|
37808
|
+
value: cfg.status,
|
|
37809
|
+
name: tag.name,
|
|
37810
|
+
label: cfg.status
|
|
37811
|
+
};
|
|
37812
|
+
let base = target.tags ?? [];
|
|
37813
|
+
const refreshBase = (v) => {
|
|
37814
|
+
if (v !== null && v.tags.length > 0) {
|
|
37815
|
+
base = v.tags;
|
|
37816
|
+
}
|
|
37817
|
+
};
|
|
37681
37818
|
const write = async () => {
|
|
37682
37819
|
const res = await setVersionTagsAndLabel(
|
|
37683
37820
|
cfg.client,
|
|
37684
37821
|
cfg.versionId,
|
|
37685
|
-
{ tags_to_update:
|
|
37822
|
+
{ tags_to_update: JSON.stringify(fullTagSetWith(base, statusWrite)) },
|
|
37686
37823
|
{ signal: cfg.signal }
|
|
37687
37824
|
);
|
|
37688
37825
|
if (res.status < 200 || res.status >= 300) {
|
|
37689
37826
|
const body = await res.text();
|
|
37690
|
-
throw new
|
|
37827
|
+
throw new TagWriteRefusedError(
|
|
37828
|
+
`set version file status refused (HTTP ${res.status}): ${body.trim()}`,
|
|
37829
|
+
`(HTTP ${res.status}): ${body.trim()}`
|
|
37830
|
+
);
|
|
37691
37831
|
}
|
|
37692
37832
|
};
|
|
37693
37833
|
const readBack = async () => {
|
|
@@ -37699,6 +37839,7 @@ async function runFileboxSetVersionFileStatus(cfg) {
|
|
|
37699
37839
|
let seen = await readBack();
|
|
37700
37840
|
if (seen !== null && tagValueOf(seen.tags, tag.id) !== cfg.status) {
|
|
37701
37841
|
reapplied = true;
|
|
37842
|
+
refreshBase(seen);
|
|
37702
37843
|
await write();
|
|
37703
37844
|
seen = await readBack();
|
|
37704
37845
|
const now = seen === null ? void 0 : tagValueOf(seen.tags, tag.id);
|
|
@@ -37708,6 +37849,53 @@ async function runFileboxSetVersionFileStatus(cfg) {
|
|
|
37708
37849
|
);
|
|
37709
37850
|
}
|
|
37710
37851
|
}
|
|
37852
|
+
const dateBefore = target.date_tag_value;
|
|
37853
|
+
const dateMoved = (v) => v !== null && typeof dateBefore === "number" && v.row.date_tag_value !== void 0 && v.row.date_tag_value !== dateBefore;
|
|
37854
|
+
let dateUnknown = false;
|
|
37855
|
+
if (dateMoved(seen)) {
|
|
37856
|
+
err.write(
|
|
37857
|
+
`warning: date_tag_value on version ${cfg.versionId} changed (${JSON.stringify(dateBefore)} -> ${JSON.stringify(seen.row.date_tag_value ?? null)}) when its File Status was set; re-applying the full tag set once
|
|
37858
|
+
`
|
|
37859
|
+
);
|
|
37860
|
+
reapplied = true;
|
|
37861
|
+
refreshBase(seen);
|
|
37862
|
+
let refused = false;
|
|
37863
|
+
try {
|
|
37864
|
+
await write();
|
|
37865
|
+
} catch (e) {
|
|
37866
|
+
if (cfg.signal.aborted) {
|
|
37867
|
+
throw e;
|
|
37868
|
+
}
|
|
37869
|
+
if (e instanceof TagWriteRefusedError) {
|
|
37870
|
+
refused = true;
|
|
37871
|
+
err.write(`warning: re-applying the full tag set was refused ${e.reason}
|
|
37872
|
+
`);
|
|
37873
|
+
} else {
|
|
37874
|
+
err.write(
|
|
37875
|
+
`warning: re-applying the full tag set failed (${e instanceof Error ? e.message : String(e)}); its outcome is unknown, reading the version again
|
|
37876
|
+
`
|
|
37877
|
+
);
|
|
37878
|
+
}
|
|
37879
|
+
}
|
|
37880
|
+
const after = refused ? seen : await readBack();
|
|
37881
|
+
if (after === null) {
|
|
37882
|
+
dateUnknown = true;
|
|
37883
|
+
err.write(
|
|
37884
|
+
`warning: could not read version ${cfg.versionId} back to confirm its date_tag_value after re-applying the full tag set \u2014 check it with \`dr filebox versions ${cfg.docId} --json\`
|
|
37885
|
+
`
|
|
37886
|
+
);
|
|
37887
|
+
} else {
|
|
37888
|
+
seen = after;
|
|
37889
|
+
}
|
|
37890
|
+
}
|
|
37891
|
+
const dateAfter = dateUnknown || seen === null || seen.row.date_tag_value === void 0 ? null : seen.row.date_tag_value;
|
|
37892
|
+
const datePreserved = dateUnknown || seen === null || dateBefore === void 0 || seen.row.date_tag_value === void 0 ? null : !dateMoved(seen);
|
|
37893
|
+
if (datePreserved === false) {
|
|
37894
|
+
err.write(
|
|
37895
|
+
`warning: date_tag_value on version ${cfg.versionId} is still ${JSON.stringify(dateAfter)} (was ${JSON.stringify(dateBefore)}) after one re-apply; its tags still carry the date. Restore it with \`dr filebox set-version-date-tag ${cfg.versionId} --doc ${cfg.docId} --<dimension> <date>\` (it sends the date tag alone; on a planning filebox use \`dr filebox set-version-cycle ${cfg.versionId} --doc ${cfg.docId} --date <date> --scenario <name>\` instead, which keeps the cycle), then check \`dr filebox versions ${cfg.docId} --json\`
|
|
37896
|
+
`
|
|
37897
|
+
);
|
|
37898
|
+
}
|
|
37711
37899
|
if (seen === null) {
|
|
37712
37900
|
err.write(
|
|
37713
37901
|
`warning: could not read version ${cfg.versionId} back to verify its File Status \u2014 confirm with \`dr filebox versions ${cfg.docId}\`
|
|
@@ -37733,6 +37921,8 @@ async function runFileboxSetVersionFileStatus(cfg) {
|
|
|
37733
37921
|
changed: true,
|
|
37734
37922
|
verified,
|
|
37735
37923
|
reapplied,
|
|
37924
|
+
date_tag_value: dateAfter,
|
|
37925
|
+
date_tag_value_preserved: datePreserved,
|
|
37736
37926
|
demoted_version_ids: demotedIds,
|
|
37737
37927
|
rescan_queued: true
|
|
37738
37928
|
});
|
|
@@ -37743,6 +37933,12 @@ async function runFileboxSetVersionFileStatus(cfg) {
|
|
|
37743
37933
|
`Set File Status on version ${cfg.versionId}: ${JSON.stringify(previous ?? "(unset)")} -> "${cfg.status}" (${verdict}).
|
|
37744
37934
|
`
|
|
37745
37935
|
);
|
|
37936
|
+
if (datePreserved === false) {
|
|
37937
|
+
cfg.out.write(
|
|
37938
|
+
`date_tag_value NOT preserved: it reads ${JSON.stringify(dateAfter)}, was ${JSON.stringify(dateBefore)} (see the warning above).
|
|
37939
|
+
`
|
|
37940
|
+
);
|
|
37941
|
+
}
|
|
37746
37942
|
if (demotedIds.length > 0) {
|
|
37747
37943
|
cfg.out.write(
|
|
37748
37944
|
`Only one version per period can be ${cfg.status}: ${plural2(demotedIds.length, "version", "versions")} ${demotedIds.join(", ")} ${plural2(demotedIds.length, "was", "were")} moved to Draft by the server.
|
|
@@ -56539,7 +56735,7 @@ async function readHiddenRulesPayload(path12) {
|
|
|
56539
56735
|
raw.forEach((entry, idx) => {
|
|
56540
56736
|
const ctx = `rules[${idx}]`;
|
|
56541
56737
|
const base = validateCreate(entry, ctx);
|
|
56542
|
-
if (!
|
|
56738
|
+
if (!isPlainObject3(entry)) {
|
|
56543
56739
|
throw new Error(`--file: ${ctx} must be a JSON object`);
|
|
56544
56740
|
}
|
|
56545
56741
|
const ctxnId = entry["customer_transaction_id"];
|
|
@@ -56598,11 +56794,11 @@ function parseReorderShorthand(raw) {
|
|
|
56598
56794
|
}
|
|
56599
56795
|
return { rules: entries };
|
|
56600
56796
|
}
|
|
56601
|
-
function
|
|
56797
|
+
function isPlainObject3(v) {
|
|
56602
56798
|
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
56603
56799
|
}
|
|
56604
56800
|
function validateCreate(raw, ctx) {
|
|
56605
|
-
if (!
|
|
56801
|
+
if (!isPlainObject3(raw)) {
|
|
56606
56802
|
throw new Error(`--file: ${ctx} must be a JSON object`);
|
|
56607
56803
|
}
|
|
56608
56804
|
if (!Array.isArray(raw["conditions"]) || raw["conditions"].length === 0) {
|
|
@@ -56658,7 +56854,7 @@ function validateCreate(raw, ctx) {
|
|
|
56658
56854
|
return out;
|
|
56659
56855
|
}
|
|
56660
56856
|
function validateCondition(raw, ctx) {
|
|
56661
|
-
if (!
|
|
56857
|
+
if (!isPlainObject3(raw)) {
|
|
56662
56858
|
throw new Error(`--file: ${ctx} must be a JSON object`);
|
|
56663
56859
|
}
|
|
56664
56860
|
const inputField = raw["input_field"];
|
|
@@ -56723,7 +56919,7 @@ function validateArgsForOperation(op, args, ctx) {
|
|
|
56723
56919
|
}
|
|
56724
56920
|
}
|
|
56725
56921
|
function validateReorder(raw, ctx) {
|
|
56726
|
-
if (!
|
|
56922
|
+
if (!isPlainObject3(raw)) {
|
|
56727
56923
|
throw new Error(`--file: ${ctx} must be a JSON object`);
|
|
56728
56924
|
}
|
|
56729
56925
|
if (!Array.isArray(raw["rules"]) || raw["rules"].length === 0) {
|
|
@@ -56732,7 +56928,7 @@ function validateReorder(raw, ctx) {
|
|
|
56732
56928
|
const seenIds = /* @__PURE__ */ new Set();
|
|
56733
56929
|
const entries = [];
|
|
56734
56930
|
raw["rules"].forEach((entry, idx) => {
|
|
56735
|
-
if (!
|
|
56931
|
+
if (!isPlainObject3(entry)) {
|
|
56736
56932
|
throw new Error(`--file: ${ctx}.rules[${idx}] must be a JSON object`);
|
|
56737
56933
|
}
|
|
56738
56934
|
const id = entry["id"];
|
package/dist/scopes-map.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
|
-
"cliVersion": "1.6.
|
|
3
|
+
"cliVersion": "1.6.122",
|
|
4
4
|
"_contract": "Resolve a command path through `aliases` (canonical prefix + alias segment -> canonical path) before any lookup. A path listed in `pendingCommands`, or whose first segment is a key of `pending`, is UNDECIDED, not unrestricted: fail closed or skip it, and never read a path's absence from `commands` as 'no requirement'. An entry carrying `denied` is UNAVAILABLE to any AGENT-SCOPED credential — one whose `scopes` claim carries at least one `resource:action` entry; a claim that is absent, empty, capability-only or wholly unparseable is UNRESTRICTED, and this mark does not apply to it — whatever else that entry says: it is not a ceiling and it is not always-available, its `denied.reason` says why and `denied.until` names the ticket that lifts it, and the absence of `requires` on it must NEVER be read as 'no requirement'. Only an entry in `commands` with an empty `requires` means always-available.",
|
|
5
5
|
"commands": {
|
|
6
6
|
"login": {
|
|
@@ -26,7 +26,8 @@ the matching subcommand. `datamappers create <flat|dimension|multiple|from-file>
|
|
|
26
26
|
`--version` — `--version` is reserved by the global `dr --version` and silently
|
|
27
27
|
no-ops the subcommand.
|
|
28
28
|
- `dimension` adds required `--dim Coord=Label` (≥1).
|
|
29
|
-
- `multiple` adds required `--dim` and `--table-id-cell Coord=Label` (
|
|
29
|
+
- `multiple` adds required `--dim` and one `--table-id-cell Coord=Label` (the
|
|
30
|
+
server allows a single table anchor; a second one is refused).
|
|
30
31
|
- `from-file --file <path>` is the power mode — it ships the JSON body without
|
|
31
32
|
the convenience-flag validation, but **not** strictly verbatim. Three things
|
|
32
33
|
still rewrite it: `--rescan`/`--no-rescan` set or strip `rescan`; a source
|
|
@@ -35,6 +36,27 @@ the matching subcommand. `datamappers create <flat|dimension|multiple|from-file>
|
|
|
35
36
|
Required body fields: `name`, `document_version_id`, `selected_document_ids`
|
|
36
37
|
(GET returns this renamed as `mapped_documents_ids`), `config`, `sheet_name`.
|
|
37
38
|
|
|
39
|
+
**`config` shape: `table_id` is not the table id (DR-54216).** `config.table_id`
|
|
40
|
+
is the table *anchor*: `[]` for none (what `datamappers get --json` emits), or a
|
|
41
|
+
list with exactly one cell object, e.g.
|
|
42
|
+
`[{"coordinate": "A1", "value": "<text in that cell>", "match_type": "any_text"}]`.
|
|
43
|
+
The table id goes on the command line. The server does not check `config`, so a
|
|
44
|
+
wrong type gets a bare HTTP 500 on create and "Unknown error while processing
|
|
45
|
+
data for preview" on preview, with no field named. `create` (payload-file /
|
|
46
|
+
from-file), `update` and `preview` therefore check these keys before sending and
|
|
47
|
+
fail naming the field:
|
|
48
|
+
|
|
49
|
+
| Key | Must be |
|
|
50
|
+
|-----|---------|
|
|
51
|
+
| `table_id` | array of at most one object, with a `match_type` string |
|
|
52
|
+
| `header`, `dimension`, `footer`, `attributes` | array of cell objects |
|
|
53
|
+
| `calculated_fields`, `fx_conversions` | array of objects |
|
|
54
|
+
| `include_sheets` | array |
|
|
55
|
+
|
|
56
|
+
An absent key is fine; `null`, a number, a string or a list of strings is not.
|
|
57
|
+
Writing a body from scratch, start from `datamappers get <mapper_id> --json` of a
|
|
58
|
+
similar mapper.
|
|
59
|
+
|
|
38
60
|
**Ordinal: mappers that share one are versions of one mapper.** Each mapper has
|
|
39
61
|
an `ordinal` (the ORDINAL column of `datamappers list --table <id>`). The server
|
|
40
62
|
binds documents per (table, ordinal): binding a mapper to a document moves that
|
|
@@ -154,7 +154,11 @@ set-version-include` (below).
|
|
|
154
154
|
|
|
155
155
|
- `filebox set-version-date-tag <vid> --doc <id> --month|--quarter|--day|--year|--week …
|
|
156
156
|
[--json]` — set the date tag on one version (resolves the tag id from the doc's
|
|
157
|
-
config; other tags untouched).
|
|
157
|
+
config; other tags untouched in `tags`). It sends the date tag alone, and the
|
|
158
|
+
server rebuilds the version's dimension value from the submitted tags, so on
|
|
159
|
+
a filebox with a second dimension tag (a cycle or plan LIST tag) that tag
|
|
160
|
+
drops out of the dimension. On a planning filebox use `set-version-cycle`,
|
|
161
|
+
which sends the date and the cycle together.
|
|
158
162
|
- `filebox set-version-label <vid> --label "<text>" | --clear [--json]` — set or
|
|
159
163
|
remove a version's free-text label; name, date and dimension tags are
|
|
160
164
|
untouched, and a locked date tag does not block it. No confirm step. Address it
|
|
@@ -176,6 +180,27 @@ set-version-include` (below).
|
|
|
176
180
|
moves that version to Draft (the output names it). The status is read back and
|
|
177
181
|
re-applied once if it did not stick. The write queues a rescan of the version,
|
|
178
182
|
so mapped tables show the new `File Status` only after it finishes.
|
|
183
|
+
Like the UI, it sends the version's **full tag set** with File Status
|
|
184
|
+
replaced, not File Status alone. The server merges the submitted tags into
|
|
185
|
+
`tags` but rebuilds the version's dimension value, and with it the
|
|
186
|
+
`date_tag_value` that `filebox versions --json` shows, from the submitted tags
|
|
187
|
+
only. A File Status-only body (CLI releases before DR-54157) therefore left
|
|
188
|
+
`date_tag_value` null while `tags` still held the month. That is not harmless:
|
|
189
|
+
the server uses the dimension value to pick the latest version per period, to
|
|
190
|
+
apply date locks and in rescan events. The command reads `date_tag_value` back,
|
|
191
|
+
re-applies the full set once if it changed, and otherwise reports it: a stderr
|
|
192
|
+
warning, a `date_tag_value NOT preserved` line, and
|
|
193
|
+
`date_tag_value_preserved: false` in `--json`. `--json` also returns
|
|
194
|
+
`date_tag_value`, and `date_tag_value_preserved: null` when the server does
|
|
195
|
+
not serve it. **To repair a version left with a null date**, run
|
|
196
|
+
`set-version-date-tag` with the period its `tags` hold. That writes the date
|
|
197
|
+
tag, and the server rebuilds the dimension from it. It sends the date tag
|
|
198
|
+
alone, so use it only when the date is the filebox's only dimension tag. On a
|
|
199
|
+
planning filebox, run `set-version-cycle` with the version's existing date
|
|
200
|
+
and scenario instead, which sends both. Re-running
|
|
201
|
+
`set-version-file-status` with the same status does not repair it, because
|
|
202
|
+
it writes nothing. A real status change does restore it, because it re-sends
|
|
203
|
+
the date tag.
|
|
179
204
|
- `filebox set-version-cycle <vid> --doc <id> --date <date> --scenario <name>
|
|
180
205
|
[--date-tag-name <n>] [--json]` — **forecast/budget (planning) fileboxes only.**
|
|
181
206
|
Sets the cycle date tag and the scenario LIST-tag together (both flags
|