@trops/dash-core 0.1.429 → 0.1.432

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.
@@ -27270,7 +27270,7 @@ function findWidgetsDir$2(widgetPath) {
27270
27270
  * @param {string} widgetPath - Absolute path to the widget directory
27271
27271
  * @returns {Promise<string|null>} Path to the compiled bundle, or null if nothing to compile
27272
27272
  */
27273
- async function compileWidget(widgetPath) {
27273
+ async function compileWidget$1(widgetPath) {
27274
27274
  const widgetsDir = findWidgetsDir$2(widgetPath);
27275
27275
 
27276
27276
  if (!widgetsDir) {
@@ -27402,7 +27402,7 @@ async function compileWidget(widgetPath) {
27402
27402
  }
27403
27403
  }
27404
27404
 
27405
- var widgetCompiler$1 = { compileWidget, findWidgetsDir: findWidgetsDir$2 };
27405
+ var widgetCompiler$1 = { compileWidget: compileWidget$1, findWidgetsDir: findWidgetsDir$2 };
27406
27406
 
27407
27407
  /**
27408
27408
  * Dynamic Widget Loader
@@ -29418,25 +29418,31 @@ var schedulerController_1 = schedulerController$2;
29418
29418
 
29419
29419
  let bundlePath = findBundlePath(widget.path);
29420
29420
 
29421
- // Auto-compile if no bundle exists (same as read-all-bundles)
29421
+ // Auto-compile if no bundle exists (registry installs ship the
29422
+ // bundle pre-compiled, so this fallback only fires for older
29423
+ // packages or local installs).
29424
+ let compileError = null;
29422
29425
  if (!bundlePath) {
29423
29426
  try {
29424
29427
  const compiled = await compileWidget(widget.path);
29425
29428
  if (compiled) {
29426
29429
  bundlePath = compiled;
29427
29430
  }
29428
- } catch (compileError) {
29429
- console.warn(
29430
- `[WidgetRegistry] Could not compile ${widgetName}:`,
29431
- compileError,
29432
- );
29431
+ } catch (err) {
29432
+ compileError = err;
29433
+ // dash-core's electron build strips console.* — surface
29434
+ // the actual cause through the IPC return so the renderer
29435
+ // can show it to the user.
29433
29436
  }
29434
29437
  }
29435
29438
 
29436
29439
  if (!bundlePath) {
29440
+ const detail = compileError
29441
+ ? ` (auto-compile failed: ${compileError.message})`
29442
+ : "";
29437
29443
  return {
29438
29444
  success: false,
29439
- error: `No bundle found in: ${widget.path}`,
29445
+ error: `No bundle found in: ${widget.path}${detail}`,
29440
29446
  };
29441
29447
  }
29442
29448
 
@@ -64504,6 +64510,96 @@ function stripPersonalizationFromWorkspace$1(workspace) {
64504
64510
  return cleaned;
64505
64511
  }
64506
64512
 
64513
+ /**
64514
+ * Remap each layout item's `packageId` from a local-only scope (e.g.
64515
+ * `@ai-built/foo`) to the caller's published scope (`@<callerScope>/foo`)
64516
+ * so the installer's ComponentManager — which registers widgets under
64517
+ * the published scope — can look them up.
64518
+ *
64519
+ * Mirrors the scope-remap that `generateRegistryManifest` already does
64520
+ * for the dashboard's widget DEPENDENCIES list. Without this, the deps
64521
+ * list is correct (`@callerScope/foo`) but the per-instance layout
64522
+ * items still say `packageId: "@ai-built/foo"` — every Dependencies
64523
+ * tab + publish-flow attribution on the installer's machine misses.
64524
+ *
64525
+ * Returns a deep copy. Idempotent: items already under the caller
64526
+ * scope (or any non-local scope) pass through untouched.
64527
+ *
64528
+ * @param {Object} workspace
64529
+ * @param {string} callerScope - Publisher's registry username (e.g. "trops")
64530
+ * @param {string[]} [localOnlyScopes=["ai-built"]] - Scopes that must be remapped
64531
+ */
64532
+ function remapLayoutPackageScopes$1(
64533
+ workspace,
64534
+ callerScope,
64535
+ localOnlyScopes = ["ai-built"],
64536
+ ) {
64537
+ if (!workspace || !callerScope) return workspace;
64538
+ const localScopeSet = new Set(
64539
+ localOnlyScopes.map((s) => String(s).replace(/^@/, "")),
64540
+ );
64541
+ const callerScopeBare = String(callerScope).replace(/^@/, "");
64542
+ const remapPackageId = (pkgId) => {
64543
+ if (typeof pkgId !== "string" || pkgId.length === 0) return pkgId;
64544
+ // Match `@<scope>/<rest>` or `<scope>/<rest>`. Tolerant of either form.
64545
+ const m = pkgId.match(/^@?([^/]+)\/(.+)$/);
64546
+ if (!m) return pkgId;
64547
+ const scope = m[1];
64548
+ const rest = m[2];
64549
+ if (!localScopeSet.has(scope)) return pkgId;
64550
+ return `@${callerScopeBare}/${rest}`;
64551
+ };
64552
+ // Layout items now carry a SCOPED `component` (e.g.
64553
+ // "ai-built.pipeline.ProspectListColumn"). On publish we have to
64554
+ // rewrite the scope segment to the caller's so the installer can
64555
+ // resolve the same component against its registry-installed widget
64556
+ // (which lives under "@<caller>/pipeline"). Bare component names
64557
+ // (legacy layouts) pass through untouched — ComponentManager's
64558
+ // bare-name fallback handles them on the install side.
64559
+ const remapComponent = (component) => {
64560
+ if (typeof component !== "string" || component.length === 0) {
64561
+ return component;
64562
+ }
64563
+ const parts = component.split(".");
64564
+ if (parts.length !== 3) return component;
64565
+ const [scope, pkg, comp] = parts;
64566
+ if (!localScopeSet.has(scope)) return component;
64567
+ return `${callerScopeBare}.${pkg}.${comp}`;
64568
+ };
64569
+ const remapItem = (item) => {
64570
+ if (!item || typeof item !== "object") return item;
64571
+ const next = { ...item };
64572
+ if (item.packageId) {
64573
+ const remapped = remapPackageId(item.packageId);
64574
+ if (remapped !== item.packageId) next.packageId = remapped;
64575
+ }
64576
+ if (item._sourcePackage) {
64577
+ const remapped = remapPackageId(item._sourcePackage);
64578
+ if (remapped !== item._sourcePackage) next._sourcePackage = remapped;
64579
+ }
64580
+ if (item.component) {
64581
+ const remapped = remapComponent(item.component);
64582
+ if (remapped !== item.component) next.component = remapped;
64583
+ }
64584
+ if (Array.isArray(item.items)) next.items = item.items.map(remapItem);
64585
+ if (Array.isArray(item.layout)) next.layout = item.layout.map(remapItem);
64586
+ return next;
64587
+ };
64588
+ const next = { ...workspace };
64589
+ if (Array.isArray(next.layout)) next.layout = next.layout.map(remapItem);
64590
+ if (Array.isArray(next.sidebarLayout)) {
64591
+ next.sidebarLayout = next.sidebarLayout.map(remapItem);
64592
+ }
64593
+ if (Array.isArray(next.pages)) {
64594
+ next.pages = next.pages.map((page) =>
64595
+ page && Array.isArray(page.layout)
64596
+ ? { ...page, layout: page.layout.map(remapItem) }
64597
+ : page,
64598
+ );
64599
+ }
64600
+ return next;
64601
+ }
64602
+
64507
64603
  var dashboardConfigUtils$1 = {
64508
64604
  collectComponentNames: collectComponentNames$1,
64509
64605
  collectComponentNamesFromWorkspace: collectComponentNamesFromWorkspace$1,
@@ -64520,6 +64616,7 @@ var dashboardConfigUtils$1 = {
64520
64616
  buildProviderSetupManifest,
64521
64617
  checkApiCompatibility,
64522
64618
  stripPersonalizationFromWorkspace: stripPersonalizationFromWorkspace$1,
64619
+ remapLayoutPackageScopes: remapLayoutPackageScopes$1,
64523
64620
  };
64524
64621
 
64525
64622
  /**
@@ -65561,6 +65658,7 @@ const {
65561
65658
  buildProviderRequirements,
65562
65659
  applyEventWiringToLayout,
65563
65660
  stripPersonalizationFromWorkspace,
65661
+ remapLayoutPackageScopes,
65564
65662
  } = dashboardConfigUtils$1;
65565
65663
  const { searchRegistry, getPackage } = registryController$3;
65566
65664
  const { getStoredToken, clearToken } = registryAuthController$2;
@@ -66980,7 +67078,33 @@ async function prepareDashboardForPublish$1(
66980
67078
  // widget's own `defaultValue` on each field never gets a chance.
66981
67079
  // Layout position, ordering, nested containers, and any title text
66982
67080
  // are preserved (they're part of the template, not personal).
66983
- const sharedWorkspace = stripPersonalizationFromWorkspace(workspace);
67081
+ let sharedWorkspace = stripPersonalizationFromWorkspace(workspace);
67082
+
67083
+ // Remap layout-item `packageId` from any local-only scope (e.g.
67084
+ // `@ai-built/foo`) to the publisher's scope (`@<callerScope>/foo`).
67085
+ // The widget-deps array in the dashboard manifest already gets
67086
+ // remapped (see generateRegistryManifest), but the per-instance
67087
+ // `packageId` on the layout items themselves was being shipped
67088
+ // as-is — so installers' ComponentManager (which registers
67089
+ // widgets under the published scope) couldn't reverse-look-up by
67090
+ // `packageId` on a layout item, breaking the Dependencies tab and
67091
+ // the publish-flow attribution on chained republishes.
67092
+ let resolvedCallerScope = options.callerScope || options.githubUser || "";
67093
+ if (!resolvedCallerScope) {
67094
+ try {
67095
+ const { getRegistryProfile } = registryAuthController$2;
67096
+ const profile = await getRegistryProfile();
67097
+ resolvedCallerScope = profile?.username || options.authorId || "";
67098
+ } catch {
67099
+ resolvedCallerScope = options.authorId || "";
67100
+ }
67101
+ }
67102
+ if (resolvedCallerScope) {
67103
+ sharedWorkspace = remapLayoutPackageScopes(
67104
+ sharedWorkspace,
67105
+ resolvedCallerScope,
67106
+ );
67107
+ }
66984
67108
  const layout = sharedWorkspace.layout || [];
66985
67109
 
66986
67110
  // 3. Build the dashboard config — walk main + pages + sidebar
@@ -73731,7 +73855,7 @@ const {
73731
73855
  } = registryAuthController$2;
73732
73856
  const widgetRegistryModule = widgetRegistryExports;
73733
73857
  const { dynamicWidgetLoader: dynamicWidgetLoader$1 } = dynamicWidgetLoaderExports;
73734
- const { findWidgetsDir } = widgetCompiler$1;
73858
+ const { findWidgetsDir, compileWidget } = widgetCompiler$1;
73735
73859
  const {
73736
73860
  resolveNextVersion,
73737
73861
  parsePackageName,
@@ -73939,9 +74063,13 @@ async function stageOverrides(srcDir, dstDir, overrides) {
73939
74063
 
73940
74064
  // ─── ZIP builder ─────────────────────────────────────────────────────────────
73941
74065
 
74066
+ // `dist` is intentionally NOT excluded — the publish flow runs
74067
+ // `compileWidget` against the staged package right before zipping so
74068
+ // the installer doesn't have to recompile (and fail silently because
74069
+ // `console.*` is stripped from dash-core's electron build, masking
74070
+ // any esbuild error). Shipping the bundle makes install zero-config.
73942
74071
  const ZIP_EXCLUDE_DIRS = new Set([
73943
74072
  "node_modules",
73944
- "dist",
73945
74073
  ".git",
73946
74074
  ".DS_Store",
73947
74075
  ".next",
@@ -74152,6 +74280,25 @@ async function prepareWidgetForPublish$1(appId, packageId, options = {}) {
74152
74280
  await stageOverrides(widget.path, stagedDir, options.defaultsOverride);
74153
74281
  sourceDir = stagedDir;
74154
74282
  }
74283
+
74284
+ // Compile the widget into `dist/index.cjs.js` before zipping.
74285
+ // The installer also runs compileWidget at first-load, but
74286
+ // dash-core strips `console.*` from its electron bundle, so any
74287
+ // esbuild error during install-time compile vanishes silently
74288
+ // and the user just sees `No bundle found`. Compiling at
74289
+ // publish time (where errors WILL surface to the publisher who
74290
+ // can fix them) and shipping the bundle in the ZIP makes
74291
+ // install zero-config.
74292
+ try {
74293
+ await compileWidget(sourceDir);
74294
+ } catch (compileErr) {
74295
+ return {
74296
+ success: false,
74297
+ error: `Widget compilation failed: ${compileErr.message}. Fix the source error and republish; otherwise installers won't be able to load the widget.`,
74298
+ manifest,
74299
+ };
74300
+ }
74301
+
74155
74302
  const zip = new AdmZip();
74156
74303
  addDirToZip(zip, sourceDir);
74157
74304
  zip.writeZip(zipPath);