@datarails-ai/dr-appspace-cli 0.12.33 → 0.12.35

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.
Files changed (2) hide show
  1. package/dist/cli.js +30 -9
  2. 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.33",
16
+ version: "0.12.35",
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-26T12:07:09.192Z";
60
+ var BUILD_TIME = "2026-10-26T12:46:38.741Z";
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)
@@ -24755,6 +24760,11 @@ function readPage2(app, page, spec, elements, problems) {
24755
24760
  well_formed: tree.well_formed,
24756
24761
  tree: [],
24757
24762
  owned: true,
24763
+ // A page `app-space eject page:` made owned still embeds the contract
24764
+ // it was compiled from, and the runtime's param store reads the
24765
+ // page's params from there, as it does on a compiled page. A page
24766
+ // written by hand with no embedded contract says nothing, as before.
24767
+ ...paramsOf2(page),
24758
24768
  ...pageRolesOf2(app.manifest, page.path)
24759
24769
  },
24760
24770
  pins: pinsOf2(page, tree)
@@ -30581,21 +30591,32 @@ async function ejectPage(dir, contract, path3) {
30581
30591
  element["children"] = element["children"].filter((uid) => !gone.has(String(uid)));
30582
30592
  }
30583
30593
  const kept = {};
30584
- for (const key of ["path", "route", "title"]) if (page[key] !== void 0) kept[key] = page[key];
30594
+ for (const key of ["path", "route", "title", "params", "roles"]) if (page[key] !== void 0) kept[key] = page[key];
30585
30595
  kept["owned"] = true;
30586
- if (gate !== null) kept["role"] = gate;
30596
+ if (gate !== null && kept["roles"] === void 0) kept["role"] = gate;
30587
30597
  pages[index] = kept;
30588
30598
  const app = obj3(obj3(contract["data"])["app"]);
30589
30599
  if (Array.isArray(app["screens"])) {
30590
30600
  app["screens"] = app["screens"].filter((screen) => !(isPlain2(screen) && screen["page"] === path3));
30591
30601
  }
30592
- const wrote = await commit(dir, contract, path3, marked2);
30602
+ const sources = Object.keys(obj3(obj3(contract["data"])["sources"]));
30603
+ const served = sources.filter((name) => files[`handlers/${name}.py`] !== void 0);
30604
+ const wrote = await commit(dir, contract, path3, marked2, (after) => {
30605
+ const lost = served.filter((name) => after[`handlers/${name}.py`] === void 0).sort();
30606
+ if (lost.length > 0) throw new Refused(unservedAfter(path3, lost));
30607
+ });
30593
30608
  return {
30594
30609
  target: `page:${path3}`,
30595
30610
  wrote,
30596
30611
  said: `page ${path3} is yours now: owned, and its ${String(gone.size)} element${gone.size === 1 ? "" : "s"} left the contract.`
30597
30612
  };
30598
30613
  }
30614
+ function unservedAfter(path3, lost) {
30615
+ const one = lost.length === 1;
30616
+ const names = lost.map((name) => JSON.stringify(name)).join(", ");
30617
+ const files = lost.map((name) => `handlers/${name}.py`).join(", ");
30618
+ 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.`;
30619
+ }
30599
30620
  function navGateOf(files, path3) {
30600
30621
  const gates = navGates;
30601
30622
  for (const [file, text3] of Object.entries(files)) {
@@ -30727,7 +30748,7 @@ async function mayPlace(dir, path3, text3, same5) {
30727
30748
  `${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
30749
  );
30729
30750
  }
30730
- async function commit(dir, contract, path3, text3) {
30751
+ async function commit(dir, contract, path3, text3, check5) {
30731
30752
  const invalid = validateContract(contract, NO_CATALOG).problems;
30732
30753
  if (invalid.length > 0) {
30733
30754
  throw new Refused(`after this eject contract.json would not validate, so eject leaves the folder as it was:
@@ -30745,6 +30766,7 @@ ${formatProblems(invalid)}`);
30745
30766
  ${lines}
30746
30767
  `);
30747
30768
  }
30769
+ check5?.(built.files);
30748
30770
  const full = join16(dir, path3);
30749
30771
  const wrote = await readIfPresent(full) === text3 ? [] : [path3];
30750
30772
  if (wrote.length > 0) {
@@ -34231,16 +34253,15 @@ var SEE = {
34231
34253
  };
34232
34254
  var NO_COMPONENTS = "This page did not load dr-components; compile it again with the current CLI.";
34233
34255
  var NO_PART = (type) => `${type} is not a part this page's dr-components draws.`;
34234
- var EMBEDDED = /<script\b[^>]*\bid\s*=\s*["']dr-contract["'][^>]*>([\s\S]*?)<\/script>/i;
34235
34256
  function pushedContract(bundle, pages) {
34236
34257
  const order2 = [...pages, ...Object.keys(bundle).filter((path3) => !pages.includes(path3))];
34237
34258
  for (const path3 of order2) {
34238
34259
  const html = bundle[path3];
34239
34260
  if (typeof html !== "string") continue;
34240
- const found = EMBEDDED.exec(html);
34261
+ const found = contractBlockText(html);
34241
34262
  if (found === null) continue;
34242
34263
  try {
34243
- const parsed = JSON.parse(found[1] ?? "");
34264
+ const parsed = JSON.parse(found);
34244
34265
  if (typeof parsed === "object" && parsed !== null && !Array.isArray(parsed)) {
34245
34266
  return parsed;
34246
34267
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datarails-ai/dr-appspace-cli",
3
- "version": "0.12.33",
3
+ "version": "0.12.35",
4
4
  "description": "Datarails App Space CLI — build, try, push and publish App Space apps",
5
5
  "type": "module",
6
6
  "engines": {