@datarails-ai/dr-appspace-cli 0.10.13 → 0.10.14
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 +100 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -13,7 +13,7 @@ import { fileURLToPath as fileURLToPath6 } from "url";
|
|
|
13
13
|
// package.json
|
|
14
14
|
var package_default = {
|
|
15
15
|
name: "@datarails-ai/dr-appspace-cli",
|
|
16
|
-
version: "0.10.
|
|
16
|
+
version: "0.10.14",
|
|
17
17
|
description: "Datarails App Space CLI \u2014 build, try, push and publish App Space apps",
|
|
18
18
|
type: "module",
|
|
19
19
|
engines: {
|
|
@@ -57,7 +57,7 @@ var package_default = {
|
|
|
57
57
|
};
|
|
58
58
|
|
|
59
59
|
// src/buildInfo.ts
|
|
60
|
-
var BUILD_TIME = "2026-10-
|
|
60
|
+
var BUILD_TIME = "2026-10-01T09:25:02.651Z";
|
|
61
61
|
function formatBuildTime(iso) {
|
|
62
62
|
if (iso === "") return "";
|
|
63
63
|
const d = new Date(iso);
|
|
@@ -14566,6 +14566,92 @@ function originOf(row) {
|
|
|
14566
14566
|
function sourcesOf(contract) {
|
|
14567
14567
|
return isPlainObject7(contract?.data?.sources) ? contract.data.sources : {};
|
|
14568
14568
|
}
|
|
14569
|
+
var FINANCEOS_SCOPES = {
|
|
14570
|
+
commands: {
|
|
14571
|
+
"status:read": ["status", "whoami"],
|
|
14572
|
+
"tables:read": ["list_tables", "get_table"],
|
|
14573
|
+
"semantic:read": ["list_semantic_tables", "get_semantic_table", "metric_series"],
|
|
14574
|
+
"metrics:read": ["list_metrics", "get_metric", "metric_series"],
|
|
14575
|
+
"filebox:read": ["list_filebox"],
|
|
14576
|
+
"users:read": ["list_users"],
|
|
14577
|
+
"pipeline:read": ["data_readiness"],
|
|
14578
|
+
"raw:read": ["get_raw_table", "get_raw_table_data", "get_aliased_table_data"]
|
|
14579
|
+
},
|
|
14580
|
+
namespaces: {
|
|
14581
|
+
"status:read": ["status"],
|
|
14582
|
+
"tables:read": ["tables"],
|
|
14583
|
+
"semantic:read": ["semantic_tables"],
|
|
14584
|
+
"metrics:read": ["metrics", "data_models"],
|
|
14585
|
+
"filebox:read": ["filebox"]
|
|
14586
|
+
},
|
|
14587
|
+
gated: {
|
|
14588
|
+
get_raw_table: "raw:read",
|
|
14589
|
+
get_raw_table_data: "raw:read",
|
|
14590
|
+
get_aliased_table_data: "raw:read"
|
|
14591
|
+
}
|
|
14592
|
+
};
|
|
14593
|
+
function scopesGranting(kind, name) {
|
|
14594
|
+
return Object.keys(FINANCEOS_SCOPES[kind]).filter((scope) => FINANCEOS_SCOPES[kind][scope].includes(name)).sort();
|
|
14595
|
+
}
|
|
14596
|
+
function financeosNeeds(row, origin) {
|
|
14597
|
+
const needs = [];
|
|
14598
|
+
const need = (reads, anyOf, catalog = false) => {
|
|
14599
|
+
if (anyOf.length > 0 && !needs.some((one) => one.reads === reads && one.catalog === catalog)) needs.push({ reads, anyOf, catalog });
|
|
14600
|
+
};
|
|
14601
|
+
if (origin === "call") {
|
|
14602
|
+
const parts = typeof row.from.call === "string" ? row.from.call.split(".") : [];
|
|
14603
|
+
if (parts.length === 1) need(parts[0], scopesGranting("commands", parts[0]));
|
|
14604
|
+
if (parts.length === 2) {
|
|
14605
|
+
need(parts[0], scopesGranting("namespaces", parts[0]));
|
|
14606
|
+
const gated = FINANCEOS_SCOPES.gated[parts[1]];
|
|
14607
|
+
if (gated) need(`${parts[0]}.${parts[1]}`, [gated]);
|
|
14608
|
+
}
|
|
14609
|
+
return needs;
|
|
14610
|
+
}
|
|
14611
|
+
const read = isPlainObject7(row.from.financeos) ? row.from.financeos : {};
|
|
14612
|
+
const filterable = Array.isArray(row.filterable) && row.filterable.length > 0;
|
|
14613
|
+
if (read.metric_id !== void 0 && read.metric_id !== null) {
|
|
14614
|
+
if (read.drill_rows) need("data_models", scopesGranting("namespaces", "data_models"));
|
|
14615
|
+
else need("metric_series", scopesGranting("commands", "metric_series"));
|
|
14616
|
+
if (filterable) need("data_models", scopesGranting("namespaces", "data_models"), true);
|
|
14617
|
+
return needs;
|
|
14618
|
+
}
|
|
14619
|
+
const address = read.address === "id" || read.address === "alias" ? read.address : read.table_alias ? "alias" : read.table_id !== void 0 && read.table_id !== null ? "id" : null;
|
|
14620
|
+
if (address === null) return needs;
|
|
14621
|
+
const raw = read.rows === "raw" || row.shape === "ohlc";
|
|
14622
|
+
if (address === "id") need("get_raw_table", scopesGranting("commands", "get_raw_table"));
|
|
14623
|
+
if (raw) {
|
|
14624
|
+
const page = address === "id" ? "get_raw_table_data" : "get_aliased_table_data";
|
|
14625
|
+
need(page, scopesGranting("commands", page));
|
|
14626
|
+
} else {
|
|
14627
|
+
need("data_models", scopesGranting("namespaces", "data_models"));
|
|
14628
|
+
}
|
|
14629
|
+
if (filterable) need("data_models", scopesGranting("namespaces", "data_models"), true);
|
|
14630
|
+
return needs;
|
|
14631
|
+
}
|
|
14632
|
+
function financeosScopeProblems(name, row, origin, declared) {
|
|
14633
|
+
const missing = /* @__PURE__ */ new Map();
|
|
14634
|
+
for (const { reads, anyOf, catalog } of financeosNeeds(row, origin)) {
|
|
14635
|
+
if (anyOf.some((scope2) => declared.includes(scope2))) continue;
|
|
14636
|
+
const scope = anyOf.includes("metrics:read") ? "metrics:read" : anyOf[0];
|
|
14637
|
+
const entry = missing.get(scope) ?? { scope, anyOf, reads: [], catalog: true };
|
|
14638
|
+
if (!entry.reads.includes(reads)) entry.reads.push(reads);
|
|
14639
|
+
entry.catalog = entry.catalog && catalog;
|
|
14640
|
+
missing.set(scope, entry);
|
|
14641
|
+
}
|
|
14642
|
+
return [...missing.values()].map(
|
|
14643
|
+
({ scope, anyOf, reads, catalog }) => catalog ? {
|
|
14644
|
+
code: "financeos_scope_catalog",
|
|
14645
|
+
pointer: `/data/sources/${escapePointer3(name)}/filterable`,
|
|
14646
|
+
message: `source "${name}" offers filterable values, which the filter bar reads from ${reads.join(" and ")} with financeos scope ${anyOf.join(" or ")}; the source loads without it, but its filter bar offers no values until you add ${JSON.stringify(scope)} to app.capabilities.financeos`,
|
|
14647
|
+
advisory: true
|
|
14648
|
+
} : {
|
|
14649
|
+
code: "financeos_scope",
|
|
14650
|
+
pointer: "/app/capabilities/financeos",
|
|
14651
|
+
message: `source "${name}" reads ${reads.join(" and ")}, which needs financeos scope ${anyOf.join(" or ")}; add ${JSON.stringify(scope)} to app.capabilities.financeos`
|
|
14652
|
+
}
|
|
14653
|
+
);
|
|
14654
|
+
}
|
|
14569
14655
|
function servedSources(elements, sources) {
|
|
14570
14656
|
const out = /* @__PURE__ */ new Set();
|
|
14571
14657
|
for (const element of Object.values(elements)) {
|
|
@@ -14606,6 +14692,8 @@ function sourceProblems(sources, app, handlers, extra) {
|
|
|
14606
14692
|
pointer: "/app/capabilities/financeos",
|
|
14607
14693
|
message: `source "${name}" reads FinanceOS, and this app grants no financeos capability; grant at least one read scope (e.g. metrics:read, plus raw:read to read a table by id)`
|
|
14608
14694
|
});
|
|
14695
|
+
} else if (origin === "financeos" || origin === "call") {
|
|
14696
|
+
problems.push(...financeosScopeProblems(name, row, origin, financeos));
|
|
14609
14697
|
}
|
|
14610
14698
|
if (origin === "depends") {
|
|
14611
14699
|
for (const [index, dep] of row.from.entries()) {
|
|
@@ -15124,7 +15212,8 @@ function compileApp(contract, { kit = null, runtime = RUNTIME, extra = {} } = {}
|
|
|
15124
15212
|
const handlers = isPlainObject7(contract.data?.app?.handlers) ? contract.data.app.handlers : {};
|
|
15125
15213
|
const names = Object.keys(handlers).sort(natural3);
|
|
15126
15214
|
const stated2 = sourcesOf(contract);
|
|
15127
|
-
|
|
15215
|
+
const sourceFindings = sourceProblems(stated2, app, handlers, extra);
|
|
15216
|
+
problems.push(...sourceFindings.filter((one) => !one.advisory));
|
|
15128
15217
|
problems.push(...compareProblems(stated2, model));
|
|
15129
15218
|
problems.push(...paramProblems(contract, stated2));
|
|
15130
15219
|
problems.push(...themeProblems(app));
|
|
@@ -15208,7 +15297,7 @@ function compileApp(contract, { kit = null, runtime = RUNTIME, extra = {} } = {}
|
|
|
15208
15297
|
problems.push(...numberPinProblems(declared, { "dr-app-runtime": runtime, "dr-app-widgets": appWidgets, "dr-components": appComponents, "dr-components-controls": appControls }));
|
|
15209
15298
|
problems.push(...whenPinProblems(declared, { "dr-components": appComponents }));
|
|
15210
15299
|
const widgetFindings = tree.problems.length === 0 ? widgetProblems(declared, tree, handlers, contract?.data?.sources, appWidgets) : [];
|
|
15211
|
-
const warnings = widgetFindings.filter((one) => one.advisory).map(({ advisory: _advisory, ...one }) => one);
|
|
15300
|
+
const warnings = [...sourceFindings, ...widgetFindings].filter((one) => one.advisory).map(({ advisory: _advisory, ...one }) => one);
|
|
15212
15301
|
problems.push(...widgetFindings.filter((one) => !one.advisory));
|
|
15213
15302
|
if (tree.problems.length === 0) problems.push(...partProblems(declared, tree, handlers, sources, contract?.pages, model));
|
|
15214
15303
|
if (problems.length > 0) return { files: {}, problems, contract, warnings };
|
|
@@ -24469,6 +24558,8 @@ var REFUSALS = /* @__PURE__ */ new Set([
|
|
|
24469
24558
|
"source_unknown",
|
|
24470
24559
|
"source_name_taken",
|
|
24471
24560
|
"source_needs_financeos",
|
|
24561
|
+
// a source the declared financeos scopes do not reach (conversation 34b3d658)
|
|
24562
|
+
"financeos_scope",
|
|
24472
24563
|
"transform_missing",
|
|
24473
24564
|
// a dashboard dataset row's own transform (transforms.mjs)
|
|
24474
24565
|
"transform_row",
|
|
@@ -24535,6 +24626,9 @@ var PARAM_REFUSALS = {
|
|
|
24535
24626
|
param_kind_value: "a param's default, min/max/step, values or max_selected is one its kind cannot hold",
|
|
24536
24627
|
param_conflict: "one param name declared twice with different rules (the server keeps the first)"
|
|
24537
24628
|
};
|
|
24629
|
+
var SOURCE_REFUSALS = {
|
|
24630
|
+
financeos_scope: "a FinanceOS source reads a surface app.capabilities.financeos does not grant (a table aggregate or a metric needs metrics:read; a by-id table or raw rows need raw:read; a call needs the scope its command is under) \u2014 add the scope the message names. `filterable` values without metrics:read are only a warning (financeos_scope_catalog): the source loads, its filter bar offers nothing"
|
|
24631
|
+
};
|
|
24538
24632
|
var KPI_REFUSALS = {
|
|
24539
24633
|
source_compare_field: "a source's compare names a field its rows do not carry (where that is knowable: a FinanceOS aggregate's dimensions, measures and period column; an app table's columns), or is set on a source not shaped kpi \u2014 declare the measure beside the figure, or name one it carries"
|
|
24540
24634
|
};
|
|
@@ -25588,6 +25682,8 @@ function registerCompileCommand(parent) {
|
|
|
25588
25682
|
"",
|
|
25589
25683
|
"An app's own header is refused with:",
|
|
25590
25684
|
...Object.entries(APP_REFUSALS).map(([code, what]) => ` ${code.padEnd(22)}${what}`),
|
|
25685
|
+
"A FinanceOS source the declared scopes do not reach is refused with:",
|
|
25686
|
+
...Object.entries(SOURCE_REFUSALS).map(([code, what]) => ` ${code.padEnd(22)}${what}`),
|
|
25591
25687
|
"A KPI source (shape kpi: its period comes from the rows; compare sets the figure against another measure of the same row) is refused with:",
|
|
25592
25688
|
...Object.entries(KPI_REFUSALS).map(([code, what]) => ` ${code.padEnd(22)}${what}`),
|
|
25593
25689
|
"",
|