@datarails-ai/dr-appspace-cli 0.12.34 → 0.12.36
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 +67 -8
- 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.12.
|
|
16
|
+
version: "0.12.36",
|
|
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-26T13:45:46.965Z";
|
|
61
61
|
function formatBuildTime(iso) {
|
|
62
62
|
if (iso === "") return "";
|
|
63
63
|
const d = new Date(iso);
|
|
@@ -5961,6 +5961,11 @@ function readPage(app, page, spec, elements, problems) {
|
|
|
5961
5961
|
well_formed: tree.well_formed,
|
|
5962
5962
|
tree: [],
|
|
5963
5963
|
owned: true,
|
|
5964
|
+
// A page `app-space eject page:` made owned still embeds the contract
|
|
5965
|
+
// it was compiled from, and the runtime's param store reads the
|
|
5966
|
+
// page's params from there, as it does on a compiled page. A page
|
|
5967
|
+
// written by hand with no embedded contract says nothing, as before.
|
|
5968
|
+
...paramsOf(page),
|
|
5964
5969
|
...pageRolesOf(app.manifest, page.path)
|
|
5965
5970
|
},
|
|
5966
5971
|
pins: pinsOf(page, tree)
|
|
@@ -10517,7 +10522,7 @@ function compile(contract, { kit, extra = {} } = {}) {
|
|
|
10517
10522
|
for (const page of pages) {
|
|
10518
10523
|
files[page.path] = pageFile(page, { contract: composed, pages, kit, problems });
|
|
10519
10524
|
}
|
|
10520
|
-
return { files, problems: problems.sort(byProblem2) };
|
|
10525
|
+
return { files, problems: problems.sort(byProblem2), warnings: narrativeOrderWarnings(composed, applied) };
|
|
10521
10526
|
}
|
|
10522
10527
|
var RUNTIME_RENDERER2 = "runtime";
|
|
10523
10528
|
function dashboardHandler(composed, handlerName, extra = {}) {
|
|
@@ -10593,6 +10598,43 @@ function missingExpressions(widgets) {
|
|
|
10593
10598
|
}
|
|
10594
10599
|
return problems;
|
|
10595
10600
|
}
|
|
10601
|
+
function narrativeOrderWarnings(composed, applied) {
|
|
10602
|
+
const picked = new Set(applied.filter((fill) => fill.what === "layout.order").map((fill) => fill.where));
|
|
10603
|
+
const elements = isPlainObject6(composed?.elements) ? composed.elements : {};
|
|
10604
|
+
const widgets = isPlainObject6(composed?.data?.widgets) ? composed.data.widgets : {};
|
|
10605
|
+
const pages = [...Array.isArray(composed?.pages) ? composed.pages : []].sort((a, b) => natural3(a.path ?? "", b.path ?? ""));
|
|
10606
|
+
const named13 = (value) => typeof value === "string" && value !== "";
|
|
10607
|
+
const quoted3 = (ids) => ids.map((id) => JSON.stringify(id)).join(", ");
|
|
10608
|
+
const warnings = [];
|
|
10609
|
+
for (const page of pages) {
|
|
10610
|
+
if (picked.has(page.path)) continue;
|
|
10611
|
+
const sections = Array.isArray(page.sections) ? page.sections : [];
|
|
10612
|
+
const sectionOf4 = (uid) => sections.findIndex((entry) => isPlainObject6(entry) && entry.id === elements[uid].section);
|
|
10613
|
+
const cards = Object.keys(elements).filter((uid) => elements[uid]?.page === page.path && elements[uid]?.type === "widget").sort((a, b) => sectionOf4(a) - sectionOf4(b) || order(elements[a]) - order(elements[b]) || natural3(a, b));
|
|
10614
|
+
const specOf2 = (uid) => {
|
|
10615
|
+
const element = elements[uid];
|
|
10616
|
+
const props = isPlainObject6(element.props) ? element.props : {};
|
|
10617
|
+
return named13(element.id) ? element.id : named13(props.card) ? props.card : named13(props.id) ? props.id : uid;
|
|
10618
|
+
};
|
|
10619
|
+
cards.forEach((uid, at) => {
|
|
10620
|
+
const own2 = specOf2(uid);
|
|
10621
|
+
const row = widgets[own2];
|
|
10622
|
+
const about = isPlainObject6(row) && row.kind === "narrative" && Array.isArray(row.about) ? row.about.filter((id) => named13(id) && id !== own2) : [];
|
|
10623
|
+
if (about.length === 0) return;
|
|
10624
|
+
const after = cards.slice(at + 1).filter((other) => sectionOf4(other) === sectionOf4(uid) && about.includes(specOf2(other)));
|
|
10625
|
+
if (after.length === 0) return;
|
|
10626
|
+
const later = [...new Set(after.map(specOf2))];
|
|
10627
|
+
const last = specOf2(after[after.length - 1]);
|
|
10628
|
+
const where2 = sectionOf4(uid) === -1 ? page.path : `section "${sections[sectionOf4(uid)].id}" of ${page.path}`;
|
|
10629
|
+
warnings.push({
|
|
10630
|
+
code: "narrative_before_about",
|
|
10631
|
+
pointer: `/elements/${escapePointer3(uid)}/order`,
|
|
10632
|
+
message: `narrative "${own2}" comes before ${quoted3(later)}, ${later.length === 1 ? "a card" : "cards"} it is about, on ${where2}: it reads the cards it is about as it loads, so its context gives ${quoted3(later)} as "(not loaded yet)". The page keeps the order you stated; move "${own2}" after "${last}"`
|
|
10633
|
+
});
|
|
10634
|
+
});
|
|
10635
|
+
}
|
|
10636
|
+
return warnings;
|
|
10637
|
+
}
|
|
10596
10638
|
var DEFAULT_CAPABILITIES = { financeos: ["metrics:read", "raw:read"] };
|
|
10597
10639
|
function manifestFile(contract, handlerName) {
|
|
10598
10640
|
const app = contract.app ?? {};
|
|
@@ -11073,7 +11115,7 @@ function compileDashboard(contract, { kit = null, extra = {}, uiKit, charts, fmt
|
|
|
11073
11115
|
files[handlerPath(composed, handlerName)] = handler.text;
|
|
11074
11116
|
const shelf2 = { runtime: DASHBOARD_RUNTIME, widgets: DASHBOARD_WIDGETS, bar: DASHBOARD_BAR, assistant, markdown, uiKit, charts, fmt, appComponents, appControls };
|
|
11075
11117
|
for (const page of whole.pages) files[page.path] = pageHtml(whole, page, elements, tree, shelf2);
|
|
11076
|
-
return { files, problems, contract: whole, order: order2, warnings:
|
|
11118
|
+
return { files, problems, contract: whole, order: order2, warnings: narrativeOrderWarnings(composed, applied) };
|
|
11077
11119
|
}
|
|
11078
11120
|
function isRefusal(problem5) {
|
|
11079
11121
|
return problem5.lossy !== false;
|
|
@@ -24755,6 +24797,11 @@ function readPage2(app, page, spec, elements, problems) {
|
|
|
24755
24797
|
well_formed: tree.well_formed,
|
|
24756
24798
|
tree: [],
|
|
24757
24799
|
owned: true,
|
|
24800
|
+
// A page `app-space eject page:` made owned still embeds the contract
|
|
24801
|
+
// it was compiled from, and the runtime's param store reads the
|
|
24802
|
+
// page's params from there, as it does on a compiled page. A page
|
|
24803
|
+
// written by hand with no embedded contract says nothing, as before.
|
|
24804
|
+
...paramsOf2(page),
|
|
24758
24805
|
...pageRolesOf2(app.manifest, page.path)
|
|
24759
24806
|
},
|
|
24760
24807
|
pins: pinsOf2(page, tree)
|
|
@@ -30581,21 +30628,32 @@ async function ejectPage(dir, contract, path3) {
|
|
|
30581
30628
|
element["children"] = element["children"].filter((uid) => !gone.has(String(uid)));
|
|
30582
30629
|
}
|
|
30583
30630
|
const kept = {};
|
|
30584
|
-
for (const key of ["path", "route", "title"]) if (page[key] !== void 0) kept[key] = page[key];
|
|
30631
|
+
for (const key of ["path", "route", "title", "params", "roles"]) if (page[key] !== void 0) kept[key] = page[key];
|
|
30585
30632
|
kept["owned"] = true;
|
|
30586
|
-
if (gate !== null) kept["role"] = gate;
|
|
30633
|
+
if (gate !== null && kept["roles"] === void 0) kept["role"] = gate;
|
|
30587
30634
|
pages[index] = kept;
|
|
30588
30635
|
const app = obj3(obj3(contract["data"])["app"]);
|
|
30589
30636
|
if (Array.isArray(app["screens"])) {
|
|
30590
30637
|
app["screens"] = app["screens"].filter((screen) => !(isPlain2(screen) && screen["page"] === path3));
|
|
30591
30638
|
}
|
|
30592
|
-
const
|
|
30639
|
+
const sources = Object.keys(obj3(obj3(contract["data"])["sources"]));
|
|
30640
|
+
const served = sources.filter((name) => files[`handlers/${name}.py`] !== void 0);
|
|
30641
|
+
const wrote = await commit(dir, contract, path3, marked2, (after) => {
|
|
30642
|
+
const lost = served.filter((name) => after[`handlers/${name}.py`] === void 0).sort();
|
|
30643
|
+
if (lost.length > 0) throw new Refused(unservedAfter(path3, lost));
|
|
30644
|
+
});
|
|
30593
30645
|
return {
|
|
30594
30646
|
target: `page:${path3}`,
|
|
30595
30647
|
wrote,
|
|
30596
30648
|
said: `page ${path3} is yours now: owned, and its ${String(gone.size)} element${gone.size === 1 ? "" : "s"} left the contract.`
|
|
30597
30649
|
};
|
|
30598
30650
|
}
|
|
30651
|
+
function unservedAfter(path3, lost) {
|
|
30652
|
+
const one = lost.length === 1;
|
|
30653
|
+
const names = lost.map((name) => JSON.stringify(name)).join(", ");
|
|
30654
|
+
const files = lost.map((name) => `handlers/${name}.py`).join(", ");
|
|
30655
|
+
return `${path3} is the only page whose cards read source${one ? "" : "s"} ${names}. Owned, the page has no elements in the contract, and the compiler writes a handler only for a source some element reads, so ${files} would go and the page would call ${one ? "a handler" : "handlers"} that ${one ? "is" : "are"} not there. Keep a card that reads ${one ? "it" : "each"} on a compiled page, or eject ${one ? "the source" : "each source"} first (app-space eject ${lost.map((name) => `source:${name}`).join(", ")}), which makes it a custom handler the compiler always carries, where that eject is allowed: eject source: says when it is not.`;
|
|
30656
|
+
}
|
|
30599
30657
|
function navGateOf(files, path3) {
|
|
30600
30658
|
const gates = navGates;
|
|
30601
30659
|
for (const [file, text3] of Object.entries(files)) {
|
|
@@ -30727,7 +30785,7 @@ async function mayPlace(dir, path3, text3, same5) {
|
|
|
30727
30785
|
`${path3} already holds something other than what eject would write there. It is yours: move it aside first, or keep it and edit contract.json by hand.`
|
|
30728
30786
|
);
|
|
30729
30787
|
}
|
|
30730
|
-
async function commit(dir, contract, path3, text3) {
|
|
30788
|
+
async function commit(dir, contract, path3, text3, check5) {
|
|
30731
30789
|
const invalid = validateContract(contract, NO_CATALOG).problems;
|
|
30732
30790
|
if (invalid.length > 0) {
|
|
30733
30791
|
throw new Refused(`after this eject contract.json would not validate, so eject leaves the folder as it was:
|
|
@@ -30745,6 +30803,7 @@ ${formatProblems(invalid)}`);
|
|
|
30745
30803
|
${lines}
|
|
30746
30804
|
`);
|
|
30747
30805
|
}
|
|
30806
|
+
check5?.(built.files);
|
|
30748
30807
|
const full = join16(dir, path3);
|
|
30749
30808
|
const wrote = await readIfPresent(full) === text3 ? [] : [path3];
|
|
30750
30809
|
if (wrote.length > 0) {
|