@glasshome/widget-sdk 1.15.1 → 1.17.0

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/dist/ui.d.ts CHANGED
@@ -15,4 +15,4 @@
15
15
  * `@glasshome/ui/solid` is a vite external of this package: these re-exports
16
16
  * resolve to the host-provided singleton at runtime, never a bundled copy.
17
17
  */
18
- export { Badge, Button, Carousel, type CarouselApi, CarouselContent, CarouselDots, CarouselItem, CarouselNext, CarouselPrevious, type CarouselTransition, type Color, ColorSlider, ColorWheel, CountPill, Icon, imageUrl, Input, Label, mediaUrl, parseColor, ResponsiveDialog, ResponsiveDialogBody, ResponsiveDialogClose, ResponsiveDialogContent, ResponsiveDialogDescription, ResponsiveDialogFooter, ResponsiveDialogHeader, ResponsiveDialogTitle, SchemaForm, SectionIcon, SectionTitle, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Slider, Switch, Tabs, TabsContent, TabsList, TabsTrigger, } from "@glasshome/ui/solid";
18
+ export { Badge, Button, ButtonGroup, Carousel, type CarouselApi, CarouselContent, CarouselDots, CarouselItem, CarouselNext, CarouselPrevious, type CarouselTransition, type Color, ColorDisc, ColorSlider, ColorWheel, CountPill, Icon, imagePreset, imageUrl, Input, Label, mediaUrl, parseColor, presetValue, Progress, ResponsiveDialog, ResponsiveDialogBody, ResponsiveDialogClose, ResponsiveDialogContent, ResponsiveDialogDescription, ResponsiveDialogFooter, ResponsiveDialogHeader, ResponsiveDialogTitle, SchemaForm, SectionIcon, SectionTitle, Select, SelectContent, SelectItem, SelectTrigger, SelectValue, Slider, SwatchPicker, Switch, Tabs, TemperatureBar, TabsContent, TabsList, TabsTrigger, Toggle, ToggleGroup, ToggleGroupItem, } from "@glasshome/ui/solid";
@@ -1,3 +1,4 @@
1
+ import { type CapabilityGrant } from "@glasshome/widget-contract";
1
2
  import type { InlineConfig, Plugin } from "vite";
2
3
  import type { ExampleConfigIssue, WidgetIntrospection } from "./introspect-core";
3
4
  import { createIntrospectSession, type IntrospectSession, type IntrospectSessionOptions, introspectOnce } from "./introspect-session";
