@glasshome/widget-sdk 1.22.2 → 1.23.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/index.js +3 -3
- package/dist/vite/in-process-introspector.d.ts +2 -0
- package/dist/vite/index.d.ts +4 -1
- package/dist/vite/index.js +150 -130
- package/dist/vite/introspect-session.d.ts +13 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -3136,7 +3136,7 @@ function Co() {
|
|
|
3136
3136
|
//#region src/version.ts
|
|
3137
3137
|
var wo = {
|
|
3138
3138
|
name: "@glasshome/widget-sdk",
|
|
3139
|
-
version: "1.
|
|
3139
|
+
version: "1.23.0",
|
|
3140
3140
|
description: "SDK for building GlassHome dashboard widgets with SolidJS",
|
|
3141
3141
|
keywords: [
|
|
3142
3142
|
"dashboard",
|
|
@@ -3207,7 +3207,7 @@ var wo = {
|
|
|
3207
3207
|
lint: "oxlint --type-aware . && oxfmt --check ."
|
|
3208
3208
|
},
|
|
3209
3209
|
dependencies: {
|
|
3210
|
-
"@glasshome/widget-contract": "0.
|
|
3210
|
+
"@glasshome/widget-contract": "0.4.0",
|
|
3211
3211
|
"@tailwindcss/vite": "^4.1.13",
|
|
3212
3212
|
clsx: "^2.1.1",
|
|
3213
3213
|
"happy-dom": "^20.0.0",
|
|
@@ -3217,7 +3217,7 @@ var wo = {
|
|
|
3217
3217
|
zod: "^4.1.13"
|
|
3218
3218
|
},
|
|
3219
3219
|
devDependencies: {
|
|
3220
|
-
"@glasshome/ui": "1.
|
|
3220
|
+
"@glasshome/ui": "1.33.0",
|
|
3221
3221
|
"@solidjs/testing-library": "^0.8.10",
|
|
3222
3222
|
"@types/bun": "^1.4.0",
|
|
3223
3223
|
"@types/node": "^25.2.2",
|
package/dist/vite/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type CapabilityGrant } from "@glasshome/widget-contract";
|
|
2
2
|
import type { InlineConfig, Plugin } from "vite";
|
|
3
3
|
import type { ExampleConfigIssue, WidgetIntrospection } from "./introspect-core";
|
|
4
|
-
import { createIntrospectSession, type IntrospectSession, type IntrospectSessionOptions, introspectOnce } from "./introspect-session";
|
|
4
|
+
import { createIntrospectSession, type IntrospectResult, type IntrospectSession, type IntrospectSessionOptions, introspectOnce } from "./introspect-session";
|
|
5
5
|
export { createIntrospectSession, introspectOnce };
|
|
6
6
|
export type { ExampleConfigIssue, IntrospectSession, IntrospectSessionOptions, WidgetIntrospection, };
|
|
7
7
|
export interface GlasshomeWidgetOptions {
|
|
@@ -21,6 +21,7 @@ export declare function sdkImportsOf(code: string): Set<string>;
|
|
|
21
21
|
/** SDK hooks that read a fixed entity on the widget's behalf, so the widget must declare that read. */
|
|
22
22
|
export declare const HOOK_READS: Record<string, string>;
|
|
23
23
|
export declare function assertHookReadsDeclared(code: string, capabilities: readonly CapabilityGrant[], widgetName: string): void;
|
|
24
|
+
export type Introspector = (outFile: string) => IntrospectResult | Promise<IntrospectResult>;
|
|
24
25
|
export declare function runSchemaGuard(args: {
|
|
25
26
|
outFile: string;
|
|
26
27
|
hashFile: string;
|
|
@@ -28,6 +29,8 @@ export declare function runSchemaGuard(args: {
|
|
|
28
29
|
manifestPath?: string;
|
|
29
30
|
/** Persistent worker to reuse. Only `bun widget connect`'s watch loop passes one. */
|
|
30
31
|
session?: IntrospectSession;
|
|
32
|
+
/** Reads the bundle when no session is given. Defaults to one subprocess per call. */
|
|
33
|
+
introspect?: Introspector;
|
|
31
34
|
}): Promise<void>;
|
|
32
35
|
/**
|
|
33
36
|
* Packages provided by the host import map — widgets must not bundle these.
|
package/dist/vite/index.js
CHANGED
|
@@ -6,40 +6,46 @@ import { createRequire as m } from "node:module";
|
|
|
6
6
|
import { dirname as h, join as g, relative as _, resolve as v, sep as y } from "node:path";
|
|
7
7
|
import { fileURLToPath as b } from "node:url";
|
|
8
8
|
import ee from "@tailwindcss/vite";
|
|
9
|
-
import { spawn as te, spawnSync as
|
|
10
|
-
//#region
|
|
11
|
-
var
|
|
12
|
-
|
|
9
|
+
import { spawn as te, spawnSync as x } from "node:child_process";
|
|
10
|
+
//#region node_modules/@glasshome/widget-contract/dist/clock.mjs
|
|
11
|
+
var S = (e) => e, C = (e) => e, ne = {
|
|
12
|
+
now: () => Date.now(),
|
|
13
|
+
setTimeout: (e, t) => S(globalThis.setTimeout(e, t)),
|
|
14
|
+
clearTimeout: (e) => globalThis.clearTimeout(C(e)),
|
|
15
|
+
setInterval: (e, t) => S(globalThis.setInterval(e, t)),
|
|
16
|
+
clearInterval: (e) => globalThis.clearInterval(C(e))
|
|
17
|
+
}, re = 262144e3, w = 3e4, ie = 3e3;
|
|
18
|
+
function T(e) {
|
|
13
19
|
let t = h(b(import.meta.url));
|
|
14
20
|
return [g(t, `${e}.js`), g(t, `${e}.ts`)].find((e) => s(e)) ?? null;
|
|
15
21
|
}
|
|
16
|
-
function
|
|
17
|
-
let
|
|
18
|
-
if (!
|
|
22
|
+
function E(e, t) {
|
|
23
|
+
let n = T("introspect");
|
|
24
|
+
if (!n) return {
|
|
19
25
|
ok: !1,
|
|
20
26
|
reason: "introspect not found next to the sdk"
|
|
21
27
|
};
|
|
22
|
-
let
|
|
28
|
+
let r = x(process.execPath, [
|
|
23
29
|
"--conditions",
|
|
24
30
|
"browser",
|
|
25
|
-
|
|
31
|
+
n,
|
|
26
32
|
e
|
|
27
33
|
], {
|
|
28
34
|
encoding: "utf-8",
|
|
29
|
-
timeout:
|
|
35
|
+
timeout: t?.timeoutMs ?? w
|
|
30
36
|
});
|
|
31
|
-
if (
|
|
37
|
+
if (r.error) return {
|
|
32
38
|
ok: !1,
|
|
33
|
-
reason:
|
|
39
|
+
reason: r.error.message
|
|
34
40
|
};
|
|
35
|
-
if (
|
|
41
|
+
if (r.status !== 0) return {
|
|
36
42
|
ok: !1,
|
|
37
|
-
reason: (
|
|
43
|
+
reason: (r.stderr || "").trim().split("\n")[0] || `exit ${r.status}`
|
|
38
44
|
};
|
|
39
45
|
try {
|
|
40
46
|
return {
|
|
41
47
|
ok: !0,
|
|
42
|
-
value: JSON.parse(
|
|
48
|
+
value: JSON.parse(r.stdout)
|
|
43
49
|
};
|
|
44
50
|
} catch {
|
|
45
51
|
return {
|
|
@@ -48,27 +54,63 @@ function w(e) {
|
|
|
48
54
|
};
|
|
49
55
|
}
|
|
50
56
|
}
|
|
51
|
-
function
|
|
57
|
+
function ae(e) {
|
|
58
|
+
let t = te(process.execPath, [
|
|
59
|
+
"--conditions",
|
|
60
|
+
"browser",
|
|
61
|
+
e
|
|
62
|
+
], { stdio: [
|
|
63
|
+
"pipe",
|
|
64
|
+
"pipe",
|
|
65
|
+
"inherit"
|
|
66
|
+
] });
|
|
67
|
+
return {
|
|
68
|
+
write(e) {
|
|
69
|
+
return t.stdin?.writable ? (t.stdin.write(e), !0) : !1;
|
|
70
|
+
},
|
|
71
|
+
onLine(e) {
|
|
72
|
+
let n = "";
|
|
73
|
+
t.stdout?.setEncoding("utf-8"), t.stdout?.on("data", (t) => {
|
|
74
|
+
n += t;
|
|
75
|
+
let r = n.indexOf("\n");
|
|
76
|
+
for (; r >= 0;) {
|
|
77
|
+
let t = n.slice(0, r).trim();
|
|
78
|
+
n = n.slice(r + 1), t && e(t), r = n.indexOf("\n");
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
},
|
|
82
|
+
onExit(e) {
|
|
83
|
+
t.on("error", (t) => e(t.message)), t.on("exit", (t, n) => e(`introspect worker exited (${n ?? `code ${t}`})`));
|
|
84
|
+
},
|
|
85
|
+
kill() {
|
|
86
|
+
t.kill();
|
|
87
|
+
},
|
|
88
|
+
get pid() {
|
|
89
|
+
return t.pid ?? null;
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
function oe(e) {
|
|
52
94
|
return {
|
|
53
|
-
introspect: async (
|
|
95
|
+
introspect: async (t) => E(t, { timeoutMs: e }),
|
|
54
96
|
dispose: async () => {},
|
|
55
97
|
childPid: null
|
|
56
98
|
};
|
|
57
99
|
}
|
|
58
|
-
function
|
|
59
|
-
if (process.env.GLASSHOME_WIDGET_NO_WORKER === "1") return
|
|
60
|
-
let t = e?.rssLimitBytes ??
|
|
61
|
-
function
|
|
100
|
+
function se(e) {
|
|
101
|
+
if (process.env.GLASSHOME_WIDGET_NO_WORKER === "1") return oe(e?.timeoutMs);
|
|
102
|
+
let t = e?.rssLimitBytes ?? re, n = e?.timeoutMs ?? w, r = e?.slowMs ?? ie, i = e?.clock ?? ne, a = e?.spawnWorker ?? ae, o = null, s = !1, c = 0, l = Promise.resolve();
|
|
103
|
+
function u(e, t) {
|
|
62
104
|
for (let n of e.pending.values()) n({
|
|
63
105
|
ok: !1,
|
|
64
106
|
reason: t
|
|
65
107
|
});
|
|
66
108
|
e.pending.clear();
|
|
67
109
|
}
|
|
68
|
-
function
|
|
69
|
-
|
|
110
|
+
function d(e, t) {
|
|
111
|
+
o === e && (o = null), u(e, t), e.proc.kill();
|
|
70
112
|
}
|
|
71
|
-
function
|
|
113
|
+
function f(e, n) {
|
|
72
114
|
let i;
|
|
73
115
|
try {
|
|
74
116
|
i = JSON.parse(n);
|
|
@@ -85,56 +127,38 @@ function ae(e) {
|
|
|
85
127
|
reason: i.reason ?? "introspection failed"
|
|
86
128
|
}));
|
|
87
129
|
}
|
|
88
|
-
function
|
|
89
|
-
let t =
|
|
90
|
-
|
|
91
|
-
"browser",
|
|
92
|
-
e
|
|
93
|
-
], { stdio: [
|
|
94
|
-
"pipe",
|
|
95
|
-
"pipe",
|
|
96
|
-
"inherit"
|
|
97
|
-
] }), a = {
|
|
98
|
-
proc: n,
|
|
130
|
+
function p(e) {
|
|
131
|
+
let t = i.now(), n = {
|
|
132
|
+
proc: a(e),
|
|
99
133
|
ready: Promise.resolve(),
|
|
100
134
|
pending: /* @__PURE__ */ new Map(),
|
|
101
135
|
retireAfterRequest: !1
|
|
102
136
|
};
|
|
103
|
-
return
|
|
104
|
-
let s =
|
|
105
|
-
n.
|
|
106
|
-
s
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
let n = Date.now() - t;
|
|
114
|
-
n > r && console.warn(`[widget-sdk] introspect worker took ${n}ms to boot`), e();
|
|
115
|
-
} else u(a, n);
|
|
116
|
-
}
|
|
117
|
-
i = s.indexOf("\n");
|
|
118
|
-
}
|
|
137
|
+
return n.ready = new Promise((e, a) => {
|
|
138
|
+
let s = !1;
|
|
139
|
+
n.proc.onLine((a) => {
|
|
140
|
+
if (!s && a.includes("\"ready\"")) {
|
|
141
|
+
s = !0;
|
|
142
|
+
let n = i.now() - t;
|
|
143
|
+
n > r && console.warn(`[widget-sdk] introspect worker took ${n}ms to boot`), e();
|
|
144
|
+
} else f(n, a);
|
|
145
|
+
}), n.proc.onExit((e) => {
|
|
146
|
+
s || a(Error(e)), o === n && (o = null), u(n, e);
|
|
119
147
|
});
|
|
120
|
-
|
|
121
|
-
l || o(Error(e)), i === a && (i = null), c(a, e);
|
|
122
|
-
};
|
|
123
|
-
n.on("error", (e) => d(e.message)), n.on("exit", (e, t) => d(`introspect worker exited (${t ?? `code ${e}`})`));
|
|
124
|
-
}), a;
|
|
148
|
+
}), n;
|
|
125
149
|
}
|
|
126
|
-
async function
|
|
127
|
-
if (
|
|
150
|
+
async function m(e) {
|
|
151
|
+
if (s) return {
|
|
128
152
|
ok: !1,
|
|
129
153
|
reason: "introspect session disposed"
|
|
130
154
|
};
|
|
131
|
-
let t =
|
|
155
|
+
let t = T("introspect-worker");
|
|
132
156
|
if (!t) return {
|
|
133
157
|
ok: !1,
|
|
134
158
|
reason: "introspect-worker not found next to the sdk"
|
|
135
159
|
};
|
|
136
|
-
|
|
137
|
-
let r =
|
|
160
|
+
o?.retireAfterRequest && d(o, "worker was replaced");
|
|
161
|
+
let r = o ??= p(t);
|
|
138
162
|
try {
|
|
139
163
|
await r.ready;
|
|
140
164
|
} catch (e) {
|
|
@@ -143,28 +167,24 @@ function ae(e) {
|
|
|
143
167
|
reason: e instanceof Error ? e.message : String(e)
|
|
144
168
|
};
|
|
145
169
|
}
|
|
146
|
-
|
|
147
|
-
ok: !1,
|
|
148
|
-
reason: "introspect worker is not writable"
|
|
149
|
-
};
|
|
150
|
-
let s = ++o;
|
|
170
|
+
let a = ++c;
|
|
151
171
|
return new Promise((t) => {
|
|
152
|
-
let
|
|
153
|
-
r.pending.delete(
|
|
172
|
+
let o = i.setTimeout(() => {
|
|
173
|
+
r.pending.delete(a), d(r, `introspection timed out after ${n}ms`), t({
|
|
154
174
|
ok: !1,
|
|
155
175
|
reason: `introspection timed out after ${n}ms`
|
|
156
176
|
});
|
|
157
177
|
}, n);
|
|
158
|
-
r.pending.set(
|
|
159
|
-
clearTimeout(
|
|
178
|
+
r.pending.set(a, (e) => {
|
|
179
|
+
i.clearTimeout(o), t(e);
|
|
160
180
|
});
|
|
161
181
|
try {
|
|
162
|
-
r.proc.
|
|
163
|
-
id:
|
|
182
|
+
if (!r.proc.write(`${JSON.stringify({
|
|
183
|
+
id: a,
|
|
164
184
|
outFile: e
|
|
165
|
-
})}\n`);
|
|
185
|
+
})}\n`)) throw Error("introspect worker is not writable");
|
|
166
186
|
} catch (e) {
|
|
167
|
-
clearTimeout(
|
|
187
|
+
i.clearTimeout(o), r.pending.delete(a), r.retireAfterRequest = !0, t({
|
|
168
188
|
ok: !1,
|
|
169
189
|
reason: e instanceof Error ? e.message : String(e)
|
|
170
190
|
});
|
|
@@ -173,33 +193,33 @@ function ae(e) {
|
|
|
173
193
|
}
|
|
174
194
|
return {
|
|
175
195
|
introspect(e) {
|
|
176
|
-
let t =
|
|
177
|
-
return
|
|
196
|
+
let t = l.then(() => m(e));
|
|
197
|
+
return l = t.catch(() => void 0), t;
|
|
178
198
|
},
|
|
179
199
|
async dispose() {
|
|
180
|
-
|
|
200
|
+
s = !0, o && d(o, "introspect session disposed");
|
|
181
201
|
},
|
|
182
202
|
get childPid() {
|
|
183
|
-
return
|
|
203
|
+
return o?.proc.pid ?? null;
|
|
184
204
|
}
|
|
185
205
|
};
|
|
186
206
|
}
|
|
187
207
|
//#endregion
|
|
188
208
|
//#region src/vite/index.ts
|
|
189
|
-
var
|
|
190
|
-
function
|
|
191
|
-
if (Array.isArray(e)) return `[${e.map(
|
|
209
|
+
var D = 2;
|
|
210
|
+
function O(e) {
|
|
211
|
+
if (Array.isArray(e)) return `[${e.map(O).join(",")}]`;
|
|
192
212
|
if (typeof e == "object" && e) {
|
|
193
213
|
let t = e;
|
|
194
|
-
return `{${Object.keys(t).sort().filter((e) => t[e] !== void 0).map((e) => `${JSON.stringify(e)}:${
|
|
214
|
+
return `{${Object.keys(t).sort().filter((e) => t[e] !== void 0).map((e) => `${JSON.stringify(e)}:${O(t[e])}`).join(",")}}`;
|
|
195
215
|
}
|
|
196
216
|
return JSON.stringify(e) ?? "null";
|
|
197
217
|
}
|
|
198
|
-
function
|
|
199
|
-
return o("sha256").update(
|
|
218
|
+
function ce(e) {
|
|
219
|
+
return o("sha256").update(O(e)).digest("hex").slice(0, 16);
|
|
200
220
|
}
|
|
201
|
-
var
|
|
202
|
-
async function
|
|
221
|
+
var le = 20;
|
|
222
|
+
async function ue(e, t) {
|
|
203
223
|
if (e === void 0) return;
|
|
204
224
|
let n;
|
|
205
225
|
try {
|
|
@@ -219,7 +239,7 @@ async function D(e, t) {
|
|
|
219
239
|
let a = i.error.issues.map((e) => ` examples${e.path.length ? `[${e.path.join("][")}]` : ""}: ${e.message}`).join("\n");
|
|
220
240
|
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.`);
|
|
221
241
|
}
|
|
222
|
-
function
|
|
242
|
+
function de(e, t) {
|
|
223
243
|
if (!e?.length) return;
|
|
224
244
|
let n = e.map((e) => {
|
|
225
245
|
let t = e.label ? `"${e.label}"` : `#${e.index}`;
|
|
@@ -227,7 +247,7 @@ function O(e, t) {
|
|
|
227
247
|
}).join("\n");
|
|
228
248
|
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
249
|
}
|
|
230
|
-
var
|
|
250
|
+
var fe = [
|
|
231
251
|
"schema",
|
|
232
252
|
"defaultConfig",
|
|
233
253
|
"examples",
|
|
@@ -240,20 +260,20 @@ var ce = [
|
|
|
240
260
|
"minSize",
|
|
241
261
|
"maxSize"
|
|
242
262
|
];
|
|
243
|
-
function
|
|
263
|
+
function pe(e, t, n) {
|
|
244
264
|
let r = l(e, "utf-8"), i = JSON.parse(r), a = {
|
|
245
265
|
...t.manifest ?? {},
|
|
246
266
|
schema: n
|
|
247
267
|
};
|
|
248
|
-
for (let e of
|
|
268
|
+
for (let e of fe) a[e] !== void 0 && (i[e] = a[e]);
|
|
249
269
|
let o = `${JSON.stringify(i, null, 2)}\n`;
|
|
250
270
|
o !== r && p(e, o);
|
|
251
271
|
}
|
|
252
|
-
var
|
|
272
|
+
var me = /import\s*(\{[^}]*\}|\*\s*as\s+[\w$]+)\s*from\s*["']@glasshome\/widget-sdk["']/g, he = /import\(\s*["']@glasshome\/widget-sdk["']\s*\)/;
|
|
253
273
|
function k(e) {
|
|
254
274
|
let t = /* @__PURE__ */ new Set();
|
|
255
|
-
|
|
256
|
-
for (let [, n = ""] of e.matchAll(
|
|
275
|
+
he.test(e) && t.add("*");
|
|
276
|
+
for (let [, n = ""] of e.matchAll(me)) if (!n.startsWith("{")) t.add("*");
|
|
257
277
|
else for (let e of n.slice(1, -1).split(",")) {
|
|
258
278
|
let n = e.trim().split(/\s+as\s+/)[0];
|
|
259
279
|
n && t.add(n);
|
|
@@ -271,16 +291,16 @@ function j(e, t, n) {
|
|
|
271
291
|
}
|
|
272
292
|
async function M(e) {
|
|
273
293
|
if (!s(e.outFile)) return;
|
|
274
|
-
let t = e.session ? await e.session.introspect(e.outFile) :
|
|
294
|
+
let t = e.session ? await e.session.introspect(e.outFile) : await (e.introspect ?? E)(e.outFile);
|
|
275
295
|
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.
|
|
276
296
|
This usually means the bundle throws while being imported.`);
|
|
277
297
|
let n = t.value, r = n.manifest?.name ?? e.widgetName;
|
|
278
|
-
await
|
|
298
|
+
await ue(n.manifest?.examples, r), de(n.exampleConfigIssues, r);
|
|
279
299
|
let i = n.jsonSchema, a = e.manifestPath && s(e.manifestPath) ? e.manifestPath : null;
|
|
280
|
-
i && a &&
|
|
300
|
+
i && a && pe(a, n, i);
|
|
281
301
|
let o = a ? JSON.parse(l(a, "utf-8")).capabilities : n.manifest?.capabilities;
|
|
282
302
|
if (j(l(e.outFile, "utf-8"), o ?? [], r), !i) return;
|
|
283
|
-
let c =
|
|
303
|
+
let c = ce(i), u = n.manifest?.configVersion ?? null, d = n.manifest?.name ?? e.widgetName, f = s(e.hashFile) ? l(e.hashFile, "utf-8") : null;
|
|
284
304
|
if (f !== null) {
|
|
285
305
|
let t = f.trim(), n = null;
|
|
286
306
|
if (t.startsWith("{")) try {
|
|
@@ -288,32 +308,32 @@ async function M(e) {
|
|
|
288
308
|
} catch {
|
|
289
309
|
n = null;
|
|
290
310
|
}
|
|
291
|
-
if (n && n.hashVersion ===
|
|
311
|
+
if (n && n.hashVersion === D) {
|
|
292
312
|
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}`);
|
|
293
|
-
} 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 ${
|
|
313
|
+
} 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 ${D}. This build is not checked for a missing configVersion bump; the next one is. (${e.hashFile})`);
|
|
294
314
|
}
|
|
295
315
|
let m = `${JSON.stringify({
|
|
296
316
|
hash: c,
|
|
297
317
|
configVersion: u,
|
|
298
|
-
hashVersion:
|
|
318
|
+
hashVersion: D
|
|
299
319
|
})}\n`;
|
|
300
320
|
m !== f && p(e.hashFile, m);
|
|
301
321
|
}
|
|
302
|
-
var
|
|
303
|
-
function
|
|
322
|
+
var ge = "virtual:glasshome-widget", N = "\0virtual:glasshome-widget", P = "/@glasshome/preview";
|
|
323
|
+
function F(e) {
|
|
304
324
|
return y === "\\" ? e.split(y).join("/") : e;
|
|
305
325
|
}
|
|
306
|
-
function
|
|
326
|
+
function I() {
|
|
307
327
|
let e = b(import.meta.url);
|
|
308
328
|
return v(h(e), "../../preview");
|
|
309
329
|
}
|
|
310
|
-
function
|
|
330
|
+
function L(e) {
|
|
311
331
|
return r(e);
|
|
312
332
|
}
|
|
313
|
-
var
|
|
333
|
+
var R = /\.(ts|tsx|js|jsx)$/, _e = /from\s+["']@glasshome\/sync-layer(\/[^"']*)?["']/;
|
|
314
334
|
function z(e, t) {
|
|
315
|
-
let n =
|
|
316
|
-
return n.includes("/node_modules/") || !
|
|
335
|
+
let n = F(e).split("?")[0] ?? "";
|
|
336
|
+
return n.includes("/node_modules/") || !R.test(n) ? !1 : _e.test(t);
|
|
317
337
|
}
|
|
318
338
|
function B() {
|
|
319
339
|
return {
|
|
@@ -321,14 +341,14 @@ function B() {
|
|
|
321
341
|
apply: "build",
|
|
322
342
|
enforce: "pre",
|
|
323
343
|
transform(e, t) {
|
|
324
|
-
if (z(t, e)) throw Error(`Widgets must not import "@glasshome/sync-layer" directly (imported by ${
|
|
344
|
+
if (z(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).`);
|
|
325
345
|
return null;
|
|
326
346
|
}
|
|
327
347
|
};
|
|
328
348
|
}
|
|
329
349
|
function V(t, n) {
|
|
330
|
-
let r =
|
|
331
|
-
if (r.includes("/node_modules/") || !
|
|
350
|
+
let r = F(t).split("?")[0] ?? "";
|
|
351
|
+
if (r.includes("/node_modules/") || !R.test(r)) return !1;
|
|
332
352
|
let i = e.find((e) => e.id === "direct-ui-import");
|
|
333
353
|
return i?.sourcePattern ? new RegExp(i.sourcePattern).test(n) : !1;
|
|
334
354
|
}
|
|
@@ -336,7 +356,7 @@ function H(e = /* @__PURE__ */ new Set()) {
|
|
|
336
356
|
let t = /* @__PURE__ */ new Set();
|
|
337
357
|
return {
|
|
338
358
|
scan(e, n) {
|
|
339
|
-
V(e, n) && t.add(
|
|
359
|
+
V(e, n) && t.add(F(_(process.cwd(), e.split("?")[0] ?? e)));
|
|
340
360
|
},
|
|
341
361
|
take() {
|
|
342
362
|
let n = [...t].filter((t) => !e.has(t));
|
|
@@ -362,7 +382,7 @@ function U(n) {
|
|
|
362
382
|
}
|
|
363
383
|
};
|
|
364
384
|
}
|
|
365
|
-
var
|
|
385
|
+
var ve = "node_modules/.cache/glasshome-widgets";
|
|
366
386
|
function W(e) {
|
|
367
387
|
try {
|
|
368
388
|
return m(g(process.cwd(), "package.json")).resolve(e);
|
|
@@ -370,7 +390,7 @@ function W(e) {
|
|
|
370
390
|
return null;
|
|
371
391
|
}
|
|
372
392
|
}
|
|
373
|
-
var
|
|
393
|
+
var ye = [
|
|
374
394
|
"--radius",
|
|
375
395
|
"--background",
|
|
376
396
|
"--foreground",
|
|
@@ -389,7 +409,7 @@ function K(e, t) {
|
|
|
389
409
|
let r = l(n, "utf-8"), i = G(r);
|
|
390
410
|
i !== r && p(n, i);
|
|
391
411
|
for (let e of i.matchAll(/:host[^{]*\{([^}]*)\}/g)) {
|
|
392
|
-
let n = e[1] ?? "", r =
|
|
412
|
+
let n = e[1] ?? "", r = ye.find((e) => n.includes(`${e}:`));
|
|
393
413
|
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.`);
|
|
394
414
|
}
|
|
395
415
|
}
|
|
@@ -398,7 +418,7 @@ function q(e, t) {
|
|
|
398
418
|
return [r, ...u(n, { withFileTypes: !0 }).filter((e) => e.isDirectory()).map((e) => g(n, e.name)).filter((e) => !i.has(e))];
|
|
399
419
|
}
|
|
400
420
|
function J(e, t, n, r) {
|
|
401
|
-
let i = v(e,
|
|
421
|
+
let i = v(e, ve);
|
|
402
422
|
c(i, { recursive: !0 });
|
|
403
423
|
let a = W("@glasshome/ui/styles");
|
|
404
424
|
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.");
|
|
@@ -412,7 +432,7 @@ function J(e, t, n, r) {
|
|
|
412
432
|
"@import \"tailwindcss\" source(none);",
|
|
413
433
|
"@import \"tw-animate-css\";",
|
|
414
434
|
"@import \"@glasshome/ui/styles/theme\";",
|
|
415
|
-
...d.map((e) => `@source "${
|
|
435
|
+
...d.map((e) => `@source "${F(e)}";`),
|
|
416
436
|
"@custom-variant dark {",
|
|
417
437
|
" &:is(.dark *) { @slot }",
|
|
418
438
|
" :host(.dark) & { @slot }",
|
|
@@ -421,8 +441,8 @@ function J(e, t, n, r) {
|
|
|
421
441
|
].join("\n"));
|
|
422
442
|
let m = v(i, `${t}.entry.ts`);
|
|
423
443
|
return p(m, [
|
|
424
|
-
`import "${
|
|
425
|
-
`export { default } from "${
|
|
444
|
+
`import "${F(f)}";`,
|
|
445
|
+
`export { default } from "${F(n)}";`,
|
|
426
446
|
""
|
|
427
447
|
].join("\n")), m;
|
|
428
448
|
}
|
|
@@ -505,7 +525,7 @@ async function $(e) {
|
|
|
505
525
|
fileName: s.name,
|
|
506
526
|
cssFileName: s.name
|
|
507
527
|
},
|
|
508
|
-
rollupOptions: { external:
|
|
528
|
+
rollupOptions: { external: L },
|
|
509
529
|
outDir: i,
|
|
510
530
|
emptyOutDir: !1,
|
|
511
531
|
copyPublicDir: !1,
|
|
@@ -521,7 +541,7 @@ async function $(e) {
|
|
|
521
541
|
});
|
|
522
542
|
Q(r, i);
|
|
523
543
|
}
|
|
524
|
-
function
|
|
544
|
+
function be(e) {
|
|
525
545
|
let t = e?.entry ?? "src/index.tsx", n = {
|
|
526
546
|
name: "glasshome-widget:build",
|
|
527
547
|
apply: "build",
|
|
@@ -536,7 +556,7 @@ function ge(e) {
|
|
|
536
556
|
fileName: "index",
|
|
537
557
|
cssFileName: "index"
|
|
538
558
|
},
|
|
539
|
-
rollupOptions: { external:
|
|
559
|
+
rollupOptions: { external: L }
|
|
540
560
|
}
|
|
541
561
|
};
|
|
542
562
|
}
|
|
@@ -545,7 +565,7 @@ function ge(e) {
|
|
|
545
565
|
apply: "serve",
|
|
546
566
|
enforce: "pre",
|
|
547
567
|
config() {
|
|
548
|
-
let e =
|
|
568
|
+
let e = I(), t = process.cwd();
|
|
549
569
|
return { server: { fs: { allow: [
|
|
550
570
|
e,
|
|
551
571
|
t,
|
|
@@ -553,7 +573,7 @@ function ge(e) {
|
|
|
553
573
|
] } } };
|
|
554
574
|
},
|
|
555
575
|
configureServer(e) {
|
|
556
|
-
let t =
|
|
576
|
+
let t = I(), n = g(t, "preview.html");
|
|
557
577
|
e.middlewares.use(async (t, r, i) => {
|
|
558
578
|
if (t.url === "/" || t.url === "/index.html") try {
|
|
559
579
|
let i = l(n, "utf-8");
|
|
@@ -565,14 +585,14 @@ function ge(e) {
|
|
|
565
585
|
});
|
|
566
586
|
},
|
|
567
587
|
resolveId(e) {
|
|
568
|
-
if (e ===
|
|
569
|
-
let e =
|
|
570
|
-
return
|
|
588
|
+
if (e === P) {
|
|
589
|
+
let e = I();
|
|
590
|
+
return F(g(e, "host.tsx"));
|
|
571
591
|
}
|
|
572
|
-
if (e ===
|
|
592
|
+
if (e === ge) return N;
|
|
573
593
|
},
|
|
574
594
|
load(e) {
|
|
575
|
-
if (e === N) return `export { default } from "${
|
|
595
|
+
if (e === N) return `export { default } from "${F(v(process.cwd(), t))}";`;
|
|
576
596
|
}
|
|
577
597
|
}, i = {
|
|
578
598
|
name: "glasshome-widget:schema",
|
|
@@ -595,7 +615,7 @@ function ge(e) {
|
|
|
595
615
|
r
|
|
596
616
|
];
|
|
597
617
|
}
|
|
598
|
-
function
|
|
618
|
+
function xe(e) {
|
|
599
619
|
let t = e?.srcDir ?? "src", n = e?.outDir ?? "dist", r = [];
|
|
600
620
|
return [{
|
|
601
621
|
name: "glasshome-widgets:build",
|
|
@@ -623,4 +643,4 @@ function _e(e) {
|
|
|
623
643
|
}];
|
|
624
644
|
}
|
|
625
645
|
//#endregion
|
|
626
|
-
export { A as HOOK_READS,
|
|
646
|
+
export { A as HOOK_READS, le as MAX_EXAMPLES, j as assertHookReadsDeclared, $ as buildWidgets, se as createIntrospectSession, H as createUiImportTracker, Z as discoverWidgets, G as dropSelfReferencingVars, Q as generateRegistry, be as glasshomeWidget, xe as glasshomeWidgets, E as introspectOnce, z as isDirectSyncLayerImportSource, V as isDirectUiImportSource, L as isWidgetExternal, M as runSchemaGuard, k as sdkImportsOf, q as widgetProjectScanDirs };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Clock } from "@glasshome/widget-contract/clock";
|
|
1
2
|
import type { WidgetIntrospection } from "./introspect-core";
|
|
2
3
|
export type IntrospectResult = {
|
|
3
4
|
ok: true;
|
|
@@ -13,6 +14,15 @@ export interface IntrospectSessionOptions {
|
|
|
13
14
|
timeoutMs?: number;
|
|
14
15
|
/** Log spawn and import durations above this. */
|
|
15
16
|
slowMs?: number;
|
|
17
|
+
clock?: Clock;
|
|
18
|
+
spawnWorker?: (probe: string) => WorkerTransport;
|
|
19
|
+
}
|
|
20
|
+
export interface WorkerTransport {
|
|
21
|
+
write(line: string): boolean;
|
|
22
|
+
onLine(cb: (line: string) => void): void;
|
|
23
|
+
onExit(cb: (reason: string) => void): void;
|
|
24
|
+
kill(): void;
|
|
25
|
+
readonly pid: number | null;
|
|
16
26
|
}
|
|
17
27
|
export interface IntrospectSession {
|
|
18
28
|
introspect(outFile: string): Promise<IntrospectResult>;
|
|
@@ -20,7 +30,9 @@ export interface IntrospectSession {
|
|
|
20
30
|
readonly childPid: number | null;
|
|
21
31
|
}
|
|
22
32
|
/** One process per check. The path `build`, `capture` and the fallback take. */
|
|
23
|
-
export declare function introspectOnce(outFile: string
|
|
33
|
+
export declare function introspectOnce(outFile: string, options?: {
|
|
34
|
+
timeoutMs?: number;
|
|
35
|
+
}): IntrospectResult;
|
|
24
36
|
/**
|
|
25
37
|
* A worker reused across rebuilds, for callers that own a session.
|
|
26
38
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glasshome/widget-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.23.0",
|
|
4
4
|
"description": "SDK for building GlassHome dashboard widgets with SolidJS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dashboard",
|
|
@@ -75,7 +75,7 @@
|
|
|
75
75
|
"lint": "oxlint --type-aware . && oxfmt --check ."
|
|
76
76
|
},
|
|
77
77
|
"dependencies": {
|
|
78
|
-
"@glasshome/widget-contract": "0.
|
|
78
|
+
"@glasshome/widget-contract": "0.4.0",
|
|
79
79
|
"@tailwindcss/vite": "^4.1.13",
|
|
80
80
|
"clsx": "^2.1.1",
|
|
81
81
|
"happy-dom": "^20.0.0",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
"zod": "^4.1.13"
|
|
86
86
|
},
|
|
87
87
|
"devDependencies": {
|
|
88
|
-
"@glasshome/ui": "1.
|
|
88
|
+
"@glasshome/ui": "1.33.0",
|
|
89
89
|
"@solidjs/testing-library": "^0.8.10",
|
|
90
90
|
"@types/bun": "^1.4.0",
|
|
91
91
|
"@types/node": "^25.2.2",
|