@datarails-ai/dr-appspace-cli 0.12.37 → 0.12.38

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 (3) hide show
  1. package/README.md +5 -2
  2. package/dist/cli.js +41 -12
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -287,8 +287,11 @@ It compiles in memory, writes only the ejected file and `contract.json`,
287
287
  refuses a file already at that path unless it holds exactly what the
288
288
  compiler would write, and refuses an eject after which the folder would not
289
289
  compile (a page holding the only form a `by` handler is called from, a
290
- handler a picker needs as a list). `page:` keeps the page's nav gate as
291
- `pages[i].role`; an ejected handler's docstring says the file is yours.
290
+ handler a picker needs as a list). `page:` keeps the page's `params` and
291
+ `roles` (its nav gate as `pages[i].role` when it states no roles), and the
292
+ sources the page reads keep their handlers and gates: the compiler reads them
293
+ off the contract the owned page embeds. An ejected handler's docstring says
294
+ the file is yours.
292
295
  The next `compile` carries the file as yours, and the one after writes
293
296
  nothing.
294
297
 
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.37",
16
+ version: "0.12.38",
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-26T14:01:26.088Z";
60
+ var BUILD_TIME = "2026-10-26T15:07:50.401Z";
61
61
  function formatBuildTime(iso) {
62
62
  if (iso === "") return "";
63
63
  const d = new Date(iso);
@@ -9618,7 +9618,7 @@ function rolesLandingNowhere(contract) {
9618
9618
  }
9619
9619
  return out;
9620
9620
  }
