@trops/dash-core 0.1.414 → 0.1.416

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.
@@ -27105,7 +27105,13 @@ async function updateRegistryPackage$1(scope, name, updates) {
27105
27105
  */
27106
27106
  async function deleteRegistryPackage$1(scope, name) {
27107
27107
  const stored = getStoredToken$4();
27108
- if (!stored) return null;
27108
+ if (!stored) {
27109
+ return {
27110
+ success: false,
27111
+ error: "Not signed in to the registry.",
27112
+ status: 0,
27113
+ };
27114
+ }
27109
27115
 
27110
27116
  try {
27111
27117
  const response = await fetch(
@@ -27120,25 +27126,49 @@ async function deleteRegistryPackage$1(scope, name) {
27120
27126
 
27121
27127
  if (response.status === 401) {
27122
27128
  clearToken$2();
27123
- return null;
27129
+ return {
27130
+ success: false,
27131
+ error: "Session expired. Sign in again and retry.",
27132
+ status: 401,
27133
+ };
27134
+ }
27135
+
27136
+ // Read body text once so we can either parse JSON on success or
27137
+ // surface the raw server error message on failure.
27138
+ const bodyText = await response.text().catch(() => "");
27139
+
27140
+ if (!response.ok) {
27141
+ let serverMsg = bodyText;
27142
+ try {
27143
+ const parsed = JSON.parse(bodyText);
27144
+ serverMsg = parsed?.error || parsed?.message || bodyText;
27145
+ } catch {
27146
+ // bodyText is already a plain string; use it as-is.
27147
+ }
27148
+ return {
27149
+ success: false,
27150
+ error:
27151
+ serverMsg ||
27152
+ `Registry returned ${response.status} ${response.statusText || ""}`.trim(),
27153
+ status: response.status,
27154
+ };
27124
27155
  }
27125
- if (!response.ok) return null;
27126
27156
 
27127
- // A successful DELETE frequently returns 204 No Content, in which
27128
- // case response.json() throws on empty body and the earlier version
27129
- // swallowed it as a null result — the UI then skipped its "onDeleted"
27130
- // refresh and looked like nothing happened. Handle 204 + unparseable
27131
- // success responses as a successful delete.
27132
- if (response.status === 204) {
27157
+ // Success path 204 No Content is common; JSON is optional.
27158
+ if (response.status === 204 || !bodyText.trim()) {
27133
27159
  return { success: true };
27134
27160
  }
27135
27161
  try {
27136
- return await response.json();
27162
+ return { success: true, ...JSON.parse(bodyText) };
27137
27163
  } catch {
27138
27164
  return { success: true };
27139
27165
  }
27140
- } catch {
27141
- return null;
27166
+ } catch (err) {
27167
+ return {
27168
+ success: false,
27169
+ error: `Network error: ${err?.message || "unknown"}`,
27170
+ status: 0,
27171
+ };
27142
27172
  }
27143
27173
  }
27144
27174
 
@@ -63837,13 +63867,31 @@ function generateRegistryManifest(dashboardConfig, options = {}) {
63837
63867
  options.callerScope && w.scope && w.scope !== options.callerScope
63838
63868
  ? options.callerScope
63839
63869
  : w.scope || "";
63870
+ // Packaged id — the scoped "@<scope>/<packageName>" string that
63871
+ // the install flow looks up in the registry. Build this from the
63872
+ // REMAPPED scope + bare packageName so installers resolve against
63873
+ // the scope the widget was actually published as, not the local
63874
+ // `@ai-built` convention. Stripping the scope prefix from a
63875
+ // potentially-scoped packageName keeps the result canonical.
63876
+ const bareName = stripScopePrefix(
63877
+ w.packageName || w.package || "",
63878
+ remappedScope || w.scope,
63879
+ );
63880
+ const scopedPackageId = remappedScope
63881
+ ? `@${remappedScope.replace(/^@/, "")}/${bareName}`
63882
+ : bareName;
63840
63883
  return {
63841
63884
  id: w.id,
63842
63885
  scope: remappedScope,
63843
- packageName: w.packageName || w.package || "",
63886
+ packageName: bareName,
63844
63887
  widgetName: w.widgetName || (w.id ? w.id.split(".").pop() : w.package),
63845
63888
  name: w.id ? w.id.split(".").pop() : w.package,
63846
- package: w.package,
63889
+ // `package` is consumed by the install flow as the registry
63890
+ // package id (see installDashboardFromRegistry in
63891
+ // dashboardConfigController.js). Must carry the remapped
63892
+ // scope, otherwise installers look up an @ai-built/... id that
63893
+ // only exists on the publisher's machine.
63894
+ package: scopedPackageId,
63847
63895
  version: w.version || "*",
63848
63896
  required: w.required !== false,
63849
63897
  author: w.author || "",
@@ -64121,6 +64169,67 @@ function extractEventWiringFromWorkspace$1(workspace) {
64121
64169
  return wiring;
64122
64170
  }
64123
64171
 
64172
+ /**
64173
+ * Strip publisher-specific personalization (userPrefs + selectedProviders)
64174
+ * from every widget instance in a layout-ish structure. Used by the
64175
+ * dashboard publish flow so the installer starts with the widget's
64176
+ * own defaultValue on every field instead of inheriting the
64177
+ * publisher's absolute paths, region tags, credentials, etc.
64178
+ *
64179
+ * Walks the standard layout shapes that forEachWidget handles:
64180
+ * - top-level `layout` arrays
64181
+ * - `workspace.pages[*].layout`
64182
+ * - `workspace.sidebarLayout`
64183
+ * - `LayoutGridContainer` children stored on `item.items` / `item.layout`
64184
+ *
64185
+ * Returns a deep copy — never mutates the input workspace.
64186
+ *
64187
+ * Title-ish defaults (widget.name) are intentionally preserved — they
64188
+ * are part of the dashboard template, not personal data. Anything else
64189
+ * under userPrefs is dropped; the installer's widget re-reads the
64190
+ * `defaultValue` declared in the component's `.dash.js`.
64191
+ */
64192
+ function stripPersonalizationFromWorkspace$1(workspace) {
64193
+ if (!workspace) return workspace;
64194
+ const cleanItem = (item) => {
64195
+ if (!item || typeof item !== "object") return item;
64196
+ // Preserve the layout position + children, but blank out the
64197
+ // user-set config values that are tied to the publisher's machine.
64198
+ const cleaned = { ...item };
64199
+ if ("userPrefs" in cleaned) delete cleaned.userPrefs;
64200
+ if ("selectedProviders" in cleaned) delete cleaned.selectedProviders;
64201
+ if (Array.isArray(cleaned.items)) {
64202
+ cleaned.items = cleaned.items.map(cleanItem);
64203
+ }
64204
+ if (Array.isArray(cleaned.layout)) {
64205
+ cleaned.layout = cleaned.layout.map(cleanItem);
64206
+ }
64207
+ return cleaned;
64208
+ };
64209
+ const cleaned = { ...workspace };
64210
+ if (Array.isArray(cleaned.layout))
64211
+ cleaned.layout = cleaned.layout.map(cleanItem);
64212
+ if (Array.isArray(cleaned.sidebarLayout))
64213
+ cleaned.sidebarLayout = cleaned.sidebarLayout.map(cleanItem);
64214
+ if (Array.isArray(cleaned.pages)) {
64215
+ cleaned.pages = cleaned.pages.map((page) =>
64216
+ page
64217
+ ? {
64218
+ ...page,
64219
+ ...(Array.isArray(page.layout)
64220
+ ? { layout: page.layout.map(cleanItem) }
64221
+ : {}),
64222
+ }
64223
+ : page,
64224
+ );
64225
+ }
64226
+ // Workspace-level selectedProviders map lives at the top level for
64227
+ // some older workspaces; drop it too so the installer doesn't get
64228
+ // bindings to provider names that don't exist on their machine.
64229
+ if ("selectedProviders" in cleaned) delete cleaned.selectedProviders;
64230
+ return cleaned;
64231
+ }
64232
+
64124
64233
  var dashboardConfigUtils$1 = {
64125
64234
  collectComponentNames: collectComponentNames$1,
64126
64235
  collectComponentNamesFromWorkspace: collectComponentNamesFromWorkspace$1,
@@ -64135,6 +64244,7 @@ var dashboardConfigUtils$1 = {
64135
64244
  checkDashboardUpdates,
64136
64245
  buildProviderSetupManifest,
64137
64246
  checkApiCompatibility,
64247
+ stripPersonalizationFromWorkspace: stripPersonalizationFromWorkspace$1,
64138
64248
  };
64139
64249
 
64140
64250
  /**
@@ -64880,6 +64990,7 @@ const {
64880
64990
  buildWidgetDependencies,
64881
64991
  buildProviderRequirements,
64882
64992
  applyEventWiringToLayout,
64993
+ stripPersonalizationFromWorkspace,
64883
64994
  } = dashboardConfigUtils$1;
64884
64995
  const { searchRegistry, getPackage } = registryController$3;
64885
64996
  const { getStoredToken, clearToken } = registryAuthController$2;
@@ -64927,7 +65038,11 @@ async function exportDashboardConfig$1(
64927
65038
  };
64928
65039
  }
64929
65040
 
64930
- const layout = workspace.layout || [];
65041
+ // Strip publisher-specific personalization (userPrefs,
65042
+ // selectedProviders) so the exported file carries a clean
65043
+ // template, not one pre-filled with the publisher's paths.
65044
+ const sharedWorkspace = stripPersonalizationFromWorkspace(workspace);
65045
+ const layout = sharedWorkspace.layout || [];
64931
65046
 
64932
65047
  // 2. Collect components, extract wiring, resolve deps — walk main
64933
65048
  // layout, every page, and the sidebar so multi-page / sidebar
@@ -64955,13 +65070,17 @@ async function exportDashboardConfig$1(
64955
65070
  label: workspace.label || workspace.name,
64956
65071
  version: workspace.version || 1,
64957
65072
  layout,
64958
- ...(Array.isArray(workspace.pages) && workspace.pages.length > 0
64959
- ? { pages: workspace.pages, activePageId: workspace.activePageId }
65073
+ ...(Array.isArray(sharedWorkspace.pages) &&
65074
+ sharedWorkspace.pages.length > 0
65075
+ ? {
65076
+ pages: sharedWorkspace.pages,
65077
+ activePageId: workspace.activePageId,
65078
+ }
64960
65079
  : {}),
64961
- ...(Array.isArray(workspace.sidebarLayout) &&
64962
- workspace.sidebarLayout.length > 0
65080
+ ...(Array.isArray(sharedWorkspace.sidebarLayout) &&
65081
+ sharedWorkspace.sidebarLayout.length > 0
64963
65082
  ? {
64964
- sidebarLayout: workspace.sidebarLayout,
65083
+ sidebarLayout: sharedWorkspace.sidebarLayout,
64965
65084
  sidebarEnabled: workspace.sidebarEnabled !== false,
64966
65085
  }
64967
65086
  : {}),
@@ -66213,7 +66332,16 @@ async function prepareDashboardForPublish$1(
66213
66332
  };
66214
66333
  }
66215
66334
 
66216
- const layout = workspace.layout || [];
66335
+ // Strip publisher-specific personalization (userPrefs,
66336
+ // selectedProviders) from every widget instance before we snapshot
66337
+ // the workspace into the dashboardConfig. Without this, every
66338
+ // installer inherits the publisher's absolute filesystem paths,
66339
+ // region tags, and provider bindings as their "defaults" — a
66340
+ // widget's own `defaultValue` on each field never gets a chance.
66341
+ // Layout position, ordering, nested containers, and any title text
66342
+ // are preserved (they're part of the template, not personal).
66343
+ const sharedWorkspace = stripPersonalizationFromWorkspace(workspace);
66344
+ const layout = sharedWorkspace.layout || [];
66217
66345
 
66218
66346
  // 3. Build the dashboard config — walk main + pages + sidebar
66219
66347
  const componentNames = collectComponentNamesFromWorkspace(workspace);
@@ -66253,13 +66381,17 @@ async function prepareDashboardForPublish$1(
66253
66381
  label: workspace.label || workspace.name,
66254
66382
  version: workspace.version || 1,
66255
66383
  layout,
66256
- ...(Array.isArray(workspace.pages) && workspace.pages.length > 0
66257
- ? { pages: workspace.pages, activePageId: workspace.activePageId }
66384
+ ...(Array.isArray(sharedWorkspace.pages) &&
66385
+ sharedWorkspace.pages.length > 0
66386
+ ? {
66387
+ pages: sharedWorkspace.pages,
66388
+ activePageId: workspace.activePageId,
66389
+ }
66258
66390
  : {}),
66259
- ...(Array.isArray(workspace.sidebarLayout) &&
66260
- workspace.sidebarLayout.length > 0
66391
+ ...(Array.isArray(sharedWorkspace.sidebarLayout) &&
66392
+ sharedWorkspace.sidebarLayout.length > 0
66261
66393
  ? {
66262
- sidebarLayout: workspace.sidebarLayout,
66394
+ sidebarLayout: sharedWorkspace.sidebarLayout,
66263
66395
  sidebarEnabled: workspace.sidebarEnabled !== false,
66264
66396
  }
66265
66397
  : {}),