@@ -15,6 +16,11 @@ export interface GlasshomeWidgetOptions {
15
16
  * author decide which states matter rather than discovering the loss never.
16
17
  */
17
18
  export declare const MAX_EXAMPLES = 20;
19
+ /** What a built bundle imports from the SDK, by exported name; `*` for a namespace or dynamic import. */
20
+ export declare function sdkImportsOf(code: string): Set<string>;
21
+ /** SDK hooks that read a fixed entity on the widget's behalf, so the widget must declare that read. */
22
+ export declare const HOOK_READS: Record<string, string>;
23
+ export declare function assertHookReadsDeclared(code: string, capabilities: readonly CapabilityGrant[], widgetName: string): void;
18
24
  export declare function runSchemaGuard(args: {
19
25
  outFile: string;
20
26
  hashFile: string;
@@ -61,6 +67,25 @@ export declare function createUiImportTracker(warned?: Set<string>): {
61
67
  /** Offending files this run has not reported yet; marks them reported. */
62
68
  take(): string[];
63
69
  };
70
+ /**
71
+ * Widgets render inside a closed shadow root in the host, which cuts them off
72
+ * from the host document stylesheet. Every widget bundle must therefore carry
73
+ * its own complete CSS: the ui theme + component styles, the SDK shell
74
+ * classes, and the Tailwind utilities its own JSX uses. This writes a
75
+ * generated css entry (a Tailwind pass over exactly those sources) plus a
76
+ * wrapper module that imports it ahead of the real widget entry, so Vite lib
77
+ * mode emits it as the widget's `<name>.css`.
78
+ *
79
+ * `source(none)` disables Tailwind's automatic project-root scan — without it
80
+ * every widget in a multi-widget repo gets the superset of all widgets'
81
+ * classes. The dark variant is redefined shadow-aware: `.dark *` cannot match
82
+ * across a shadow boundary, so the host mirrors the document's `dark` class
83
+ * onto the shadow host element and `:host(.dark)` picks it up.
84
+ */
85
+ /** The widget's own folder plus the project's shared folders: Tailwind only
86
+ * emits utilities for files it is pointed at, and a widget's shared component
87
+ * is as much its source as its entry. A sibling widget's folder stays out. */
88
+ export declare function widgetProjectScanDirs(srcDir: string, widgetEntry: string): string[];
64
89
  interface DiscoveredWidget {
65
90
  name: string;
66
91
  entry: string;
@@ -1,32 +1,32 @@
1
1
  import { deprecations as e, formatDeprecation as t } from "../deprecations.js";
2
- import { formatSchemaError as n, isHostProvidedModule as r, widgetManifestSchema as i } from "@glasshome/widget-contract";
3
- import { createHash as a } from "node:crypto";
4
- import { existsSync as o, mkdirSync as s, readFileSync as c, readdirSync as l, rmSync as u, statSync as d, writeFileSync as f } from "node:fs";
5
- import { createRequire as p } from "node:module";
6
- import { dirname as m, join as h, relative as g, resolve as _, sep as v } from "node:path";
7
- import { fileURLToPath as y } from "node:url";
2
+ import { formatSchemaError as n, isHostProvidedModule as r, matchesRead as i, widgetManifestSchema as a } from "@glasshome/widget-contract";
3
+ import { createHash as o } from "node:crypto";
4
+ import { existsSync as s, mkdirSync as c, readFileSync as l, readdirSync as u, rmSync as d, statSync as f, writeFileSync as p } from "node:fs";
5
+ import { createRequire as m } from "node:module";
6
+ import { dirname as h, join as g, relative as _, resolve as v, sep as y } from "node:path";
7
+ import { fileURLToPath as b } from "node:url";
8
8
  import ee from "@tailwindcss/vite";
9
- import { spawn as te, spawnSync as ne } from "node:child_process";
9
+ import { spawn as te, spawnSync as x } from "node:child_process";
10
10
  //#region src/vite/introspect-session.ts
11
- var re = 262144e3, b = 3e4, ie = 3e3;
12
- function x(e) {
13
- let t = m(y(import.meta.url));
14
- return [h(t, `${e}.js`), h(t, `${e}.ts`)].find((e) => o(e)) ?? null;
11
+ var S = 262144e3, C = 3e4, ne = 3e3;
12
+ function w(e) {
13
+ let t = h(b(import.meta.url));
14
+ return [g(t, `${e}.js`), g(t, `${e}.ts`)].find((e) => s(e)) ?? null;
15
15
  }
16
- function S(e) {
17
- let t = x("introspect");
16
+ function T(e) {
17
+ let t = w("introspect");
18
18
  if (!t) return {
19
19
  ok: !1,
20
20
  reason: "introspect not found next to the sdk"
21
21
  };
22
- let n = ne(process.execPath, [
22
+ let n = x(process.execPath, [
23
23
  "--conditions",
24
24
  "browser",
25
25
  t,
26
26
  e
27
27
  ], {
28
28
  encoding: "utf-8",
29
- timeout: b
29
+ timeout: C
30
30
  });
31
31
  if (n.error) return {
32
32
  ok: !1,
@@ -48,16 +48,16 @@ function S(e) {
48
48
  };
49
49
  }
50
50
  }
51
- function ae() {
51
+ function re() {
52
52
  return {
53
- introspect: async (e) => S(e),
53
+ introspect: async (e) => T(e),
54
54
  dispose: async () => {},
55
55
  childPid: null
56
56
  };
57
57
  }
58
- function C(e) {
59
- if (process.env.GLASSHOME_WIDGET_NO_WORKER === "1") return ae();
60
- let t = e?.rssLimitBytes ?? re, n = e?.timeoutMs ?? b, r = e?.slowMs ?? ie, i = null, a = !1, o = 0, s = Promise.resolve();
58
+ function ie(e) {
59
+ if (process.env.GLASSHOME_WIDGET_NO_WORKER === "1") return re();
60
+ let t = e?.rssLimitBytes ?? S, n = e?.timeoutMs ?? C, r = e?.slowMs ?? ne, i = null, a = !1, o = 0, s = Promise.resolve();
61
61
  function c(e, t) {
62
62
  for (let n of e.pending.values()) n({
63
63
  ok: !1,
@@ -128,7 +128,7 @@ function C(e) {
128
128
  ok: !1,
129
129
  reason: "introspect session disposed"
130
130
  };
131
- let t = x("introspect-worker");
131
+ let t = w("introspect-worker");
132
132
  if (!t) return {
133
133
  ok: !1,
134
134
  reason: "introspect-worker not found next to the sdk"
@@ -186,19 +186,19 @@ function C(e) {
186
186
  }
187
187
  //#endregion
188
188
  //#region src/vite/index.ts
189
- var w = 2;
190
- function T(e) {
191
- if (Array.isArray(e)) return `[${e.map(T).join(",")}]`;
189
+ var E = 2;
190
+ function D(e) {
191
+ if (Array.isArray(e)) return `[${e.map(D).join(",")}]`;
192
192
  if (typeof e == "object" && e) {
193
193
  let t = e;
194
- return `{${Object.keys(t).sort().filter((e) => t[e] !== void 0).map((e) => `${JSON.stringify(e)}:${T(t[e])}`).join(",")}}`;
194
+ return `{${Object.keys(t).sort().filter((e) => t[e] !== void 0).map((e) => `${JSON.stringify(e)}:${D(t[e])}`).join(",")}}`;
195
195
  }
196
196
  return JSON.stringify(e) ?? "null";
197
197
  }
198
- function E(e) {
199
- return a("sha256").update(T(e)).digest("hex").slice(0, 16);
198
+ function ae(e) {
199
+ return o("sha256").update(D(e)).digest("hex").slice(0, 16);
200
200
  }
201
- var D = 20;
201
+ var oe = 20;
202
202
  async function O(e, t) {
203
203
  if (e === void 0) return;
204
204
  let n;
@@ -227,7 +227,7 @@ function k(e, t) {
227
227
  }).join("\n");
228
228
  throw Error(`[widget-sdk] Example config rejected by "${t}"'s own configSchema:\n${n}\nEach example's \`config\` must be a config the widget would actually accept, or its preview renders empty.`);
229
229
  }
230
- var A = [
230
+ var se = [
231
231
  "schema",
232
232
  "defaultConfig",
233
233
  "examples",
@@ -240,51 +240,77 @@ var A = [
240
240
  "minSize",
241
241
  "maxSize"
242
242
  ];
243
- function j(e, t, n) {
244
- let r = c(e, "utf-8"), i = JSON.parse(r), a = {
243
+ function ce(e, t, n) {
244
+ let r = l(e, "utf-8"), i = JSON.parse(r), a = {
245
245
  ...t.manifest ?? {},
246
246
  schema: n
247
247
  };
248
- for (let e of A) a[e] !== void 0 && (i[e] = a[e]);
248
+ for (let e of se) a[e] !== void 0 && (i[e] = a[e]);
249
249
  let o = `${JSON.stringify(i, null, 2)}\n`;
250
- o !== r && f(e, o);
250
+ o !== r && p(e, o);
251
251
  }
252
- async function M(e) {
253
- if (!o(e.outFile)) return;
254
- let t = e.session ? await e.session.introspect(e.outFile) : S(e.outFile);
252
+ var le = /import\s*(\{[^}]*\}|\*\s*as\s+[\w$]+)\s*from\s*["']@glasshome\/widget-sdk["']/g, ue = /import\(\s*["']@glasshome\/widget-sdk["']\s*\)/;
253
+ function A(e) {
254
+ let t = /* @__PURE__ */ new Set();
255
+ ue.test(e) && t.add("*");
256
+ for (let [, n = ""] of e.matchAll(le)) {
257
+ if (!n.startsWith("{")) {
258
+ t.add("*");
259
+ continue;
260
+ }
261
+ for (let e of n.slice(1, -1).split(",")) {
262
+ let n = e.trim().split(/\s+as\s+/)[0];
263
+ n && t.add(n);
264
+ }
265
+ }
266
+ return t;
267
+ }
268
+ var j = { useDaylight: "sun.sun" };
269
+ function M(e, t, n) {
270
+ let r = A(e);
271
+ for (let [e, a] of Object.entries(j)) {
272
+ if (!r.has(e) && !r.has("*") || i(t, a)) continue;
273
+ let o = a.split(".")[0];
274
+ throw Error(`[widget-sdk] "${n}" uses ${e}(), which reads ${a}, but its capabilities grant no read of it.\n Add { "domain": "${o}", "access": "read" } to capabilities, so the homeowner is told before installing.`);
275
+ }
276
+ }
277
+ async function N(e) {
278
+ if (!s(e.outFile)) return;
279
+ let t = e.session ? await e.session.introspect(e.outFile) : T(e.outFile);
255
280
  if (!t.ok) throw Error(`[widget-sdk] Could not read "${e.widgetName}" to check it: ${t.reason}\n Its examples and config schema could not be validated, so the build cannot continue.
256
281
  This usually means the bundle throws while being imported.`);
257
282
  let n = t.value, r = n.manifest?.name ?? e.widgetName;
258
283
  await O(n.manifest?.examples, r), k(n.exampleConfigIssues, r);
259
- let i = n.jsonSchema;
260
- if (!i) return;
261
- e.manifestPath && o(e.manifestPath) && j(e.manifestPath, n, i);
262
- let a = E(i), s = n.manifest?.configVersion ?? null, l = n.manifest?.name ?? e.widgetName, u = o(e.hashFile) ? c(e.hashFile, "utf-8") : null;
263
- if (u !== null) {
264
- let t = u.trim(), n = null;
284
+ let i = n.jsonSchema, a = e.manifestPath && s(e.manifestPath) ? e.manifestPath : null;
285
+ i && a && ce(a, n, i);
286
+ let o = a ? JSON.parse(l(a, "utf-8")).capabilities : n.manifest?.capabilities;
287
+ if (M(l(e.outFile, "utf-8"), o ?? [], r), !i) return;
288
+ let c = ae(i), u = n.manifest?.configVersion ?? null, d = n.manifest?.name ?? e.widgetName, f = s(e.hashFile) ? l(e.hashFile, "utf-8") : null;
289
+ if (f !== null) {
290
+ let t = f.trim(), n = null;
265
291
  if (t.startsWith("{")) try {
266
292
  n = JSON.parse(t);
267
293
  } catch {
268
294
  n = null;
269
295
  }
270
- if (n && n.hashVersion === w) {
271
- if (n.hash !== a && n.configVersion === s) throw Error(`[widget-sdk] Config schema shape changed for "${l}" without a configVersion bump. Bump configVersion in defineWidget (currently ${s ?? "unset"}) or revert the schema change, then rebuild. Recorded in ${e.hashFile}`);
272
- } else console.warn(`[widget-sdk] Schema shape record for "${l}" was written by an older SDK, so it cannot be compared. Re-recording it under hash format ${w}. This build is not checked for a missing configVersion bump; the next one is. (${e.hashFile})`);
296
+ if (n && n.hashVersion === E) {
297
+ if (n.hash !== c && n.configVersion === u) throw Error(`[widget-sdk] Config schema shape changed for "${d}" without a configVersion bump. Bump configVersion in defineWidget (currently ${u ?? "unset"}) or revert the schema change, then rebuild. Recorded in ${e.hashFile}`);
298
+ } else console.warn(`[widget-sdk] Schema shape record for "${d}" was written by an older SDK, so it cannot be compared. Re-recording it under hash format ${E}. This build is not checked for a missing configVersion bump; the next one is. (${e.hashFile})`);
273
299
  }
274
- let d = `${JSON.stringify({
275
- hash: a,
276
- configVersion: s,
277
- hashVersion: w
300
+ let m = `${JSON.stringify({
301
+ hash: c,
302
+ configVersion: u,
303
+ hashVersion: E
278
304
  })}\n`;
279
- d !== u && f(e.hashFile, d);
305
+ m !== f && p(e.hashFile, m);
280
306
  }
281
- var oe = "virtual:glasshome-widget", N = "\0virtual:glasshome-widget", P = "/@glasshome/preview";
307
+ var de = "virtual:glasshome-widget", P = "\0virtual:glasshome-widget", fe = "/@glasshome/preview";
282
308
  function F(e) {
283
- return v === "\\" ? e.split(v).join("/") : e;
309
+ return y === "\\" ? e.split(y).join("/") : e;
284
310
  }
285
311
  function I() {
286
- let e = y(import.meta.url);
287
- return _(m(e), "../../preview");
312
+ let e = b(import.meta.url);
313
+ return v(h(e), "../../preview");
288
314
  }
289
315
  function L(e) {
290
316
  return r(e);
@@ -300,7 +326,7 @@ function V() {
300
326
  apply: "build",
301
327
  enforce: "pre",
302
328
  transform(e, t) {
303
- if (B(t, e)) throw Error(`Widgets must not import "@glasshome/sync-layer" directly (imported by ${F(g(process.cwd(), t.split("?")[0] ?? t))}). Import the equivalent hook from "@glasshome/widget-sdk" instead (e.g. useEntity, useEntities, useService).`);
329
+ if (B(t, e)) throw Error(`Widgets must not import "@glasshome/sync-layer" directly (imported by ${F(_(process.cwd(), t.split("?")[0] ?? t))}). Import the equivalent hook from "@glasshome/widget-sdk" instead (e.g. useEntity, useEntities, useService).`);
304
330
  return null;
305
331
  }
306
332
  };
@@ -315,7 +341,7 @@ function U(e = /* @__PURE__ */ new Set()) {
315
341
  let t = /* @__PURE__ */ new Set();
316
342
  return {
317
343
  scan(e, n) {
318
- H(e, n) && t.add(F(g(process.cwd(), e.split("?")[0] ?? e)));
344
+ H(e, n) && t.add(F(_(process.cwd(), e.split("?")[0] ?? e)));
319
345
  },
320
346
  take() {
321
347
  let n = [...t].filter((t) => !e.has(t));
@@ -341,15 +367,15 @@ function W(n) {
341
367
  }
342
368
  };
343
369
  }
344
- var G = "node_modules/.cache/glasshome-widgets";
345
- function K(e) {
370
+ var pe = "node_modules/.cache/glasshome-widgets";
371
+ function G(e) {
346
372
  try {
347
- return p(h(process.cwd(), "package.json")).resolve(e);
373
+ return m(g(process.cwd(), "package.json")).resolve(e);
348
374
  } catch {
349
375
  return null;
350
376
  }
351
377
  }
352
- var se = [
378
+ var me = [
353
379
  "--radius",
354
380
  "--background",
355
381
  "--foreground",
@@ -359,46 +385,50 @@ var se = [
359
385
  "--muted",
360
386
  "--accent"
361
387
  ];
362
- function q(e, t) {
363
- let n = h(e, `${t}.css`);
364
- if (!o(n)) return;
365
- let r = c(n, "utf-8");
388
+ function K(e, t) {
389
+ let n = g(e, `${t}.css`);
390
+ if (!s(n)) return;
391
+ let r = l(n, "utf-8");
366
392
  for (let e of r.matchAll(/:host[^{]*\{([^}]*)\}/g)) {
367
- let n = e[1] ?? "", r = se.find((e) => n.includes(`${e}:`));
393
+ let n = e[1] ?? "", r = me.find((e) => n.includes(`${e}:`));
368
394
  if (r) throw Error(`[glasshome-widget] "${t}.css" defines theme variable "${r}" on :host. Theme variables must inherit from the document so widgets follow the household theme — never re-scope them into the widget's shadow root.`);
369
395
  }
370
396
  }
371
- function J(e, t, n) {
372
- let r = _(e, G);
373
- s(r, { recursive: !0 });
374
- let i = K("@glasshome/ui/styles");
375
- if (!i) throw Error("[widget-sdk] @glasshome/ui is required to build widgets (it provides the theme every GlassHome widget ships with). Add it to your widget's dependencies.");
376
- let a = _(m(i), "../.."), c = K("@glasshome/widget-sdk/tailwind-sources"), l = c ? m(c) : null, u = [
377
- h(a, "src"),
378
- h(a, "dist"),
379
- ...l ? [h(l, "src"), h(l, "dist")] : [],
380
- m(n)
381
- ].filter((e) => o(e)), d = _(r, `${t}.tailwind.css`);
382
- f(d, [
397
+ function q(e, t) {
398
+ let n = v(e), r = h(t), i = new Set(Z(n).map((e) => h(e.entry)));
399
+ return [r, ...u(n, { withFileTypes: !0 }).filter((e) => e.isDirectory()).map((e) => g(n, e.name)).filter((e) => !i.has(e))];
400
+ }
401
+ function J(e, t, n, r) {
402
+ let i = v(e, pe);
403
+ c(i, { recursive: !0 });
404
+ let a = G("@glasshome/ui/styles");
405
+ if (!a) throw Error("[widget-sdk] @glasshome/ui is required to build widgets (it provides the theme every GlassHome widget ships with). Add it to your widget's dependencies.");
406
+ let o = v(h(a), "../.."), l = G("@glasshome/widget-sdk/tailwind-sources"), u = l ? h(l) : null, d = [
407
+ g(o, "src"),
408
+ g(o, "dist"),
409
+ ...u ? [g(u, "src"), g(u, "dist")] : [],
410
+ ...q(r, n)
411
+ ].filter((e) => s(e)), f = v(i, `${t}.tailwind.css`);
412
+ p(f, [
383
413
  "@import \"tailwindcss\" source(none);",
384
414
  "@import \"tw-animate-css\";",
385
415
  "@import \"@glasshome/ui/styles/theme\";",
386
- ...u.map((e) => `@source "${F(e)}";`),
416
+ ...d.map((e) => `@source "${F(e)}";`),
387
417
  "@custom-variant dark {",
388
418
  " &:is(.dark *) { @slot }",
389
419
  " :host(.dark) & { @slot }",
390
420
  "}",
391
421
  ""
392
422
  ].join("\n"));
393
- let p = _(r, `${t}.entry.ts`);
394
- return f(p, [
395
- `import "${F(d)}";`,
423
+ let m = v(i, `${t}.entry.ts`);
424
+ return p(m, [
425
+ `import "${F(f)}";`,
396
426
  `export { default } from "${F(n)}";`,
397
427
  ""
398
- ].join("\n")), p;
428
+ ].join("\n")), m;
399
429
  }
400
430
  function Y() {
401
- let { Features: e } = p(import.meta.url)("lightningcss");
431
+ let { Features: e } = m(import.meta.url)("lightningcss");
402
432
  return { lightningcss: { include: e.HexAlphaColors } };
403
433
  }
404
434
  function X() {
@@ -408,12 +438,12 @@ function X() {
408
438
  }
409
439
  function Z(e) {
410
440
  let t = [];
411
- if (!o(e)) return t;
412
- for (let n of l(e)) {
413
- let r = _(e, n);
414
- if (!d(r).isDirectory()) continue;
415
- let i = _(r, "index.tsx"), a = _(r, "manifest.json");
416
- o(i) && o(a) && t.push({
441
+ if (!s(e)) return t;
442
+ for (let n of u(e)) {
443
+ let r = v(e, n);
444
+ if (!f(r).isDirectory()) continue;
445
+ let i = v(r, "index.tsx"), a = v(r, "manifest.json");
446
+ s(i) && s(a) && t.push({
417
447
  name: n,
418
448
  entry: i
419
449
  });
@@ -422,29 +452,29 @@ function Z(e) {
422
452
  }
423
453
  function Q(e, t) {
424
454
  let r = [];
425
- if (o(e)) for (let a of l(e)) {
426
- if (!d(h(e, a)).isDirectory()) continue;
427
- let s = h(e, a, "manifest.json");
428
- if (!o(s)) continue;
429
- let l = i.safeParse(JSON.parse(c(s, "utf-8")));
430
- if (!l.success) throw Error(`[registry] Invalid manifest for "${a}": ${n(l.error)}`);
431
- let u = o(h(t, `${a}.css`));
455
+ if (s(e)) for (let i of u(e)) {
456
+ if (!f(g(e, i)).isDirectory()) continue;
457
+ let o = g(e, i, "manifest.json");
458
+ if (!s(o)) continue;
459
+ let c = a.safeParse(JSON.parse(l(o, "utf-8")));
460
+ if (!c.success) throw Error(`[registry] Invalid manifest for "${i}": ${n(c.error)}`);
461
+ let u = s(g(t, `${i}.css`));
432
462
  r.push({
433
- ...l.data,
434
- bundleUrl: `./${a}.js`,
435
- ...u ? { cssUrl: `./${a}.css` } : {}
463
+ ...c.data,
464
+ bundleUrl: `./${i}.js`,
465
+ ...u ? { cssUrl: `./${i}.css` } : {}
436
466
  });
437
467
  }
438
- let a = {
468
+ let i = {
439
469
  version: 1,
440
470
  generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
441
471
  baseUrl: "./",
442
472
  widgets: r
443
473
  };
444
- o(t) || s(t, { recursive: !0 }), f(h(t, "registry.json"), JSON.stringify(a, null, 2)), console.log(`[registry] Generated registry.json with ${r.length} widget(s)`);
474
+ s(t) || c(t, { recursive: !0 }), p(g(t, "registry.json"), JSON.stringify(i, null, 2)), console.log(`[registry] Generated registry.json with ${r.length} widget(s)`);
445
475
  }
446
476
  async function $(e) {
447
- let { build: t } = await import("vite"), n = process.cwd(), r = _(n, e?.srcDir ?? "src"), i = _(n, e?.outDir ?? "dist"), a = Z(r);
477
+ let { build: t } = await import("vite"), n = process.cwd(), r = v(n, e?.srcDir ?? "src"), i = v(n, e?.outDir ?? "dist"), a = Z(r);
448
478
  if (a.length === 0) {
449
479
  console.warn("[glasshome-widgets] No widgets found in", r);
450
480
  return;
@@ -453,16 +483,16 @@ async function $(e) {
453
483
  let t = new Set(e.only);
454
484
  a = a.filter((e) => t.has(e.name));
455
485
  }
456
- e?.only || o(i) && u(i, { recursive: !0 }), o(i) || s(i, { recursive: !0 });
457
- let c = /* @__PURE__ */ new Set();
458
- for (let r of a) await t({
486
+ e?.only || s(i) && d(i, { recursive: !0 }), s(i) || c(i, { recursive: !0 });
487
+ let o = /* @__PURE__ */ new Set();
488
+ for (let s of a) await t({
459
489
  configFile: !1,
460
490
  root: n,
461
491
  plugins: [
462
492
  ...X(),
463
493
  ...e?.plugins ?? [],
464
494
  V(),
465
- W(c)
495
+ W(o)
466
496
  ],
467
497
  ...e?.viteConfig,
468
498
  css: {
@@ -471,10 +501,10 @@ async function $(e) {
471
501
  },
472
502
  build: {
473
503
  lib: {
474
- entry: J(n, r.name, r.entry),
504
+ entry: J(n, s.name, s.entry, r),
475
505
  formats: ["es"],
476
- fileName: r.name,
477
- cssFileName: r.name
506
+ fileName: s.name,
507
+ cssFileName: s.name
478
508
  },
479
509
  rollupOptions: { external: L },
480
510
  outDir: i,
@@ -483,16 +513,16 @@ async function $(e) {
483
513
  ...e?.viteConfig?.build
484
514
  },
485
515
  logLevel: "warn"
486
- }), q(i, r.name), await M({
487
- outFile: h(i, `${r.name}.js`),
488
- hashFile: h(m(r.entry), ".schema-hash"),
489
- widgetName: r.name,
490
- manifestPath: h(m(r.entry), "manifest.json"),
516
+ }), K(i, s.name), await N({
517
+ outFile: g(i, `${s.name}.js`),
518
+ hashFile: g(h(s.entry), ".schema-hash"),
519
+ widgetName: s.name,
520
+ manifestPath: g(h(s.entry), "manifest.json"),
491
521
  session: e?.session
492
522
  });
493
523
  Q(r, i);
494
524
  }
495
- function ce(e) {
525
+ function he(e) {
496
526
  let t = e?.entry ?? "src/index.tsx", n = {
497
527
  name: "glasshome-widget:build",
498
528
  apply: "build",
@@ -502,7 +532,7 @@ function ce(e) {
502
532
  css: Y(),
503
533
  build: {
504
534
  lib: {
505
- entry: J(e, "index", _(e, t)),
535
+ entry: J(e, "index", v(e, t), h(v(e, t))),
506
536
  formats: ["es"],
507
537
  fileName: "index",
508
538
  cssFileName: "index"
@@ -520,14 +550,14 @@ function ce(e) {
520
550
  return { server: { fs: { allow: [
521
551
  e,
522
552
  t,
523
- _(t, "..", "..")
553
+ v(t, "..", "..")
524
554
  ] } } };
525
555
  },
526
556
  configureServer(e) {
527
- let t = I(), n = h(t, "preview.html");
557
+ let t = I(), n = g(t, "preview.html");
528
558
  e.middlewares.use(async (t, r, i) => {
529
559
  if (t.url === "/" || t.url === "/index.html") try {
530
- let i = c(n, "utf-8");
560
+ let i = l(n, "utf-8");
531
561
  i = await e.transformIndexHtml(t.url, i), r.setHeader("Content-Type", "text/html"), r.statusCode = 200, r.end(i);
532
562
  } catch (e) {
533
563
  i(e);
@@ -536,24 +566,24 @@ function ce(e) {
536
566
  });
537
567
  },
538
568
  resolveId(e) {
539
- if (e === P) {
569
+ if (e === fe) {
540
570
  let e = I();
541
- return F(h(e, "host.tsx"));
571
+ return F(g(e, "host.tsx"));
542
572
  }
543
- if (e === oe) return N;
573
+ if (e === de) return P;
544
574
  },
545
575
  load(e) {
546
- if (e === N) return `export { default } from "${F(_(process.cwd(), t))}";`;
576
+ if (e === P) return `export { default } from "${F(v(process.cwd(), t))}";`;
547
577
  }
548
578
  }, i = {
549
579
  name: "glasshome-widget:schema",
550
580
  apply: "build",
551
581
  async closeBundle() {
552
- q(_(process.cwd(), "dist"), "index"), await M({
553
- outFile: _(process.cwd(), "dist", "index.js"),
554
- hashFile: _(process.cwd(), ".schema-hash"),
582
+ K(v(process.cwd(), "dist"), "index"), await N({
583
+ outFile: v(process.cwd(), "dist", "index.js"),
584
+ hashFile: v(process.cwd(), ".schema-hash"),
555
585
  widgetName: "index",
556
- manifestPath: _(process.cwd(), "manifest.json")
586
+ manifestPath: v(process.cwd(), "manifest.json")
557
587
  });
558
588
  }
559
589
  };
@@ -566,7 +596,7 @@ function ce(e) {
566
596
  r
567
597
  ];
568
598
  }
569
- function le(e) {
599
+ function ge(e) {
570
600
  let t = e?.srcDir ?? "src", n = e?.outDir ?? "dist", r = [];
571
601
  return [{
572
602
  name: "glasshome-widgets:build",
@@ -594,4 +624,4 @@ function le(e) {
594
624
  }];
595
625
  }
596
626
  //#endregion
597
- export { D as MAX_EXAMPLES, $ as buildWidgets, C as createIntrospectSession, U as createUiImportTracker, Z as discoverWidgets, Q as generateRegistry, ce as glasshomeWidget, le as glasshomeWidgets, S as introspectOnce, B as isDirectSyncLayerImportSource, H as isDirectUiImportSource, L as isWidgetExternal, M as runSchemaGuard };
627
+ export { j as HOOK_READS, oe as MAX_EXAMPLES, M as assertHookReadsDeclared, $ as buildWidgets, ie as createIntrospectSession, U as createUiImportTracker, Z as discoverWidgets, Q as generateRegistry, he as glasshomeWidget, ge as glasshomeWidgets, T as introspectOnce, B as isDirectSyncLayerImportSource, H as isDirectUiImportSource, L as isWidgetExternal, N as runSchemaGuard, A as sdkImportsOf, q as widgetProjectScanDirs };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glasshome/widget-sdk",
3
- "version": "1.15.1",
3
+ "version": "1.17.0",
4
4
  "description": "SDK for building GlassHome dashboard widgets with SolidJS",
5
5
  "keywords": [
6
6
  "glasshome",
@@ -59,12 +59,12 @@
59
59
  "typecheck:test": "tsc --noEmit -p tsconfig.test.json"
60
60
  },
61
61
  "peerDependencies": {
62
- "@glasshome/sync-layer": "0.8.1",
63
- "@glasshome/ui": "1.14.0",
62
+ "@glasshome/sync-layer": "0.9.0",
63
+ "@glasshome/ui": "1.20.0",
64
64
  "solid-js": "^1.9.11"
65
65
  },
66
66
  "dependencies": {
67
- "@glasshome/widget-contract": "0.2.1",
67
+ "@glasshome/widget-contract": "0.3.0",
68
68
  "@modular-forms/solid": "^0.25.1",
69
69
  "@tailwindcss/vite": "^4.1.13",
70
70
  "clsx": "^2.1.1",
@@ -75,7 +75,7 @@
75
75
  "zod": "^4.1.13"
76
76
  },
77
77
  "devDependencies": {
78
- "@glasshome/ui": "1.14.0",
78
+ "@glasshome/ui": "1.20.0",
79
79
  "@solidjs/testing-library": "^0.8.10",
80
80
  "@types/bun": "^1.4.0",
81
81
  "@types/node": "^25.2.2",