@datarails-ai/dr-appspace-cli 0.10.5 → 0.10.7
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 +109 -12
- 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.7",
|
|
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-09-
|
|
60
|
+
var BUILD_TIME = "2026-09-30T19:32:36.822Z";
|
|
61
61
|
function formatBuildTime(iso) {
|
|
62
62
|
if (iso === "") return "";
|
|
63
63
|
const d = new Date(iso);
|
|
@@ -2793,10 +2793,53 @@ function conflictTables(body) {
|
|
|
2793
2793
|
const entries = Object.entries(raw).filter((e) => Array.isArray(e[1]) && e[1].length > 0).map(([table, owners]) => [table, owners.map(String)]);
|
|
2794
2794
|
return entries.length === 0 ? void 0 : entries;
|
|
2795
2795
|
}
|
|
2796
|
+
function conflictOwners(body, table) {
|
|
2797
|
+
const owners = (body?.conflicts?.[table] ?? {}).owners;
|
|
2798
|
+
if (!Array.isArray(owners)) return [];
|
|
2799
|
+
return owners.flatMap((o) => {
|
|
2800
|
+
if (typeof o !== "object" || o === null) return [];
|
|
2801
|
+
const r = o;
|
|
2802
|
+
if (typeof r["app_id"] !== "string") return [];
|
|
2803
|
+
const cols = r["columns"];
|
|
2804
|
+
return [
|
|
2805
|
+
{
|
|
2806
|
+
appId: r["app_id"],
|
|
2807
|
+
columns: typeof cols === "object" && cols !== null && !Array.isArray(cols) ? Object.fromEntries(Object.entries(cols).map(([k, v]) => [k, String(v)])) : null,
|
|
2808
|
+
connectProblems: Array.isArray(r["connect_problems"]) ? r["connect_problems"].map(String) : []
|
|
2809
|
+
}
|
|
2810
|
+
];
|
|
2811
|
+
});
|
|
2812
|
+
}
|
|
2813
|
+
function columnsLine(columns) {
|
|
2814
|
+
return Object.entries(columns).map(([n, t]) => `${n} ${t}`).join(", ");
|
|
2815
|
+
}
|
|
2816
|
+
function conflictGuidance(body) {
|
|
2817
|
+
const lines = [];
|
|
2818
|
+
for (const [table, ids] of conflictTables(body) ?? []) {
|
|
2819
|
+
const owners = conflictOwners(body, table);
|
|
2820
|
+
for (const owner of owners.length > 0 ? owners : ids.map((appId) => ({ appId, columns: null, connectProblems: [] }))) {
|
|
2821
|
+
lines.push(
|
|
2822
|
+
`table "${table}" is owned by ${owner.appId}` + (owner.columns === null ? " (its structure could not be read)" : ` with columns: ${columnsLine(owner.columns)}`)
|
|
2823
|
+
);
|
|
2824
|
+
if (owner.connectProblems.length > 0) {
|
|
2825
|
+
lines.push(
|
|
2826
|
+
` as declared, connecting would be refused: ${owner.connectProblems.join("; ")}`,
|
|
2827
|
+
" Match the owner's columns and types exactly (tables share ONE structure: the owner's), or rename yours."
|
|
2828
|
+
);
|
|
2829
|
+
} else if (owners.length > 0) {
|
|
2830
|
+
lines.push(
|
|
2831
|
+
` to share it, add to manifest.json: "connect_tables": ${JSON.stringify({ [table]: owner.appId })}`
|
|
2832
|
+
);
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
return lines;
|
|
2837
|
+
}
|
|
2796
2838
|
function describeFailure(status, method, path3, body) {
|
|
2797
2839
|
const conflicts = conflictTables(body);
|
|
2798
2840
|
if (status === 409 && conflicts !== void 0) {
|
|
2799
|
-
return `${method} ${path3} failed (409) \u2014 ${conflicts.map(([table, owners]) => `table "${table}" already belongs to ${owners.join(", ")}`).join("; ")}. Rename the table in data_model.json, or
|
|
2841
|
+
return `${method} ${path3} failed (409) \u2014 ${conflicts.map(([table, owners]) => `table "${table}" already belongs to ${owners.join(", ")}`).join("; ")}. Rename the table in data_model.json, or share the existing one with \`connect_tables\` in manifest.json.` + conflictGuidance(body).map((l) => `
|
|
2842
|
+
${l}`).join("");
|
|
2800
2843
|
}
|
|
2801
2844
|
const code = body?.detail?.error;
|
|
2802
2845
|
if (status === 403 && code === "studio_not_enabled") {
|
|
@@ -6190,9 +6233,13 @@ var EXPECT_EMPTY = "empty";
|
|
|
6190
6233
|
var EXPECTATIONS = /* @__PURE__ */ new Set([EXPECT_FIGURE, EXPECT_EMPTY]);
|
|
6191
6234
|
var FIGURE = {
|
|
6192
6235
|
series: (body) => Array.isArray(body.series) && body.series.some((entry) => Array.isArray(entry?.values) && entry.values.some(isNumber)),
|
|
6193
|
-
|
|
6236
|
+
// A container of labels with nothing beside them draws no figure either:
|
|
6237
|
+
// seven departments down a variance table with every cell null is the same
|
|
6238
|
+
// blank card as no rows at all (dev-1, 2026-09-30, `actual - budget` where
|
|
6239
|
+
// neither was a measure of the dataset), and it passed here as "rows > 0".
|
|
6240
|
+
breakdown: (body) => Array.isArray(body.items) && body.items.some((item) => isNumber(item?.value)),
|
|
6194
6241
|
kpi: (body) => isNumber(body.value),
|
|
6195
|
-
table: (body) => Array.isArray(body.rows) && body.rows.
|
|
6242
|
+
table: (body) => Array.isArray(body.rows) && body.rows.some((row) => isPlainObject2(row) && Object.values(row).some(isNumber)),
|
|
6196
6243
|
ohlc: (body) => Array.isArray(body.candles) && body.candles.length > 0,
|
|
6197
6244
|
scatter: (body) => Array.isArray(body.points) && body.points.length > 0,
|
|
6198
6245
|
// A narrative in AGENT mode has no prose to carry: the words arrive from the
|
|
@@ -6937,6 +6984,10 @@ async function pushBody(dir, opts) {
|
|
|
6937
6984
|
if (ui?.field === "frontend_bundle_gz") {
|
|
6938
6985
|
body["frontend_bundle_gz"] = ui.files;
|
|
6939
6986
|
}
|
|
6987
|
+
const connectTables = manifest["connect_tables"];
|
|
6988
|
+
if (typeof connectTables === "object" && connectTables !== null && !Array.isArray(connectTables)) {
|
|
6989
|
+
if (Object.keys(connectTables).length > 0) body["connect_tables"] = connectTables;
|
|
6990
|
+
}
|
|
6940
6991
|
if (contract !== null) {
|
|
6941
6992
|
body["contract"] = contract;
|
|
6942
6993
|
}
|
|
@@ -7006,6 +7057,10 @@ async function pushFolder(dir, opts) {
|
|
|
7006
7057
|
}
|
|
7007
7058
|
if (result.stage !== "published") {
|
|
7008
7059
|
process.stdout.write("Only you can see it until an admin publishes it.\n");
|
|
7060
|
+
} else if (opts.publish !== true) {
|
|
7061
|
+
process.stdout.write(
|
|
7062
|
+
"The app was already published: this push changed its working version only; the published one is unchanged until it is published again.\n"
|
|
7063
|
+
);
|
|
7009
7064
|
}
|
|
7010
7065
|
return outcome;
|
|
7011
7066
|
} finally {
|
|
@@ -7142,9 +7197,11 @@ async function writePackage(dir, appId, pkg) {
|
|
|
7142
7197
|
rm2(join10(dir, "handlers"), { recursive: true, force: true }),
|
|
7143
7198
|
rm2(join10(dir, "ui"), { recursive: true, force: true })
|
|
7144
7199
|
]);
|
|
7200
|
+
const connected = pkg.connect_tables ?? {};
|
|
7201
|
+
const manifestOut = Object.keys(connected).length > 0 ? { ...pkg.manifest, connect_tables: connected } : pkg.manifest;
|
|
7145
7202
|
await writeFile5(
|
|
7146
7203
|
join10(dir, "manifest.json"),
|
|
7147
|
-
JSON.stringify(
|
|
7204
|
+
JSON.stringify(manifestOut, null, 2) + "\n"
|
|
7148
7205
|
);
|
|
7149
7206
|
if (pkg.data_model !== null && pkg.data_model !== void 0) {
|
|
7150
7207
|
await writeFile5(
|
|
@@ -10759,12 +10816,19 @@ function fromRefusal(status, detail, contract) {
|
|
|
10759
10816
|
const tables = tablesOf(contract);
|
|
10760
10817
|
const conflicts = conflictTables(detail);
|
|
10761
10818
|
if (conflicts !== void 0) {
|
|
10762
|
-
return conflicts.map(([table, owners]) =>
|
|
10763
|
-
|
|
10764
|
-
|
|
10765
|
-
|
|
10766
|
-
|
|
10767
|
-
|
|
10819
|
+
return conflicts.map(([table, owners]) => {
|
|
10820
|
+
const owned = conflictOwners(detail, table);
|
|
10821
|
+
const detailLines = conflictGuidance({
|
|
10822
|
+
conflict_tables: { [table]: owners },
|
|
10823
|
+
conflicts: detail.conflicts
|
|
10824
|
+
});
|
|
10825
|
+
return {
|
|
10826
|
+
code: "server:table-conflict",
|
|
10827
|
+
pointer: tables.has(table) ? pointer("app", "data_model", "tables", table) : "/",
|
|
10828
|
+
message: `${refused}: table "${table}" already belongs to ${owners.join(", ")}.` + (owned.length > 0 ? ` ${detailLines.join(" ")}` : ""),
|
|
10829
|
+
fix: `Rename the table, or share the existing one: add "connect_tables" to manifest.json (the entry is in the message) with your columns matching the owner's exactly.`
|
|
10830
|
+
};
|
|
10831
|
+
});
|
|
10768
10832
|
}
|
|
10769
10833
|
if (isObj3(detail) && detail["error"] === "stale_revision") {
|
|
10770
10834
|
return [
|
|
@@ -29985,6 +30049,38 @@ ${METRIC_ADVICE}
|
|
|
29985
30049
|
);
|
|
29986
30050
|
}
|
|
29987
30051
|
|
|
30052
|
+
// src/commands/appspace/tables.ts
|
|
30053
|
+
function renderTables(rows2) {
|
|
30054
|
+
if (rows2.length === 0) return "No app owns a table you can see.\n";
|
|
30055
|
+
return rows2.map(
|
|
30056
|
+
(r) => `${r.table} (owner ${r.owner_app}${r.stage ? `, ${r.stage}` : ""})
|
|
30057
|
+
columns: ${columnsLine(r.columns)}
|
|
30058
|
+
to share: "connect_tables": ${JSON.stringify(r.connect_tables)}
|
|
30059
|
+
`
|
|
30060
|
+
).join("");
|
|
30061
|
+
}
|
|
30062
|
+
function registerTablesCommand(parent) {
|
|
30063
|
+
withJsonOption(
|
|
30064
|
+
withServerOptions(
|
|
30065
|
+
parent.command("tables").description(
|
|
30066
|
+
"List the tables this tenant's apps own, with their columns and owner app (to share one, connect to it)."
|
|
30067
|
+
)
|
|
30068
|
+
)
|
|
30069
|
+
).action(async (opts) => {
|
|
30070
|
+
const client = await connect(opts);
|
|
30071
|
+
try {
|
|
30072
|
+
const rows2 = await client.request("/apps/tables");
|
|
30073
|
+
if (opts.json === true) {
|
|
30074
|
+
printJson(rows2);
|
|
30075
|
+
return;
|
|
30076
|
+
}
|
|
30077
|
+
process.stdout.write(renderTables(rows2));
|
|
30078
|
+
} finally {
|
|
30079
|
+
client.cleanup();
|
|
30080
|
+
}
|
|
30081
|
+
});
|
|
30082
|
+
}
|
|
30083
|
+
|
|
29988
30084
|
// src/commands/appspace/whoami.ts
|
|
29989
30085
|
function registerWhoamiCommand2(parent) {
|
|
29990
30086
|
withJsonOption(
|
|
@@ -30023,6 +30119,7 @@ function registerAppSpaceCommand(root) {
|
|
|
30023
30119
|
const cmd = root.command("app-space").description("Build and deploy App Space apps.");
|
|
30024
30120
|
registerWhoamiCommand2(cmd);
|
|
30025
30121
|
registerListCommand(cmd);
|
|
30122
|
+
registerTablesCommand(cmd);
|
|
30026
30123
|
registerScaffoldCommand(cmd);
|
|
30027
30124
|
registerGetCommand(cmd);
|
|
30028
30125
|
registerLogsCommand(cmd);
|