9621
- function sourceRoles(contract, name) {
9621
+ function sourceRoles(contract, name, known = /* @__PURE__ */ new Set()) {
9622
9622
  const source = contract?.data?.sources?.[name];
9623
9623
  const stated2 = gateRoles(source?.requiresRole);
9624
9624
  const elements = isPlainObject3(contract?.elements) ? contract.elements : {};
@@ -9636,7 +9636,7 @@ function sourceRoles(contract, name) {
9636
9636
  for (const role of roles) if (!union.includes(role)) union.push(role);
9637
9637
  }
9638
9638
  for (const page of pagesOf(contract)) {
9639
- if (page.owned !== true || readers === 0) continue;
9639
+ if (page.owned !== true || readers === 0 || known.has(page.path)) continue;
9640
9640
  const roles = pageRoles(page);
9641
9641
  if (roles.length === 0) open2 = true;
9642
9642
  for (const role of roles) if (!union.includes(role)) union.push(role);
@@ -12593,6 +12593,34 @@ function servedSources(elements, sources) {
12593
12593
  }
12594
12594
  return [...out].sort(natural3);
12595
12595
  }
12596
+ function ownedReaders(pages, extra) {
12597
+ const readers = {};
12598
+ const known = /* @__PURE__ */ new Set();
12599
+ for (const page of Array.isArray(pages) ? pages : []) {
12600
+ if (page?.owned !== true || !named5(page.path)) continue;
12601
+ const text3 = extra?.[page.path];
12602
+ if (typeof text3 !== "string" || !isOwnedPage(text3)) continue;
12603
+ const embedded = embeddedContractOf({ text: text3 });
12604
+ if (embedded === null) continue;
12605
+ known.add(page.path);
12606
+ const elements = isPlainObject8(embedded.elements) ? embedded.elements : {};
12607
+ for (const uid of Object.keys(elements).sort(natural3)) {
12608
+ const element = elements[uid];
12609
+ if (!isPlainObject8(element) || element.page !== page.path) continue;
12610
+ const props = isPlainObject8(element.props) ? element.props : {};
12611
+ const kept = {};
12612
+ if (named5(props.source)) kept.source = props.source;
12613
+ if (Array.isArray(props.declares?.reads)) kept.declares = { reads: props.declares.reads.filter(named5) };
12614
+ if (Object.keys(kept).length > 0) readers[`owned:${uid}`] = { page: page.path, props: kept };
12615
+ }
12616
+ }
12617
+ return { readers, known };
12618
+ }
12619
+ function withOwnedReaders(contract, readers) {
12620
+ if (Object.keys(readers).length === 0) return contract;
12621
+ const elements = isPlainObject8(contract?.elements) ? contract.elements : {};
12622
+ return { ...contract, elements: { ...elements, ...readers } };
12623
+ }
12596
12624
  function sourceProblems(sources, app, handlers, extra) {
12597
12625
  const problems = [];
12598
12626
  const names = Object.keys(sources).sort(natural3);
@@ -13624,7 +13652,8 @@ function compileApp(contract, { kit = null, runtime = RUNTIME, extra = {} } = {}
13624
13652
  problems.push(...exprProblems(stated2));
13625
13653
  const metricFindings = metricProblems(contract?.data?.metrics, stated2);
13626
13654
  problems.push(...metricFindings.filter((one) => !one.advisory));
13627
- problems.push(...paramProblems(contract, stated2));
13655
+ const owned = ownedReaders(contract.pages, extra);
13656
+ problems.push(...paramProblems(withOwnedReaders(contract, owned.readers), stated2));
13628
13657
  problems.push(...themeProblems(app));
13629
13658
  problems.push(...shellProblems(contract, typed, handlers, stated2));
13630
13659
  const sources = fillFilterable(stated2);
@@ -13743,10 +13772,10 @@ function compileApp(contract, { kit = null, runtime = RUNTIME, extra = {} } = {}
13743
13772
  problems.push(...placementProblems(elements, pages, tree, order2));
13744
13773
  if (problems.length > 0) return { files: {}, problems, contract, warnings };
13745
13774
  const whole = restate(contract, elements, pages, typed, order2);
13746
- const served = servedSources(elements, sources);
13775
+ const served = servedSources({ ...elements, ...owned.readers }, sources);
13747
13776
  const transforms = transformTexts2(sources, extra);
13748
13777
  const files = {};
13749
- files["manifest.json"] = json(manifestOf(contract, manifestApp, handlers, names, model, served));
13778
+ files["manifest.json"] = json(manifestOf(contract, manifestApp, handlers, names, model, served, withOwnedReaders(contract, owned.readers), owned.known));
13750
13779
  if (app.data_model) files["data_model.json"] = json(dataModelOf(app.data_model));
13751
13780
  for (const name of names) {
13752
13781
  const path3 = `handlers/${name}.py`;
@@ -16559,7 +16588,7 @@ function statusColumn(model, row) {
16559
16588
  const status = table.columns.status;
16560
16589
  return status !== void 0 && status.enum === null ? "status" : null;
16561
16590
  }
16562
- function manifestOf(contract, app, handlers, names, model, served = []) {
16591
+ function manifestOf(contract, app, handlers, names, model, served = [], readers = contract, known = /* @__PURE__ */ new Set()) {
16563
16592
  const manifest = {
16564
16593
  apiVersion: app.api_version ?? DEFAULT_API_VERSION,
16565
16594
  id: app.id ?? null,
@@ -16585,7 +16614,7 @@ function manifestOf(contract, app, handlers, names, model, served = []) {
16585
16614
  }
16586
16615
  for (const name of served) {
16587
16616
  const entry = { http: "POST", entrypoint: `handlers/${name}.py` };
16588
- const { roles: gate } = sourceRoles(contract, name);
16617
+ const { roles: gate } = sourceRoles(readers, name, known);
16589
16618
  if (gate.length > 0) entry.requiresRole = gate;
16590
16619
  manifest.handlers[name] = entry;
16591
16620
  }
@@ -29407,7 +29436,7 @@ function rolesLandingNowhere2(contract) {
29407
29436
  }
29408
29437
  return out;
29409
29438
  }
29410
- function sourceRoles2(contract, name) {
29439
+ function sourceRoles2(contract, name, known = /* @__PURE__ */ new Set()) {
29411
29440
  const source = contract?.data?.sources?.[name];
29412
29441
  const stated2 = gateRoles2(source?.requiresRole);
29413
29442
  const elements = isPlainObject17(contract?.elements) ? contract.elements : {};
@@ -29425,7 +29454,7 @@ function sourceRoles2(contract, name) {
29425
29454
  for (const role of roles) if (!union.includes(role)) union.push(role);
29426
29455
  }
29427
29456
  for (const page of pagesOf2(contract)) {
29428
- if (page.owned !== true || readers === 0) continue;
29457
+ if (page.owned !== true || readers === 0 || known.has(page.path)) continue;
29429
29458
  const roles = pageRoles2(page);
29430
29459
  if (roles.length === 0) open2 = true;
29431
29460
  for (const role of roles) if (!union.includes(role)) union.push(role);
@@ -31242,7 +31271,7 @@ function unservedAfter(path3, lost) {
31242
31271
  const one = lost.length === 1;
31243
31272
  const names = lost.map((name) => JSON.stringify(name)).join(", ");
31244
31273
  const files = lost.map((name) => `handlers/${name}.py`).join(", ");
31245
- 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.`;
31274
+ return `after this eject the compiler would write no handler for source${one ? "" : "s"} ${names}, which ${path3} reads, so ${files} would go and the page would call ${one ? "a handler" : "handlers"} that ${one ? "is" : "are"} not there. The compiler counts an owned page as a reader of what the contract it embeds reads, and eject keeps that contract on the page, so this is a bug in the compiler or in eject, not in your contract. Meanwhile, 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.`;
31246
31275
  }
31247
31276
  function navGateOf(files, path3) {
31248
31277
  const gates = navGates;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@datarails-ai/dr-appspace-cli",
3
- "version": "0.12.37",
3
+ "version": "0.12.38",
4
4
  "description": "Datarails App Space CLI — build, try, push and publish App Space apps",
5
5
  "type": "module",
6
6
  "engines": {