@glasshome/widget-sdk 1.7.0 → 1.8.1
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/deprecations.js +8 -0
- package/dist/framework/config/index.d.ts +12 -0
- package/dist/framework/fields.d.ts +1 -1
- package/dist/index.js +22 -13
- package/dist/vite/index.d.ts +9 -1
- package/dist/vite/index.js +169 -117
- package/dist/vite/introspect.d.ts +27 -0
- package/dist/vite/introspect.js +37 -0
- package/package.json +5 -4
package/dist/deprecations.js
CHANGED
|
@@ -32,6 +32,14 @@ var e = "https://glasshome.app/docs/widget-sdk/config", t = [
|
|
|
32
32
|
docsUrl: e,
|
|
33
33
|
sourcePattern: "widgetFields\\.areaId\\b"
|
|
34
34
|
},
|
|
35
|
+
{
|
|
36
|
+
id: "area-by-field-name",
|
|
37
|
+
since: "1.8.0",
|
|
38
|
+
removeIn: "2.0.0",
|
|
39
|
+
replacement: "field.area()",
|
|
40
|
+
docsUrl: e,
|
|
41
|
+
sourcePattern: "\\bareaId\\s*:\\s*z\\.string\\("
|
|
42
|
+
},
|
|
35
43
|
{
|
|
36
44
|
id: "raw-zod-config",
|
|
37
45
|
since: "1.4.0",
|
|
@@ -71,6 +71,17 @@ declare function entity(domain: string, o?: EntitiesOpts): z.ZodDefault<z.ZodArr
|
|
|
71
71
|
declare function area(o?: {
|
|
72
72
|
title?: string;
|
|
73
73
|
}): z.ZodOptional<z.ZodString>;
|
|
74
|
+
/**
|
|
75
|
+
* Icon name (e.g. "mdi:lightbulb"). The host renders its icon picker; the
|
|
76
|
+
* widget only declares that this field is an icon.
|
|
77
|
+
*/
|
|
78
|
+
declare function icon(o: {
|
|
79
|
+
title?: string;
|
|
80
|
+
default: string;
|
|
81
|
+
}): z.ZodDefault<z.ZodString>;
|
|
82
|
+
declare function icon(o?: {
|
|
83
|
+
title?: string;
|
|
84
|
+
}): z.ZodOptional<z.ZodString>;
|
|
74
85
|
declare function stringList(o: {
|
|
75
86
|
title: string;
|
|
76
87
|
description?: string;
|
|
@@ -89,6 +100,7 @@ export declare const field: {
|
|
|
89
100
|
entities: typeof entities;
|
|
90
101
|
entity: typeof entity;
|
|
91
102
|
area: typeof area;
|
|
103
|
+
icon: typeof icon;
|
|
92
104
|
stringList: typeof stringList;
|
|
93
105
|
group: typeof group;
|
|
94
106
|
};
|
|
@@ -4,7 +4,7 @@ import { z } from "zod";
|
|
|
4
4
|
*
|
|
5
5
|
* @deprecated since 1.4.0, removed in 2.0.0. Use the config API instead:
|
|
6
6
|
* `defineConfig` + `field.*` (`field.title()`, `field.entities()`, `field.entity()`,
|
|
7
|
-
* `field.area()`). See https://glasshome.app/docs/widget-sdk/config
|
|
7
|
+
* `field.area()`, `field.icon()`). See https://glasshome.app/docs/widget-sdk/config
|
|
8
8
|
*/
|
|
9
9
|
export declare const widgetFields: {
|
|
10
10
|
/**
|
package/dist/index.js
CHANGED
|
@@ -1246,16 +1246,23 @@ function Xt(e) {
|
|
|
1246
1246
|
});
|
|
1247
1247
|
}
|
|
1248
1248
|
function Zt(e) {
|
|
1249
|
+
let t = l.string().meta({
|
|
1250
|
+
formType: "icon-picker",
|
|
1251
|
+
title: e?.title ?? "Icon"
|
|
1252
|
+
});
|
|
1253
|
+
return e?.default === void 0 ? t.optional() : t.default(e.default);
|
|
1254
|
+
}
|
|
1255
|
+
function Qt(e) {
|
|
1249
1256
|
return l.array(l.string()).default([]).meta($({
|
|
1250
1257
|
title: e.title,
|
|
1251
1258
|
description: e.description
|
|
1252
1259
|
}));
|
|
1253
1260
|
}
|
|
1254
|
-
function
|
|
1261
|
+
function $t(e, t) {
|
|
1255
1262
|
let n = l.object(e);
|
|
1256
1263
|
return n.default(Se(n)).meta({ title: t.title });
|
|
1257
1264
|
}
|
|
1258
|
-
var
|
|
1265
|
+
var en = {
|
|
1259
1266
|
title: Ut,
|
|
1260
1267
|
text: Wt,
|
|
1261
1268
|
number: Gt,
|
|
@@ -1264,15 +1271,16 @@ var $t = {
|
|
|
1264
1271
|
entities: Jt,
|
|
1265
1272
|
entity: Yt,
|
|
1266
1273
|
area: Xt,
|
|
1267
|
-
|
|
1268
|
-
|
|
1274
|
+
icon: Zt,
|
|
1275
|
+
stringList: Qt,
|
|
1276
|
+
group: $t
|
|
1269
1277
|
};
|
|
1270
|
-
function
|
|
1278
|
+
function tn(e) {
|
|
1271
1279
|
return l.object(e);
|
|
1272
1280
|
}
|
|
1273
1281
|
//#endregion
|
|
1274
1282
|
//#region src/shared/spline.ts
|
|
1275
|
-
function
|
|
1283
|
+
function nn(e) {
|
|
1276
1284
|
if (e.length < 2) return "";
|
|
1277
1285
|
let t = e[0], n = e[1];
|
|
1278
1286
|
if (!t || !n) return "";
|
|
@@ -1299,14 +1307,14 @@ function tn(e) {
|
|
|
1299
1307
|
}
|
|
1300
1308
|
//#endregion
|
|
1301
1309
|
//#region src/theme.ts
|
|
1302
|
-
function
|
|
1310
|
+
function rn() {
|
|
1303
1311
|
return document.documentElement.classList.contains("dark");
|
|
1304
1312
|
}
|
|
1305
1313
|
//#endregion
|
|
1306
1314
|
//#region src/version.ts
|
|
1307
|
-
var
|
|
1315
|
+
var an = {
|
|
1308
1316
|
name: "@glasshome/widget-sdk",
|
|
1309
|
-
version: "1.
|
|
1317
|
+
version: "1.8.1",
|
|
1310
1318
|
description: "SDK for building GlassHome dashboard widgets with SolidJS",
|
|
1311
1319
|
keywords: [
|
|
1312
1320
|
"glasshome",
|
|
@@ -1369,11 +1377,12 @@ var rn = {
|
|
|
1369
1377
|
dependencies: {
|
|
1370
1378
|
"@glasshome/widget-contract": "0.2.0",
|
|
1371
1379
|
"@modular-forms/solid": "^0.25.1",
|
|
1380
|
+
"@tailwindcss/vite": "^4.1.13",
|
|
1372
1381
|
clsx: "^2.1.1",
|
|
1382
|
+
"happy-dom": "^20.0.0",
|
|
1373
1383
|
"tailwind-merge": "^3.5.0",
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
tailwindcss: "^4.1.13"
|
|
1384
|
+
tailwindcss: "^4.1.13",
|
|
1385
|
+
zod: "^4.1.13"
|
|
1377
1386
|
},
|
|
1378
1387
|
devDependencies: {
|
|
1379
1388
|
"@types/bun": "latest",
|
|
@@ -1394,4 +1403,4 @@ var rn = {
|
|
|
1394
1403
|
engines: { node: ">=18" }
|
|
1395
1404
|
}.version;
|
|
1396
1405
|
//#endregion
|
|
1397
|
-
export {
|
|
1406
|
+
export { an as SDK_VERSION, Vt as ToneSchema, U as Widget, Pe as WidgetContent, e as WidgetCtx, Ct as WidgetDialog, Re as WidgetIcon, o as WidgetManifestSchema, Me as WidgetSliderFill, Be as WidgetStatus, Ue as WidgetTitle, tt as WidgetValue, ee as byDomain, We as calculateLightGroup, Ge as calculateSensorGroup, Xe as countActiveEntities, tn as defineConfig, Ce as defineWidget, i as deprecations, en as field, a as formatDeprecation, s as formatSchemaError, Ye as getEntityAttribute, u as getForecasts, d as getStream, f as getWebRtcClientConfig, p as hassMediaUrl, n as injectTokens, rn as isDark, Je as isEntityActive, nn as monotoneCubicPath, m as sendWebRtcCandidate, h as startWebRtcSession, g as state, Bt as svgColors, _ as trackEntityHistory, v as untrackEntityHistory, y as useArea, b as useCamera, te as useConnection, x as useCurrency, ne as useEntities, S as useEntity, re as useEntityHistory, ie as useEntityStatistics, C as useForecast, ae as useHassConfig, wt as useIntersectionPause, oe as useLocale, Tt as useReducedMotion, Te as useService, ce as useStore, le as useTemperatureUnit, Oe as useToggle, De as useTurnOff, Ee as useTurnOn, pe as useUnitSystem, t as useWidgetContext, Et as useWidgetDialog, Dt as useWidgetEntityGroup, Lt as useWidgetGestures, Ht as widgetFields, c as z };
|
package/dist/vite/index.d.ts
CHANGED
|
@@ -4,7 +4,15 @@ export interface GlasshomeWidgetOptions {
|
|
|
4
4
|
entry?: string;
|
|
5
5
|
}
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
7
|
+
* Most previews anyone will look at, and the ceiling the hub renders to.
|
|
8
|
+
*
|
|
9
|
+
* Declaring more than this used to mean the extras were quietly not rendered:
|
|
10
|
+
* the gallery looked complete and was not. Failing the build instead makes the
|
|
11
|
+
* author decide which states matter rather than discovering the loss never.
|
|
12
|
+
*/
|
|
13
|
+
export declare const MAX_EXAMPLES = 20;
|
|
14
|
+
/**
|
|
15
|
+
* Configuration-drift guard (D-11). Reads the built bundle, derives the JSON
|
|
8
16
|
* Schema from its configSchema, and compares against the recorded
|
|
9
17
|
* `.schema-hash`. A shape change without a configVersion bump fails the build:
|
|
10
18
|
* tsc cannot catch this class of break because the old persisted config still
|
package/dist/vite/index.js
CHANGED
|
@@ -1,63 +1,115 @@
|
|
|
1
1
|
import { formatSchemaError as e, isHostProvidedModule as t, widgetManifestSchema as n } from "@glasshome/widget-contract";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import _ from "
|
|
2
|
+
import { spawnSync as r } from "node:child_process";
|
|
3
|
+
import { createHash as i } from "node:crypto";
|
|
4
|
+
import { existsSync as a, mkdirSync as o, readFileSync as s, readdirSync as c, rmSync as l, statSync as u, writeFileSync as d } from "node:fs";
|
|
5
|
+
import { createRequire as f } from "node:module";
|
|
6
|
+
import { dirname as p, join as m, resolve as h, sep as g } from "node:path";
|
|
7
|
+
import { fileURLToPath as _ } from "node:url";
|
|
8
|
+
import v from "@tailwindcss/vite";
|
|
8
9
|
//#region src/vite/index.ts
|
|
9
|
-
function
|
|
10
|
+
function y(e) {
|
|
10
11
|
let t = JSON.stringify(e, Object.keys(e).sort());
|
|
11
|
-
return
|
|
12
|
+
return i("sha256").update(t).digest("hex").slice(0, 16);
|
|
12
13
|
}
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
var b = 20;
|
|
15
|
+
async function x(e, t) {
|
|
16
|
+
if (e === void 0) return;
|
|
17
|
+
let n;
|
|
16
18
|
try {
|
|
17
|
-
|
|
19
|
+
({z: n} = await import("zod"));
|
|
18
20
|
} catch {
|
|
19
21
|
return;
|
|
20
22
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
+
let r = n.number().int().positive(), i = n.array(n.object({
|
|
24
|
+
config: n.record(n.string(), n.unknown()),
|
|
25
|
+
size: n.object({
|
|
26
|
+
w: r,
|
|
27
|
+
h: r
|
|
28
|
+
}),
|
|
29
|
+
label: n.string().optional()
|
|
30
|
+
})).max(20).safeParse(e);
|
|
31
|
+
if (i.success) return;
|
|
32
|
+
let a = i.error.issues.map((e) => ` examples${e.path.length ? `[${e.path.join("][")}]` : ""}: ${e.message}`).join("\n");
|
|
33
|
+
throw Error(`[widget-sdk] Invalid \`examples\` for "${t}":\n${a}\nEach example needs a \`config\` object and a \`size\` of whole positive tiles, and at most 20 are rendered.`);
|
|
34
|
+
}
|
|
35
|
+
function S(e) {
|
|
36
|
+
let t = p(_(import.meta.url)), n = [m(t, "introspect.js"), m(t, "introspect.ts")].find((e) => a(e));
|
|
37
|
+
if (!n) return {
|
|
38
|
+
ok: !1,
|
|
39
|
+
reason: `introspect not found next to ${t}`
|
|
40
|
+
};
|
|
41
|
+
let i = r(process.execPath, [
|
|
42
|
+
"--conditions",
|
|
43
|
+
"browser",
|
|
44
|
+
n,
|
|
45
|
+
e
|
|
46
|
+
], {
|
|
47
|
+
encoding: "utf-8",
|
|
48
|
+
timeout: 3e4
|
|
49
|
+
});
|
|
50
|
+
if (i.error) return {
|
|
51
|
+
ok: !1,
|
|
52
|
+
reason: i.error.message
|
|
53
|
+
};
|
|
54
|
+
if (i.status !== 0) return {
|
|
55
|
+
ok: !1,
|
|
56
|
+
reason: (i.stderr || "").trim().split("\n")[0] || `exit ${i.status}`
|
|
57
|
+
};
|
|
23
58
|
try {
|
|
24
|
-
|
|
25
|
-
|
|
59
|
+
return {
|
|
60
|
+
ok: !0,
|
|
61
|
+
value: JSON.parse(i.stdout)
|
|
62
|
+
};
|
|
26
63
|
} catch {
|
|
64
|
+
return {
|
|
65
|
+
ok: !1,
|
|
66
|
+
reason: "introspect returned unparseable output"
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
async function C(e) {
|
|
71
|
+
if (!a(e.outFile)) return;
|
|
72
|
+
let t = S(e.outFile);
|
|
73
|
+
if (!t.ok) {
|
|
74
|
+
console.warn(`[widget-sdk] Could not read "${e.widgetName}" to check it: ${t.reason}\n Its examples and config schema were NOT validated.`);
|
|
27
75
|
return;
|
|
28
76
|
}
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
77
|
+
let n = t.value;
|
|
78
|
+
await x(n.manifest?.examples, n.manifest?.name ?? e.widgetName);
|
|
79
|
+
let r = n.jsonSchema;
|
|
80
|
+
if (!r) return;
|
|
81
|
+
if (e.manifestPath && a(e.manifestPath)) {
|
|
82
|
+
let t = JSON.parse(s(e.manifestPath, "utf-8"));
|
|
83
|
+
t.schema = r, d(e.manifestPath, JSON.stringify(t, null, 2));
|
|
32
84
|
}
|
|
33
|
-
let
|
|
34
|
-
if (
|
|
35
|
-
let t =
|
|
85
|
+
let i = y(r), o = n.manifest?.configVersion ?? null, c = n.manifest?.name ?? e.widgetName;
|
|
86
|
+
if (a(e.hashFile)) {
|
|
87
|
+
let t = s(e.hashFile, "utf-8").trim(), n = null;
|
|
36
88
|
if (t.startsWith("{")) try {
|
|
37
89
|
n = JSON.parse(t);
|
|
38
90
|
} catch {
|
|
39
91
|
n = null;
|
|
40
92
|
}
|
|
41
93
|
if (n) {
|
|
42
|
-
if (n.hash !==
|
|
43
|
-
} else t !==
|
|
94
|
+
if (n.hash !== i && n.configVersion === o) throw Error(`[widget-sdk] Config schema shape changed for "${c}" without a configVersion bump. Bump configVersion in defineWidget (currently ${o ?? "unset"}) or revert the schema change, then rebuild. Recorded in ${e.hashFile}`);
|
|
95
|
+
} else t !== i && console.warn(`[widget-sdk] Schema shape changed for "${c}" — verify configVersion was bumped`);
|
|
44
96
|
}
|
|
45
|
-
|
|
46
|
-
hash:
|
|
47
|
-
configVersion:
|
|
97
|
+
d(e.hashFile, `${JSON.stringify({
|
|
98
|
+
hash: i,
|
|
99
|
+
configVersion: o
|
|
48
100
|
})}\n`);
|
|
49
101
|
}
|
|
50
|
-
var
|
|
51
|
-
function
|
|
52
|
-
return
|
|
102
|
+
var w = "virtual:glasshome-widget", T = "\0virtual:glasshome-widget", E = "/@glasshome/preview";
|
|
103
|
+
function D(e) {
|
|
104
|
+
return g === "\\" ? e.split(g).join("/") : e;
|
|
53
105
|
}
|
|
54
|
-
function
|
|
55
|
-
return
|
|
106
|
+
function O() {
|
|
107
|
+
return h(p(_(import.meta.url)), "../../preview");
|
|
56
108
|
}
|
|
57
|
-
function
|
|
109
|
+
function k(e) {
|
|
58
110
|
return t(e);
|
|
59
111
|
}
|
|
60
|
-
function
|
|
112
|
+
function A() {
|
|
61
113
|
return {
|
|
62
114
|
name: "glasshome-widget:sync-layer-guard",
|
|
63
115
|
apply: "build",
|
|
@@ -67,15 +119,15 @@ function E() {
|
|
|
67
119
|
}
|
|
68
120
|
};
|
|
69
121
|
}
|
|
70
|
-
var
|
|
71
|
-
function
|
|
122
|
+
var j = "node_modules/.cache/glasshome-widgets";
|
|
123
|
+
function M(e) {
|
|
72
124
|
try {
|
|
73
|
-
return
|
|
125
|
+
return f(m(process.cwd(), "package.json")).resolve(e);
|
|
74
126
|
} catch {
|
|
75
127
|
return null;
|
|
76
128
|
}
|
|
77
129
|
}
|
|
78
|
-
var
|
|
130
|
+
var N = [
|
|
79
131
|
"--radius",
|
|
80
132
|
"--background",
|
|
81
133
|
"--foreground",
|
|
@@ -85,88 +137,88 @@ var k = [
|
|
|
85
137
|
"--muted",
|
|
86
138
|
"--accent"
|
|
87
139
|
];
|
|
88
|
-
function
|
|
89
|
-
let n =
|
|
90
|
-
if (!
|
|
91
|
-
let r =
|
|
140
|
+
function P(e, t) {
|
|
141
|
+
let n = m(e, `${t}.css`);
|
|
142
|
+
if (!a(n)) return;
|
|
143
|
+
let r = s(n, "utf-8");
|
|
92
144
|
for (let e of r.matchAll(/:host[^{]*\{([^}]*)\}/g)) {
|
|
93
|
-
let n = e[1] ?? "", r =
|
|
145
|
+
let n = e[1] ?? "", r = N.find((e) => n.includes(`${e}:`));
|
|
94
146
|
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.`);
|
|
95
147
|
}
|
|
96
148
|
}
|
|
97
|
-
function
|
|
98
|
-
let r =
|
|
99
|
-
|
|
100
|
-
let
|
|
101
|
-
if (!
|
|
102
|
-
let s =
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
...l ? [
|
|
106
|
-
|
|
107
|
-
].filter((e) =>
|
|
108
|
-
|
|
149
|
+
function F(e, t, n) {
|
|
150
|
+
let r = h(e, j);
|
|
151
|
+
o(r, { recursive: !0 });
|
|
152
|
+
let i = M("@glasshome/ui/styles");
|
|
153
|
+
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.");
|
|
154
|
+
let s = h(p(i), "../.."), c = M("@glasshome/widget-sdk/tailwind-sources"), l = c ? p(c) : null, u = [
|
|
155
|
+
m(s, "src"),
|
|
156
|
+
m(s, "dist"),
|
|
157
|
+
...l ? [m(l, "src"), m(l, "dist")] : [],
|
|
158
|
+
p(n)
|
|
159
|
+
].filter((e) => a(e)), f = h(r, `${t}.tailwind.css`);
|
|
160
|
+
d(f, [
|
|
109
161
|
"@import \"tailwindcss\" source(none);",
|
|
110
162
|
"@import \"tw-animate-css\";",
|
|
111
163
|
"@import \"@glasshome/ui/styles/theme\";",
|
|
112
|
-
...
|
|
164
|
+
...u.map((e) => `@source "${D(e)}";`),
|
|
113
165
|
"@custom-variant dark {",
|
|
114
166
|
" &:is(.dark *) { @slot }",
|
|
115
167
|
" :host(.dark) & { @slot }",
|
|
116
168
|
"}",
|
|
117
169
|
""
|
|
118
170
|
].join("\n"));
|
|
119
|
-
let g =
|
|
120
|
-
return
|
|
121
|
-
`import "${
|
|
122
|
-
`export { default } from "${
|
|
171
|
+
let g = h(r, `${t}.entry.ts`);
|
|
172
|
+
return d(g, [
|
|
173
|
+
`import "${D(f)}";`,
|
|
174
|
+
`export { default } from "${D(n)}";`,
|
|
123
175
|
""
|
|
124
176
|
].join("\n")), g;
|
|
125
177
|
}
|
|
126
|
-
function
|
|
127
|
-
let e =
|
|
178
|
+
function I() {
|
|
179
|
+
let e = v();
|
|
128
180
|
for (let t of e) t.apply ??= "build";
|
|
129
181
|
return e;
|
|
130
182
|
}
|
|
131
|
-
function
|
|
183
|
+
function L(e) {
|
|
132
184
|
let t = [];
|
|
133
|
-
if (!
|
|
134
|
-
for (let n of
|
|
135
|
-
let r =
|
|
136
|
-
if (!
|
|
137
|
-
let
|
|
138
|
-
i
|
|
185
|
+
if (!a(e)) return t;
|
|
186
|
+
for (let n of c(e)) {
|
|
187
|
+
let r = h(e, n);
|
|
188
|
+
if (!u(r).isDirectory()) continue;
|
|
189
|
+
let i = h(r, "index.tsx"), o = h(r, "manifest.json");
|
|
190
|
+
a(i) && a(o) && t.push({
|
|
139
191
|
name: n,
|
|
140
|
-
entry:
|
|
192
|
+
entry: i
|
|
141
193
|
});
|
|
142
194
|
}
|
|
143
195
|
return t;
|
|
144
196
|
}
|
|
145
|
-
function
|
|
146
|
-
let
|
|
147
|
-
if (
|
|
148
|
-
if (!
|
|
149
|
-
let
|
|
150
|
-
if (!
|
|
151
|
-
let
|
|
152
|
-
if (!
|
|
153
|
-
let d =
|
|
154
|
-
|
|
155
|
-
...
|
|
156
|
-
bundleUrl: `./${
|
|
157
|
-
...d ? { cssUrl: `./${
|
|
197
|
+
function R(t, r) {
|
|
198
|
+
let i = [];
|
|
199
|
+
if (a(t)) for (let o of c(t)) {
|
|
200
|
+
if (!u(m(t, o)).isDirectory()) continue;
|
|
201
|
+
let c = m(t, o, "manifest.json");
|
|
202
|
+
if (!a(c)) continue;
|
|
203
|
+
let l = n.safeParse(JSON.parse(s(c, "utf-8")));
|
|
204
|
+
if (!l.success) throw Error(`[registry] Invalid manifest for "${o}": ${e(l.error)}`);
|
|
205
|
+
let d = a(m(r, `${o}.css`));
|
|
206
|
+
i.push({
|
|
207
|
+
...l.data,
|
|
208
|
+
bundleUrl: `./${o}.js`,
|
|
209
|
+
...d ? { cssUrl: `./${o}.css` } : {}
|
|
158
210
|
});
|
|
159
211
|
}
|
|
160
|
-
let
|
|
212
|
+
let l = {
|
|
161
213
|
version: 1,
|
|
162
214
|
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
163
215
|
baseUrl: "./",
|
|
164
|
-
widgets:
|
|
216
|
+
widgets: i
|
|
165
217
|
};
|
|
166
|
-
|
|
218
|
+
a(r) || o(r, { recursive: !0 }), d(m(r, "registry.json"), JSON.stringify(l, null, 2)), console.log(`[registry] Generated registry.json with ${i.length} widget(s)`);
|
|
167
219
|
}
|
|
168
|
-
async function
|
|
169
|
-
let { build: t } = await import("vite"), n = process.cwd(), r =
|
|
220
|
+
async function z(e) {
|
|
221
|
+
let { build: t } = await import("vite"), n = process.cwd(), r = h(n, e?.srcDir ?? "src"), i = h(n, e?.outDir ?? "dist"), s = L(r);
|
|
170
222
|
if (s.length === 0) {
|
|
171
223
|
console.warn("[glasshome-widgets] No widgets found in", r);
|
|
172
224
|
return;
|
|
@@ -175,38 +227,38 @@ async function F(e) {
|
|
|
175
227
|
let t = new Set(e.only);
|
|
176
228
|
s = s.filter((e) => t.has(e.name));
|
|
177
229
|
}
|
|
178
|
-
e?.only || i
|
|
230
|
+
e?.only || a(i) && l(i, { recursive: !0 }), a(i) || o(i, { recursive: !0 });
|
|
179
231
|
for (let r of s) await t({
|
|
180
232
|
configFile: !1,
|
|
181
233
|
root: n,
|
|
182
234
|
plugins: [
|
|
183
|
-
...
|
|
235
|
+
...I(),
|
|
184
236
|
...e?.plugins ?? [],
|
|
185
|
-
|
|
237
|
+
A()
|
|
186
238
|
],
|
|
187
239
|
...e?.viteConfig,
|
|
188
240
|
build: {
|
|
189
241
|
lib: {
|
|
190
|
-
entry:
|
|
242
|
+
entry: F(n, r.name, r.entry),
|
|
191
243
|
formats: ["es"],
|
|
192
244
|
fileName: r.name,
|
|
193
245
|
cssFileName: r.name
|
|
194
246
|
},
|
|
195
|
-
rollupOptions: { external:
|
|
196
|
-
outDir:
|
|
247
|
+
rollupOptions: { external: k },
|
|
248
|
+
outDir: i,
|
|
197
249
|
emptyOutDir: !1,
|
|
198
250
|
copyPublicDir: !1,
|
|
199
251
|
...e?.viteConfig?.build
|
|
200
252
|
},
|
|
201
253
|
logLevel: "warn"
|
|
202
|
-
}),
|
|
203
|
-
outFile:
|
|
204
|
-
hashFile: p(
|
|
254
|
+
}), P(i, r.name), await C({
|
|
255
|
+
outFile: m(i, `${r.name}.js`),
|
|
256
|
+
hashFile: m(p(r.entry), ".schema-hash"),
|
|
205
257
|
widgetName: r.name
|
|
206
258
|
});
|
|
207
|
-
|
|
259
|
+
R(r, i);
|
|
208
260
|
}
|
|
209
|
-
function
|
|
261
|
+
function B(e) {
|
|
210
262
|
let t = e?.entry ?? "src/index.tsx", n = {
|
|
211
263
|
name: "glasshome-widget:build",
|
|
212
264
|
apply: "build",
|
|
@@ -214,12 +266,12 @@ function I(e) {
|
|
|
214
266
|
let e = process.cwd();
|
|
215
267
|
return { build: {
|
|
216
268
|
lib: {
|
|
217
|
-
entry:
|
|
269
|
+
entry: F(e, "index", h(e, t)),
|
|
218
270
|
formats: ["es"],
|
|
219
271
|
fileName: "index",
|
|
220
272
|
cssFileName: "index"
|
|
221
273
|
},
|
|
222
|
-
rollupOptions: { external:
|
|
274
|
+
rollupOptions: { external: k }
|
|
223
275
|
} };
|
|
224
276
|
}
|
|
225
277
|
}, r = {
|
|
@@ -227,18 +279,18 @@ function I(e) {
|
|
|
227
279
|
apply: "serve",
|
|
228
280
|
enforce: "pre",
|
|
229
281
|
config() {
|
|
230
|
-
let e =
|
|
282
|
+
let e = O(), t = process.cwd();
|
|
231
283
|
return { server: { fs: { allow: [
|
|
232
284
|
e,
|
|
233
285
|
t,
|
|
234
|
-
|
|
286
|
+
h(t, "..", "..")
|
|
235
287
|
] } } };
|
|
236
288
|
},
|
|
237
289
|
configureServer(e) {
|
|
238
|
-
let t =
|
|
290
|
+
let t = m(O(), "preview.html");
|
|
239
291
|
e.middlewares.use(async (n, r, i) => {
|
|
240
292
|
if (n.url === "/" || n.url === "/index.html") try {
|
|
241
|
-
let i =
|
|
293
|
+
let i = s(t, "utf-8");
|
|
242
294
|
i = await e.transformIndexHtml(n.url, i), r.setHeader("Content-Type", "text/html"), r.statusCode = 200, r.end(i);
|
|
243
295
|
} catch (e) {
|
|
244
296
|
i(e);
|
|
@@ -247,33 +299,33 @@ function I(e) {
|
|
|
247
299
|
});
|
|
248
300
|
},
|
|
249
301
|
resolveId(e) {
|
|
250
|
-
if (e ===
|
|
251
|
-
if (e ===
|
|
302
|
+
if (e === E) return D(m(O(), "host.tsx"));
|
|
303
|
+
if (e === w) return T;
|
|
252
304
|
},
|
|
253
305
|
load(e) {
|
|
254
|
-
if (e ===
|
|
306
|
+
if (e === T) return `export { default } from "${D(h(process.cwd(), t))}";`;
|
|
255
307
|
}
|
|
256
308
|
}, i = {
|
|
257
309
|
name: "glasshome-widget:schema",
|
|
258
310
|
apply: "build",
|
|
259
311
|
async closeBundle() {
|
|
260
|
-
|
|
261
|
-
outFile:
|
|
262
|
-
hashFile:
|
|
312
|
+
P(h(process.cwd(), "dist"), "index"), await C({
|
|
313
|
+
outFile: h(process.cwd(), "dist", "index.js"),
|
|
314
|
+
hashFile: h(process.cwd(), ".schema-hash"),
|
|
263
315
|
widgetName: "index",
|
|
264
|
-
manifestPath:
|
|
316
|
+
manifestPath: h(process.cwd(), "manifest.json")
|
|
265
317
|
});
|
|
266
318
|
}
|
|
267
319
|
};
|
|
268
320
|
return [
|
|
269
|
-
...
|
|
321
|
+
...I(),
|
|
270
322
|
n,
|
|
271
|
-
|
|
323
|
+
A(),
|
|
272
324
|
i,
|
|
273
325
|
r
|
|
274
326
|
];
|
|
275
327
|
}
|
|
276
|
-
function
|
|
328
|
+
function V(e) {
|
|
277
329
|
let t = e?.srcDir ?? "src", n = e?.outDir ?? "dist", r = [];
|
|
278
330
|
return [{
|
|
279
331
|
name: "glasshome-widgets:build",
|
|
@@ -292,7 +344,7 @@ function L(e) {
|
|
|
292
344
|
if (e === "\0glasshome-noop") return "export {}";
|
|
293
345
|
},
|
|
294
346
|
async closeBundle() {
|
|
295
|
-
await
|
|
347
|
+
await z({
|
|
296
348
|
srcDir: t,
|
|
297
349
|
outDir: n,
|
|
298
350
|
plugins: r
|
|
@@ -301,4 +353,4 @@ function L(e) {
|
|
|
301
353
|
}];
|
|
302
354
|
}
|
|
303
355
|
//#endregion
|
|
304
|
-
export {
|
|
356
|
+
export { b as MAX_EXAMPLES, z as buildWidgets, L as discoverWidgets, R as generateRegistry, B as glasshomeWidget, V as glasshomeWidgets, k as isWidgetExternal, C as runSchemaGuard };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads a built widget bundle's definition and prints it as JSON.
|
|
3
|
+
*
|
|
4
|
+
* Runs as its own process because a widget bundle cannot be imported by the
|
|
5
|
+
* build: `solid-js/web` resolves to its server build under Node's conditions
|
|
6
|
+
* and throws "Client-only API called on the server side" the moment the module
|
|
7
|
+
* initialises, and forcing browser conditions then needs a DOM for the
|
|
8
|
+
* templates Solid creates at import time. The build spawns this with
|
|
9
|
+
* `--conditions browser` and a DOM in place, so the import succeeds.
|
|
10
|
+
*
|
|
11
|
+
* Until this existed the guard swallowed that import failure and silently did
|
|
12
|
+
* nothing — for every widget, on every build.
|
|
13
|
+
*
|
|
14
|
+
* Usage: bun --conditions browser introspect.js <bundle.js>
|
|
15
|
+
* Prints: { manifest, jsonSchema } on stdout, or exits non-zero with a reason.
|
|
16
|
+
*/
|
|
17
|
+
interface Introspection {
|
|
18
|
+
manifest: {
|
|
19
|
+
name?: string;
|
|
20
|
+
configVersion?: number;
|
|
21
|
+
examples?: unknown;
|
|
22
|
+
} | null;
|
|
23
|
+
/** JSON Schema derived from the widget's configSchema, when it has one. */
|
|
24
|
+
jsonSchema: object | null;
|
|
25
|
+
}
|
|
26
|
+
declare function installDom(): Promise<void>;
|
|
27
|
+
declare function main(): Promise<void>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region src/vite/introspect.ts
|
|
2
|
+
async function e() {
|
|
3
|
+
let { Window: e } = await import("happy-dom"), t = new e({ url: "http://localhost" });
|
|
4
|
+
for (let e of [
|
|
5
|
+
"window",
|
|
6
|
+
"document",
|
|
7
|
+
"navigator",
|
|
8
|
+
"location",
|
|
9
|
+
"customElements",
|
|
10
|
+
"HTMLElement",
|
|
11
|
+
"Element",
|
|
12
|
+
"Node",
|
|
13
|
+
"CSS",
|
|
14
|
+
"getComputedStyle",
|
|
15
|
+
"requestAnimationFrame",
|
|
16
|
+
"cancelAnimationFrame",
|
|
17
|
+
"matchMedia"
|
|
18
|
+
]) globalThis[e] === void 0 && (globalThis[e] = t[e]);
|
|
19
|
+
}
|
|
20
|
+
async function t() {
|
|
21
|
+
let t = process.argv[2];
|
|
22
|
+
t || (process.stderr.write("introspect: no bundle path given\n"), process.exit(2)), await e();
|
|
23
|
+
let n = (await import(t)).default, r = null;
|
|
24
|
+
if (n?.configSchema) {
|
|
25
|
+
let { z: e } = await import("zod");
|
|
26
|
+
r = e.toJSONSchema(n.configSchema, { unrepresentable: "any" });
|
|
27
|
+
}
|
|
28
|
+
let i = {
|
|
29
|
+
manifest: n?.manifest ?? null,
|
|
30
|
+
jsonSchema: r
|
|
31
|
+
};
|
|
32
|
+
process.stdout.write(JSON.stringify(i));
|
|
33
|
+
}
|
|
34
|
+
t().catch((e) => {
|
|
35
|
+
process.stderr.write(`${e instanceof Error ? e.message : String(e)}\n`), process.exit(1);
|
|
36
|
+
});
|
|
37
|
+
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glasshome/widget-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.8.1",
|
|
4
4
|
"description": "SDK for building GlassHome dashboard widgets with SolidJS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"glasshome",
|
|
@@ -63,11 +63,12 @@
|
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"@glasshome/widget-contract": "0.2.0",
|
|
65
65
|
"@modular-forms/solid": "^0.25.1",
|
|
66
|
+
"@tailwindcss/vite": "^4.1.13",
|
|
66
67
|
"clsx": "^2.1.1",
|
|
68
|
+
"happy-dom": "^20.0.0",
|
|
67
69
|
"tailwind-merge": "^3.5.0",
|
|
68
|
-
"
|
|
69
|
-
"
|
|
70
|
-
"tailwindcss": "^4.1.13"
|
|
70
|
+
"tailwindcss": "^4.1.13",
|
|
71
|
+
"zod": "^4.1.13"
|
|
71
72
|
},
|
|
72
73
|
"devDependencies": {
|
|
73
74
|
"@types/bun": "latest",
|