@glasshome/widget-cli 0.10.1 → 0.10.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glasshome/widget-cli",
3
- "version": "0.10.1",
3
+ "version": "0.10.3",
4
4
  "description": "CLI for creating and managing GlassHome widgets",
5
5
  "type": "module",
6
6
  "bin": {
@@ -28,9 +28,9 @@
28
28
  "@fontsource-variable/caveat": "^5.2.8",
29
29
  "@fontsource-variable/geist": "^5.2.9",
30
30
  "@fontsource-variable/geist-mono": "^5.2.8",
31
- "@glasshome/sync-layer": "0.5.0",
31
+ "@glasshome/sync-layer": "0.7.0",
32
32
  "@glasshome/widget-contract": "0.2.0",
33
- "@glasshome/widget-sdk": "1.9.0",
33
+ "@glasshome/widget-sdk": "1.10.0",
34
34
  "@iconify-json/lucide": "^1.2.0",
35
35
  "@iconify-json/mdi": "^1.2.3",
36
36
  "@tailwindcss/vite": "^4.1.13",
@@ -193,6 +193,10 @@ export async function runPublish(
193
193
  process.exit(1);
194
194
  }
195
195
 
196
+ // Re-read after the build: it rewrites the bundle-owned manifest keys, and
197
+ // serializing the pre-build object would ship them one publish behind.
198
+ const builtManifest = readManifest(cwd, widgetName);
199
+
196
200
  // Step 7: Publish
197
201
  const distPath = resolve(cwd, "dist", `${widgetName}.js`);
198
202
 
@@ -217,37 +221,37 @@ export async function runPublish(
217
221
  ? createHash("sha256").update(cssBuffer).digest("hex")
218
222
  : undefined;
219
223
 
220
- s.start(`Publishing ${manifest.name}@${version}...`);
224
+ s.start(`Publishing ${builtManifest.name}@${version}...`);
221
225
 
222
226
  let publishData: Awaited<ReturnType<typeof requestPublish>>;
223
227
  try {
224
228
  publishData = await requestPublish(hubUrl, token!, {
225
229
  scope,
226
230
  name: widgetName,
227
- displayName: manifest.name,
228
- description: manifest.description,
229
- icon: manifest.icon,
230
- minSize: manifest.minSize,
231
- maxSize: manifest.maxSize,
232
- sdkVersion: manifest.sdkVersion,
231
+ displayName: builtManifest.name,
232
+ description: builtManifest.description,
233
+ icon: builtManifest.icon,
234
+ minSize: builtManifest.minSize,
235
+ maxSize: builtManifest.maxSize,
236
+ sdkVersion: builtManifest.sdkVersion,
233
237
  version,
234
238
  bundleSize: bundleBuffer.byteLength,
235
239
  sha256Hash,
236
240
  ...(cssBuffer && cssSha256Hash
237
241
  ? { cssSize: cssBuffer.byteLength, cssSha256Hash }
238
242
  : {}),
239
- manifestJson: JSON.stringify(manifest),
243
+ manifestJson: JSON.stringify(builtManifest),
240
244
  });
241
245
  } catch (err: any) {
242
246
  if (err.status === 409) {
243
- s.stop(`${manifest.name}@${version} already published, bump version to republish`);
247
+ s.stop(`${builtManifest.name}@${version} already published, bump version to republish`);
244
248
  process.exit(0);
245
249
  }
246
250
  s.stop(`Publish failed: ${err.message}`);
247
251
  process.exit(1);
248
252
  }
249
253
 
250
- s.message(`Uploading ${manifest.name} to CDN...`);
254
+ s.message(`Uploading ${builtManifest.name} to CDN...`);
251
255
  try {
252
256
  await uploadToR2(publishData.uploadUrl, bundleBuffer);
253
257
  } catch (err: any) {
@@ -262,7 +266,7 @@ export async function runPublish(
262
266
  );
263
267
  process.exit(1);
264
268
  }
265
- s.message(`Uploading ${manifest.name} styles to CDN...`);
269
+ s.message(`Uploading ${builtManifest.name} styles to CDN...`);
266
270
  try {
267
271
  await uploadToR2(publishData.cssUploadUrl, cssBuffer, "text/css");
268
272
  } catch (err: any) {
@@ -271,10 +275,10 @@ export async function runPublish(
271
275
  }
272
276
  }
273
277
 
274
- s.message(`Confirming ${manifest.name}...`);
278
+ s.message(`Confirming ${builtManifest.name}...`);
275
279
  try {
276
280
  const result = await confirmPublish(hubUrl, token!, publishData.versionId);
277
- s.stop(`Published ${manifest.name}@${version}`);
281
+ s.stop(`Published ${builtManifest.name}@${version}`);
278
282
  log.info(`CDN: ${result.bundleUrl}`);
279
283
  if (result.cssUrl) log.info(`CSS: ${result.cssUrl}`);
280
284
  } catch (err: any) {
@@ -1,7 +1,6 @@
1
1
  import type { ReactiveWidgetContext, WidgetDefinition } from "@glasshome/widget-sdk";
2
2
  import { instantiateWidget } from "@glasshome/widget-sdk/host";
3
- import { loadDemoData } from "@glasshome/sync-layer";
4
- import { getEntityView } from "@glasshome/sync-layer";
3
+ import { claimHostApi, getEntityView } from "@glasshome/sync-layer";
5
4
  import { byDomain, useAreas, useEntities } from "@glasshome/sync-layer/solid";
6
5
  import type { EntityDataAdapter } from "@glasshome/ui/solid";
7
6
  import { provideEntityData } from "@glasshome/ui/solid";
@@ -85,7 +84,13 @@ async function loadWidget(name: string): Promise<{ def: WidgetDefinition; css: s
85
84
  // Grid geometry mirrored from the dash route (rowHeight 70, margin 16, lg 12
86
85
  // cols at a 1024px reference container). A preview approximates one dashboard
87
86
  // width rather than mirroring every breakpoint.
88
- const CONTAINER = 1024;
87
+ // max-w-7xl (1280px) minus the route's px-3 padding, i.e. the width the grid
88
+ // actually gets on a desktop dashboard. NOT the lg breakpoint's 1024 minimum:
89
+ // that is the narrowest a desktop can be, and using it rendered every
90
+ // size-responsive widget one tier below what users see (energy-flow never
91
+ // reached its node-graph tier, so the storefront advertised the compact
92
+ // layout).
93
+ const CONTAINER = 1256;
89
94
  const COLS = 12;
90
95
  const GAP = 16;
91
96
  const ROW_H = 70;
@@ -98,11 +103,26 @@ function tilePx(size: { w: number; h: number }): { width: number; height: number
98
103
  };
99
104
  }
100
105
 
106
+ /* The shell composites `--glass-frost` as its bottom background layer and
107
+ defaults it to `none`, because in the app a live backdrop-filter blurs the
108
+ dashboard wallpaper behind the widget. A preview is shot alone on a
109
+ transparent page, so there is nothing to blur and the widget would render
110
+ with no surface at all: legible by luck in light mode, white-on-nothing in
111
+ dark. ui registers --glass-frost with `inherits: false`, so it cannot be
112
+ handed down from the host and has to be set on the shell element itself,
113
+ which is what dash's performant-blur override sheet does too.
114
+
115
+ `--card` is an ordinary inheriting theme token, so it crosses the shadow
116
+ boundary and follows the `dark` class already mirrored onto the host. */
117
+ const FROST_SHEET = new CSSStyleSheet();
118
+ FROST_SHEET.replaceSync(
119
+ ".glasshome-widget { --glass-frost: linear-gradient(var(--card), var(--card)); }",
120
+ );
121
+
101
122
  /** Mount via the shared SDK recipe (`@glasshome/widget-sdk/host`): closed shadow
102
123
  root, injected tokens, adopted widget CSS, WidgetCtx provider, `dark`
103
- mirrored onto the host. No perf-blur/a11y override sheet — not needed for a
104
- static shot, so no `extraSheets`; `dark` is the default `mirrorClasses`. The
105
- `dark` document class is toggled by the caller before this runs. */
124
+ mirrored onto the host. `dark` is the default `mirrorClasses`; the `dark`
125
+ document class is toggled by the caller before this runs. */
106
126
  function mount(
107
127
  host: HTMLElement,
108
128
  def: WidgetDefinition,
@@ -115,6 +135,7 @@ function mount(
115
135
  config: () => config,
116
136
  ctx,
117
137
  cssText,
138
+ extraSheets: [FROST_SHEET],
118
139
  onCrash: (err) => console.error("[harness] widget threw:", err),
119
140
  });
120
141
  }
@@ -144,7 +165,11 @@ async function main(): Promise<void> {
144
165
  // triggers the (now dead) network lookup and renders blank.
145
166
  await preloadIcons();
146
167
 
147
- await loadDemoData();
168
+ // The harness is a host: claim the privileged surface once at boot
169
+ // (sync-layer keeps demo control off the widget-reachable entry).
170
+ const hostApi = claimHostApi();
171
+ if (!hostApi) throw new Error("harness: host API already claimed");
172
+ await hostApi.loadDemoData();
148
173
 
149
174
  // Background and padding are the renderer's job: the preview is the widget
150
175
  // alone, tight and transparent (omitBackground on capture).