@glasshome/widget-sdk 1.10.2 → 1.11.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/README.md +6 -0
- package/dist/index.js +1 -2
- package/dist/introspect-core-DYv9Uufi.js +72 -0
- package/dist/vite/fixtures/orphan-parent.d.ts +1 -0
- package/dist/vite/index.d.ts +8 -1
- package/dist/vite/index.js +305 -165
- package/dist/vite/introspect-core.d.ts +33 -0
- package/dist/vite/introspect-session.d.ts +30 -0
- package/dist/vite/introspect-worker.d.ts +10 -0
- package/dist/vite/introspect-worker.js +76 -0
- package/dist/vite/introspect.d.ts +6 -15
- package/dist/vite/introspect.js +4 -53
- package/package.json +1 -6
package/README.md
CHANGED
|
@@ -86,6 +86,12 @@ The `area` widget renders quick-glance metric pills (CO2 traffic-light, humidity
|
|
|
86
86
|
|
|
87
87
|
If your widget needs full visual control (a chart, a video stream, a custom animated surface), follow these patterns: keep the `<Widget>` shell neutral (no `tone`/`color`), place your custom DOM inside `<Widget.Content>`, and document the choice in the widget's README.
|
|
88
88
|
|
|
89
|
+
## Troubleshooting
|
|
90
|
+
|
|
91
|
+
| Variable | Effect |
|
|
92
|
+
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
93
|
+
| `GLASSHOME_WIDGET_NO_WORKER` | Set to `1` to make `bun widget connect` check each rebuild in a fresh process again, instead of reusing one worker for the session. |
|
|
94
|
+
|
|
89
95
|
## Peer Dependencies
|
|
90
96
|
|
|
91
97
|
| Package | Required | Notes |
|
package/dist/index.js
CHANGED
|
@@ -1451,7 +1451,7 @@ function Un() {
|
|
|
1451
1451
|
//#region src/version.ts
|
|
1452
1452
|
var Wn = {
|
|
1453
1453
|
name: "@glasshome/widget-sdk",
|
|
1454
|
-
version: "1.
|
|
1454
|
+
version: "1.11.0",
|
|
1455
1455
|
description: "SDK for building GlassHome dashboard widgets with SolidJS",
|
|
1456
1456
|
keywords: [
|
|
1457
1457
|
"glasshome",
|
|
@@ -1514,7 +1514,6 @@ var Wn = {
|
|
|
1514
1514
|
"@glasshome/ui": "1.3.0",
|
|
1515
1515
|
"solid-js": "^1.9.11"
|
|
1516
1516
|
},
|
|
1517
|
-
peerDependenciesMeta: { "@glasshome/ui": { optional: !0 } },
|
|
1518
1517
|
dependencies: {
|
|
1519
1518
|
"@glasshome/widget-contract": "0.2.0",
|
|
1520
1519
|
"@modular-forms/solid": "^0.25.1",
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { copyFileSync as e, rmSync as t } from "node:fs";
|
|
2
|
+
import { pathToFileURL as n } from "node:url";
|
|
3
|
+
//#region src/vite/introspect-core.ts
|
|
4
|
+
function r(e) {
|
|
5
|
+
return typeof e?.safeParse == "function";
|
|
6
|
+
}
|
|
7
|
+
function i(e, t) {
|
|
8
|
+
if (!r(e) || !Array.isArray(t)) return [];
|
|
9
|
+
let n = [];
|
|
10
|
+
for (let [r, i] of t.entries()) {
|
|
11
|
+
let t = i?.config;
|
|
12
|
+
if (typeof t != "object" || !t) continue;
|
|
13
|
+
let a = e.safeParse(t);
|
|
14
|
+
a.success || n.push({
|
|
15
|
+
index: r,
|
|
16
|
+
label: i.label,
|
|
17
|
+
problems: (a.error?.issues ?? []).map((e) => {
|
|
18
|
+
let t = e.path.map(String).join(".");
|
|
19
|
+
return t ? `${t}: ${e.message}` : e.message;
|
|
20
|
+
})
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
return n;
|
|
24
|
+
}
|
|
25
|
+
var a = [
|
|
26
|
+
"window",
|
|
27
|
+
"document",
|
|
28
|
+
"navigator",
|
|
29
|
+
"location",
|
|
30
|
+
"customElements",
|
|
31
|
+
"HTMLElement",
|
|
32
|
+
"Element",
|
|
33
|
+
"Node",
|
|
34
|
+
"CSS",
|
|
35
|
+
"getComputedStyle",
|
|
36
|
+
"requestAnimationFrame",
|
|
37
|
+
"cancelAnimationFrame",
|
|
38
|
+
"matchMedia"
|
|
39
|
+
];
|
|
40
|
+
async function o() {
|
|
41
|
+
let { Window: e } = await import("happy-dom"), t = new e({ url: "http://localhost" });
|
|
42
|
+
for (let e of a) try {
|
|
43
|
+
Object.defineProperty(globalThis, e, {
|
|
44
|
+
value: t[e],
|
|
45
|
+
configurable: !0,
|
|
46
|
+
writable: !0
|
|
47
|
+
});
|
|
48
|
+
} catch {}
|
|
49
|
+
}
|
|
50
|
+
async function s(r, i) {
|
|
51
|
+
let a = `${r}.introspect-${i}.mjs`;
|
|
52
|
+
e(r, a);
|
|
53
|
+
try {
|
|
54
|
+
return await import(n(a).href);
|
|
55
|
+
} finally {
|
|
56
|
+
t(a, { force: !0 });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function c(e, t) {
|
|
60
|
+
let r = (t ? await s(e, t) : await import(n(e).href)).default, a = null;
|
|
61
|
+
if (r?.configSchema) {
|
|
62
|
+
let { z: e } = await import("zod");
|
|
63
|
+
a = e.toJSONSchema(r.configSchema, { unrepresentable: "any" });
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
manifest: r?.manifest ?? null,
|
|
67
|
+
jsonSchema: a,
|
|
68
|
+
exampleConfigIssues: i(r?.configSchema, r?.manifest?.examples)
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
//#endregion
|
|
72
|
+
export { c as n, o as t };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/vite/index.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import type { InlineConfig, Plugin } from "vite";
|
|
2
|
+
import type { ExampleConfigIssue, WidgetIntrospection } from "./introspect-core";
|
|
3
|
+
import { createIntrospectSession, type IntrospectSession, type IntrospectSessionOptions, introspectOnce } from "./introspect-session";
|
|
4
|
+
export { createIntrospectSession, introspectOnce };
|
|
5
|
+
export type { ExampleConfigIssue, IntrospectSession, IntrospectSessionOptions, WidgetIntrospection, };
|
|
2
6
|
export interface GlasshomeWidgetOptions {
|
|
3
7
|
/** Entry file for the widget (default: "src/index.tsx") */
|
|
4
8
|
entry?: string;
|
|
@@ -16,6 +20,8 @@ export declare function runSchemaGuard(args: {
|
|
|
16
20
|
hashFile: string;
|
|
17
21
|
widgetName: string;
|
|
18
22
|
manifestPath?: string;
|
|
23
|
+
/** Persistent worker to reuse. Only `bun widget connect`'s watch loop passes one. */
|
|
24
|
+
session?: IntrospectSession;
|
|
19
25
|
}): Promise<void>;
|
|
20
26
|
/**
|
|
21
27
|
* Packages provided by the host import map — widgets must not bundle these.
|
|
@@ -74,6 +80,8 @@ export interface BuildWidgetsOptions {
|
|
|
74
80
|
viteConfig?: InlineConfig;
|
|
75
81
|
/** Build only these widget names (subdirectory names). Skips full clean. */
|
|
76
82
|
only?: string[];
|
|
83
|
+
/** Persistent introspection worker to reuse across rebuilds. */
|
|
84
|
+
session?: IntrospectSession;
|
|
77
85
|
}
|
|
78
86
|
/**
|
|
79
87
|
* Build each widget as a separate Vite invocation so shared code is inlined
|
|
@@ -103,4 +111,3 @@ export interface GlasshomeWidgetsOptions {
|
|
|
103
111
|
* default build, and `closeBundle()` runs the actual per-widget builds.
|
|
104
112
|
*/
|
|
105
113
|
export declare function glasshomeWidgets(options?: GlasshomeWidgetsOptions): Plugin[];
|
|
106
|
-
export {};
|
package/dist/vite/index.js
CHANGED
|
@@ -1,19 +1,193 @@
|
|
|
1
1
|
import { deprecations as e, formatDeprecation as t } from "../deprecations.js";
|
|
2
2
|
import { formatSchemaError as n, isHostProvidedModule as r, widgetManifestSchema as i } from "@glasshome/widget-contract";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import
|
|
9
|
-
import x from "
|
|
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";
|
|
8
|
+
import ee from "@tailwindcss/vite";
|
|
9
|
+
import { spawn as b, spawnSync as x } from "node:child_process";
|
|
10
|
+
//#region src/vite/introspect-session.ts
|
|
11
|
+
var te = 262144e3, S = 3e4, C = 3e3;
|
|
12
|
+
function w(e) {
|
|
13
|
+
let t = m(y(import.meta.url));
|
|
14
|
+
return [h(t, `${e}.js`), h(t, `${e}.ts`)].find((e) => o(e)) ?? null;
|
|
15
|
+
}
|
|
16
|
+
function T(e) {
|
|
17
|
+
let t = w("introspect");
|
|
18
|
+
if (!t) return {
|
|
19
|
+
ok: !1,
|
|
20
|
+
reason: "introspect not found next to the sdk"
|
|
21
|
+
};
|
|
22
|
+
let n = x(process.execPath, [
|
|
23
|
+
"--conditions",
|
|
24
|
+
"browser",
|
|
25
|
+
t,
|
|
26
|
+
e
|
|
27
|
+
], {
|
|
28
|
+
encoding: "utf-8",
|
|
29
|
+
timeout: S
|
|
30
|
+
});
|
|
31
|
+
if (n.error) return {
|
|
32
|
+
ok: !1,
|
|
33
|
+
reason: n.error.message
|
|
34
|
+
};
|
|
35
|
+
if (n.status !== 0) return {
|
|
36
|
+
ok: !1,
|
|
37
|
+
reason: (n.stderr || "").trim().split("\n")[0] || `exit ${n.status}`
|
|
38
|
+
};
|
|
39
|
+
try {
|
|
40
|
+
return {
|
|
41
|
+
ok: !0,
|
|
42
|
+
value: JSON.parse(n.stdout)
|
|
43
|
+
};
|
|
44
|
+
} catch {
|
|
45
|
+
return {
|
|
46
|
+
ok: !1,
|
|
47
|
+
reason: "introspect returned unparseable output"
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function ne() {
|
|
52
|
+
return {
|
|
53
|
+
introspect: async (e) => T(e),
|
|
54
|
+
dispose: async () => {},
|
|
55
|
+
childPid: null
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function re(e) {
|
|
59
|
+
if (process.env.GLASSHOME_WIDGET_NO_WORKER === "1") return ne();
|
|
60
|
+
let t = e?.rssLimitBytes ?? te, n = e?.timeoutMs ?? S, r = e?.slowMs ?? C, i = null, a = null, o = !1, s = !1, c = 0, l = Promise.resolve(), u = /* @__PURE__ */ new Map();
|
|
61
|
+
function d(e) {
|
|
62
|
+
for (let t of u.values()) t({
|
|
63
|
+
ok: !1,
|
|
64
|
+
reason: e
|
|
65
|
+
});
|
|
66
|
+
u.clear();
|
|
67
|
+
}
|
|
68
|
+
function f(e) {
|
|
69
|
+
let t = i;
|
|
70
|
+
i = null, a = null, o = !1, d(e), t?.kill();
|
|
71
|
+
}
|
|
72
|
+
function p(e) {
|
|
73
|
+
let n;
|
|
74
|
+
try {
|
|
75
|
+
n = JSON.parse(e);
|
|
76
|
+
} catch {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (typeof n.id != "number") return;
|
|
80
|
+
let i = u.get(n.id);
|
|
81
|
+
i && (u.delete(n.id), (n.rss ?? 0) > t && (o = !0), (n.importMs ?? 0) > r && console.warn(`[widget-sdk] introspection took ${n.importMs}ms`), i(n.ok ? {
|
|
82
|
+
ok: !0,
|
|
83
|
+
value: n.value
|
|
84
|
+
} : {
|
|
85
|
+
ok: !1,
|
|
86
|
+
reason: n.reason ?? "introspection failed"
|
|
87
|
+
}));
|
|
88
|
+
}
|
|
89
|
+
function m() {
|
|
90
|
+
if (i && a && !o) return a;
|
|
91
|
+
(o || i) && f("worker was replaced");
|
|
92
|
+
let e = w("introspect-worker");
|
|
93
|
+
if (!e) return Promise.reject(/* @__PURE__ */ Error("introspect-worker not found next to the sdk"));
|
|
94
|
+
let t = Date.now(), n = b(process.execPath, [
|
|
95
|
+
"--conditions",
|
|
96
|
+
"browser",
|
|
97
|
+
e
|
|
98
|
+
], { stdio: [
|
|
99
|
+
"pipe",
|
|
100
|
+
"pipe",
|
|
101
|
+
"inherit"
|
|
102
|
+
] });
|
|
103
|
+
i = n;
|
|
104
|
+
let s = new Promise((e, o) => {
|
|
105
|
+
let s = "", c = !1;
|
|
106
|
+
n.stdout?.setEncoding("utf-8"), n.stdout?.on("data", (n) => {
|
|
107
|
+
s += n;
|
|
108
|
+
let i = s.indexOf("\n");
|
|
109
|
+
for (; i >= 0;) {
|
|
110
|
+
let n = s.slice(0, i).trim();
|
|
111
|
+
if (s = s.slice(i + 1), n) {
|
|
112
|
+
if (!c && n.includes("\"ready\"")) {
|
|
113
|
+
c = !0;
|
|
114
|
+
let n = Date.now() - t;
|
|
115
|
+
n > r && console.warn(`[widget-sdk] introspect worker took ${n}ms to boot`), e();
|
|
116
|
+
} else p(n);
|
|
117
|
+
}
|
|
118
|
+
i = s.indexOf("\n");
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
let l = (e) => {
|
|
122
|
+
i === n && (i = null, a = null), d(e), c || o(Error(e));
|
|
123
|
+
};
|
|
124
|
+
n.on("error", (e) => l(e.message)), n.on("exit", (e, t) => l(`introspect worker exited (${t ?? `code ${e}`})`));
|
|
125
|
+
});
|
|
126
|
+
return a = s, s;
|
|
127
|
+
}
|
|
128
|
+
async function h(e) {
|
|
129
|
+
if (s) return {
|
|
130
|
+
ok: !1,
|
|
131
|
+
reason: "introspect session disposed"
|
|
132
|
+
};
|
|
133
|
+
try {
|
|
134
|
+
await m();
|
|
135
|
+
} catch (e) {
|
|
136
|
+
return {
|
|
137
|
+
ok: !1,
|
|
138
|
+
reason: e instanceof Error ? e.message : String(e)
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
let t = i;
|
|
142
|
+
if (!t?.stdin?.writable) return {
|
|
143
|
+
ok: !1,
|
|
144
|
+
reason: "introspect worker is not writable"
|
|
145
|
+
};
|
|
146
|
+
let r = ++c;
|
|
147
|
+
return new Promise((i) => {
|
|
148
|
+
let a = setTimeout(() => {
|
|
149
|
+
u.delete(r), f(`introspection timed out after ${n}ms`), i({
|
|
150
|
+
ok: !1,
|
|
151
|
+
reason: `introspection timed out after ${n}ms`
|
|
152
|
+
});
|
|
153
|
+
}, n);
|
|
154
|
+
u.set(r, (e) => {
|
|
155
|
+
clearTimeout(a), i(e);
|
|
156
|
+
});
|
|
157
|
+
try {
|
|
158
|
+
t.stdin?.write(`${JSON.stringify({
|
|
159
|
+
id: r,
|
|
160
|
+
outFile: e
|
|
161
|
+
})}\n`);
|
|
162
|
+
} catch (e) {
|
|
163
|
+
clearTimeout(a), u.delete(r), o = !0, i({
|
|
164
|
+
ok: !1,
|
|
165
|
+
reason: e instanceof Error ? e.message : String(e)
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
return {
|
|
171
|
+
introspect(e) {
|
|
172
|
+
let t = l.then(() => h(e));
|
|
173
|
+
return l = t.catch(() => void 0), t;
|
|
174
|
+
},
|
|
175
|
+
async dispose() {
|
|
176
|
+
s = !0, f("introspect session disposed");
|
|
177
|
+
},
|
|
178
|
+
get childPid() {
|
|
179
|
+
return i?.pid ?? null;
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
//#endregion
|
|
10
184
|
//#region src/vite/index.ts
|
|
11
|
-
function
|
|
185
|
+
function E(e) {
|
|
12
186
|
let t = JSON.stringify(e, Object.keys(e).sort());
|
|
13
|
-
return
|
|
187
|
+
return a("sha256").update(t).digest("hex").slice(0, 16);
|
|
14
188
|
}
|
|
15
|
-
var
|
|
16
|
-
async function
|
|
189
|
+
var D = 20;
|
|
190
|
+
async function O(e, t) {
|
|
17
191
|
if (e === void 0) return;
|
|
18
192
|
let n;
|
|
19
193
|
try {
|
|
@@ -33,7 +207,7 @@ async function w(e, t) {
|
|
|
33
207
|
let a = i.error.issues.map((e) => ` examples${e.path.length ? `[${e.path.join("][")}]` : ""}: ${e.message}`).join("\n");
|
|
34
208
|
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.`);
|
|
35
209
|
}
|
|
36
|
-
function
|
|
210
|
+
function k(e, t) {
|
|
37
211
|
if (!e?.length) return;
|
|
38
212
|
let n = e.map((e) => {
|
|
39
213
|
let t = e.label ? `"${e.label}"` : `#${e.index}`;
|
|
@@ -41,42 +215,7 @@ function T(e, t) {
|
|
|
41
215
|
}).join("\n");
|
|
42
216
|
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.`);
|
|
43
217
|
}
|
|
44
|
-
|
|
45
|
-
let t = h(b(import.meta.url)), n = [g(t, "introspect.js"), g(t, "introspect.ts")].find((e) => s(e));
|
|
46
|
-
if (!n) return {
|
|
47
|
-
ok: !1,
|
|
48
|
-
reason: `introspect not found next to ${t}`
|
|
49
|
-
};
|
|
50
|
-
let r = a(process.execPath, [
|
|
51
|
-
"--conditions",
|
|
52
|
-
"browser",
|
|
53
|
-
n,
|
|
54
|
-
e
|
|
55
|
-
], {
|
|
56
|
-
encoding: "utf-8",
|
|
57
|
-
timeout: 3e4
|
|
58
|
-
});
|
|
59
|
-
if (r.error) return {
|
|
60
|
-
ok: !1,
|
|
61
|
-
reason: r.error.message
|
|
62
|
-
};
|
|
63
|
-
if (r.status !== 0) return {
|
|
64
|
-
ok: !1,
|
|
65
|
-
reason: (r.stderr || "").trim().split("\n")[0] || `exit ${r.status}`
|
|
66
|
-
};
|
|
67
|
-
try {
|
|
68
|
-
return {
|
|
69
|
-
ok: !0,
|
|
70
|
-
value: JSON.parse(r.stdout)
|
|
71
|
-
};
|
|
72
|
-
} catch {
|
|
73
|
-
return {
|
|
74
|
-
ok: !1,
|
|
75
|
-
reason: "introspect returned unparseable output"
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
var D = [
|
|
218
|
+
var A = [
|
|
80
219
|
"schema",
|
|
81
220
|
"defaultConfig",
|
|
82
221
|
"examples",
|
|
@@ -89,80 +228,80 @@ var D = [
|
|
|
89
228
|
"minSize",
|
|
90
229
|
"maxSize"
|
|
91
230
|
];
|
|
92
|
-
function
|
|
93
|
-
let r =
|
|
231
|
+
function j(e, t, n) {
|
|
232
|
+
let r = c(e, "utf-8"), i = JSON.parse(r), a = {
|
|
94
233
|
...t.manifest ?? {},
|
|
95
234
|
schema: n
|
|
96
235
|
};
|
|
97
|
-
for (let e of
|
|
236
|
+
for (let e of A) a[e] !== void 0 && (i[e] = a[e]);
|
|
98
237
|
let o = `${JSON.stringify(i, null, 2)}\n`;
|
|
99
|
-
o !== r &&
|
|
238
|
+
o !== r && f(e, o);
|
|
100
239
|
}
|
|
101
|
-
async function
|
|
102
|
-
if (!
|
|
103
|
-
let t =
|
|
240
|
+
async function M(e) {
|
|
241
|
+
if (!o(e.outFile)) return;
|
|
242
|
+
let t = e.session ? await e.session.introspect(e.outFile) : T(e.outFile);
|
|
104
243
|
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.
|
|
105
244
|
This usually means the bundle throws while being imported.`);
|
|
106
245
|
let n = t.value, r = n.manifest?.name ?? e.widgetName;
|
|
107
|
-
await
|
|
246
|
+
await O(n.manifest?.examples, r), k(n.exampleConfigIssues, r);
|
|
108
247
|
let i = n.jsonSchema;
|
|
109
248
|
if (!i) return;
|
|
110
|
-
e.manifestPath &&
|
|
111
|
-
let a =
|
|
112
|
-
if (
|
|
113
|
-
let t =
|
|
249
|
+
e.manifestPath && o(e.manifestPath) && j(e.manifestPath, n, i);
|
|
250
|
+
let a = E(i), s = n.manifest?.configVersion ?? null, l = n.manifest?.name ?? e.widgetName;
|
|
251
|
+
if (o(e.hashFile)) {
|
|
252
|
+
let t = c(e.hashFile, "utf-8").trim(), n = null;
|
|
114
253
|
if (t.startsWith("{")) try {
|
|
115
254
|
n = JSON.parse(t);
|
|
116
255
|
} catch {
|
|
117
256
|
n = null;
|
|
118
257
|
}
|
|
119
258
|
if (n) {
|
|
120
|
-
if (n.hash !== a && n.configVersion ===
|
|
121
|
-
} else t !== a && console.warn(`[widget-sdk] Schema shape changed for "${
|
|
259
|
+
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}`);
|
|
260
|
+
} else t !== a && console.warn(`[widget-sdk] Schema shape changed for "${l}" — verify configVersion was bumped`);
|
|
122
261
|
}
|
|
123
|
-
|
|
262
|
+
f(e.hashFile, `${JSON.stringify({
|
|
124
263
|
hash: a,
|
|
125
|
-
configVersion:
|
|
264
|
+
configVersion: s
|
|
126
265
|
})}\n`);
|
|
127
266
|
}
|
|
128
|
-
var
|
|
129
|
-
function
|
|
130
|
-
return
|
|
267
|
+
var ie = "virtual:glasshome-widget", N = "\0virtual:glasshome-widget", P = "/@glasshome/preview";
|
|
268
|
+
function F(e) {
|
|
269
|
+
return v === "\\" ? e.split(v).join("/") : e;
|
|
131
270
|
}
|
|
132
|
-
function
|
|
133
|
-
let e =
|
|
134
|
-
return
|
|
271
|
+
function I() {
|
|
272
|
+
let e = y(import.meta.url);
|
|
273
|
+
return _(m(e), "../../preview");
|
|
135
274
|
}
|
|
136
|
-
function
|
|
275
|
+
function L(e) {
|
|
137
276
|
return r(e);
|
|
138
277
|
}
|
|
139
|
-
var
|
|
140
|
-
function
|
|
141
|
-
let n =
|
|
142
|
-
return n.includes("/node_modules/") || !
|
|
278
|
+
var R = /\.(ts|tsx|js|jsx)$/, z = /from\s+["']@glasshome\/sync-layer(\/[^"']*)?["']/;
|
|
279
|
+
function B(e, t) {
|
|
280
|
+
let n = F(e).split("?")[0] ?? "";
|
|
281
|
+
return n.includes("/node_modules/") || !R.test(n) ? !1 : z.test(t);
|
|
143
282
|
}
|
|
144
|
-
function
|
|
283
|
+
function V() {
|
|
145
284
|
return {
|
|
146
285
|
name: "glasshome-widget:sync-layer-guard",
|
|
147
286
|
apply: "build",
|
|
148
287
|
enforce: "pre",
|
|
149
288
|
transform(e, t) {
|
|
150
|
-
if (
|
|
289
|
+
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).`);
|
|
151
290
|
return null;
|
|
152
291
|
}
|
|
153
292
|
};
|
|
154
293
|
}
|
|
155
|
-
function
|
|
156
|
-
let r =
|
|
157
|
-
if (r.includes("/node_modules/") || !
|
|
294
|
+
function H(t, n) {
|
|
295
|
+
let r = F(t).split("?")[0] ?? "";
|
|
296
|
+
if (r.includes("/node_modules/") || !R.test(r)) return !1;
|
|
158
297
|
let i = e.find((e) => e.id === "direct-ui-import");
|
|
159
298
|
return i?.sourcePattern ? new RegExp(i.sourcePattern).test(n) : !1;
|
|
160
299
|
}
|
|
161
|
-
function
|
|
300
|
+
function U(e = /* @__PURE__ */ new Set()) {
|
|
162
301
|
let t = /* @__PURE__ */ new Set();
|
|
163
302
|
return {
|
|
164
303
|
scan(e, n) {
|
|
165
|
-
|
|
304
|
+
H(e, n) && t.add(F(g(process.cwd(), e.split("?")[0] ?? e)));
|
|
166
305
|
},
|
|
167
306
|
take() {
|
|
168
307
|
let n = [...t].filter((t) => !e.has(t));
|
|
@@ -171,8 +310,8 @@ function V(e = /* @__PURE__ */ new Set()) {
|
|
|
171
310
|
}
|
|
172
311
|
};
|
|
173
312
|
}
|
|
174
|
-
function
|
|
175
|
-
let r =
|
|
313
|
+
function W(n) {
|
|
314
|
+
let r = U(n);
|
|
176
315
|
return {
|
|
177
316
|
name: "glasshome-widget:ui-import-guard",
|
|
178
317
|
apply: "build",
|
|
@@ -188,15 +327,15 @@ function H(n) {
|
|
|
188
327
|
}
|
|
189
328
|
};
|
|
190
329
|
}
|
|
191
|
-
var
|
|
192
|
-
function
|
|
330
|
+
var G = "node_modules/.cache/glasshome-widgets";
|
|
331
|
+
function K(e) {
|
|
193
332
|
try {
|
|
194
|
-
return
|
|
333
|
+
return p(h(process.cwd(), "package.json")).resolve(e);
|
|
195
334
|
} catch {
|
|
196
335
|
return null;
|
|
197
336
|
}
|
|
198
337
|
}
|
|
199
|
-
var
|
|
338
|
+
var q = [
|
|
200
339
|
"--radius",
|
|
201
340
|
"--background",
|
|
202
341
|
"--foreground",
|
|
@@ -206,74 +345,74 @@ var G = [
|
|
|
206
345
|
"--muted",
|
|
207
346
|
"--accent"
|
|
208
347
|
];
|
|
209
|
-
function
|
|
210
|
-
let n =
|
|
211
|
-
if (!
|
|
212
|
-
let r =
|
|
348
|
+
function J(e, t) {
|
|
349
|
+
let n = h(e, `${t}.css`);
|
|
350
|
+
if (!o(n)) return;
|
|
351
|
+
let r = c(n, "utf-8");
|
|
213
352
|
for (let e of r.matchAll(/:host[^{]*\{([^}]*)\}/g)) {
|
|
214
|
-
let n = e[1] ?? "", r =
|
|
353
|
+
let n = e[1] ?? "", r = q.find((e) => n.includes(`${e}:`));
|
|
215
354
|
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.`);
|
|
216
355
|
}
|
|
217
356
|
}
|
|
218
|
-
function
|
|
219
|
-
let r =
|
|
220
|
-
|
|
221
|
-
let i =
|
|
357
|
+
function Y(e, t, n) {
|
|
358
|
+
let r = _(e, G);
|
|
359
|
+
s(r, { recursive: !0 });
|
|
360
|
+
let i = K("@glasshome/ui/styles");
|
|
222
361
|
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.");
|
|
223
|
-
let a =
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
...l ? [
|
|
227
|
-
|
|
228
|
-
].filter((e) =>
|
|
229
|
-
|
|
362
|
+
let a = _(m(i), "../.."), c = K("@glasshome/widget-sdk/tailwind-sources"), l = c ? m(c) : null, u = [
|
|
363
|
+
h(a, "src"),
|
|
364
|
+
h(a, "dist"),
|
|
365
|
+
...l ? [h(l, "src"), h(l, "dist")] : [],
|
|
366
|
+
m(n)
|
|
367
|
+
].filter((e) => o(e)), d = _(r, `${t}.tailwind.css`);
|
|
368
|
+
f(d, [
|
|
230
369
|
"@import \"tailwindcss\" source(none);",
|
|
231
370
|
"@import \"tw-animate-css\";",
|
|
232
371
|
"@import \"@glasshome/ui/styles/theme\";",
|
|
233
|
-
...u.map((e) => `@source "${
|
|
372
|
+
...u.map((e) => `@source "${F(e)}";`),
|
|
234
373
|
"@custom-variant dark {",
|
|
235
374
|
" &:is(.dark *) { @slot }",
|
|
236
375
|
" :host(.dark) & { @slot }",
|
|
237
376
|
"}",
|
|
238
377
|
""
|
|
239
378
|
].join("\n"));
|
|
240
|
-
let
|
|
241
|
-
return p
|
|
242
|
-
`import "${
|
|
243
|
-
`export { default } from "${
|
|
379
|
+
let p = _(r, `${t}.entry.ts`);
|
|
380
|
+
return f(p, [
|
|
381
|
+
`import "${F(d)}";`,
|
|
382
|
+
`export { default } from "${F(n)}";`,
|
|
244
383
|
""
|
|
245
|
-
].join("\n")),
|
|
384
|
+
].join("\n")), p;
|
|
246
385
|
}
|
|
247
|
-
function
|
|
248
|
-
let e =
|
|
386
|
+
function X() {
|
|
387
|
+
let e = ee();
|
|
249
388
|
for (let t of e) t.apply ??= "build";
|
|
250
389
|
return e;
|
|
251
390
|
}
|
|
252
|
-
function
|
|
391
|
+
function Z(e) {
|
|
253
392
|
let t = [];
|
|
254
|
-
if (!
|
|
255
|
-
for (let n of
|
|
256
|
-
let r =
|
|
257
|
-
if (!
|
|
258
|
-
let i =
|
|
259
|
-
|
|
393
|
+
if (!o(e)) return t;
|
|
394
|
+
for (let n of l(e)) {
|
|
395
|
+
let r = _(e, n);
|
|
396
|
+
if (!d(r).isDirectory()) continue;
|
|
397
|
+
let i = _(r, "index.tsx"), a = _(r, "manifest.json");
|
|
398
|
+
o(i) && o(a) && t.push({
|
|
260
399
|
name: n,
|
|
261
400
|
entry: i
|
|
262
401
|
});
|
|
263
402
|
}
|
|
264
403
|
return t;
|
|
265
404
|
}
|
|
266
|
-
function
|
|
405
|
+
function Q(e, t) {
|
|
267
406
|
let r = [];
|
|
268
|
-
if (
|
|
269
|
-
if (!
|
|
270
|
-
let
|
|
271
|
-
if (!s
|
|
272
|
-
let
|
|
273
|
-
if (!
|
|
274
|
-
let u =
|
|
407
|
+
if (o(e)) for (let a of l(e)) {
|
|
408
|
+
if (!d(h(e, a)).isDirectory()) continue;
|
|
409
|
+
let s = h(e, a, "manifest.json");
|
|
410
|
+
if (!o(s)) continue;
|
|
411
|
+
let l = i.safeParse(JSON.parse(c(s, "utf-8")));
|
|
412
|
+
if (!l.success) throw Error(`[registry] Invalid manifest for "${a}": ${n(l.error)}`);
|
|
413
|
+
let u = o(h(t, `${a}.css`));
|
|
275
414
|
r.push({
|
|
276
|
-
...
|
|
415
|
+
...l.data,
|
|
277
416
|
bundleUrl: `./${a}.js`,
|
|
278
417
|
...u ? { cssUrl: `./${a}.css` } : {}
|
|
279
418
|
});
|
|
@@ -284,10 +423,10 @@ function X(e, t) {
|
|
|
284
423
|
baseUrl: "./",
|
|
285
424
|
widgets: r
|
|
286
425
|
};
|
|
287
|
-
|
|
426
|
+
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)`);
|
|
288
427
|
}
|
|
289
|
-
async function
|
|
290
|
-
let { build: t } = await import("vite"), n = process.cwd(), r =
|
|
428
|
+
async function $(e) {
|
|
429
|
+
let { build: t } = await import("vite"), n = process.cwd(), r = _(n, e?.srcDir ?? "src"), i = _(n, e?.outDir ?? "dist"), a = Z(r);
|
|
291
430
|
if (a.length === 0) {
|
|
292
431
|
console.warn("[glasshome-widgets] No widgets found in", r);
|
|
293
432
|
return;
|
|
@@ -296,41 +435,42 @@ async function Z(e) {
|
|
|
296
435
|
let t = new Set(e.only);
|
|
297
436
|
a = a.filter((e) => t.has(e.name));
|
|
298
437
|
}
|
|
299
|
-
e?.only ||
|
|
300
|
-
let
|
|
438
|
+
e?.only || o(i) && u(i, { recursive: !0 }), o(i) || s(i, { recursive: !0 });
|
|
439
|
+
let c = /* @__PURE__ */ new Set();
|
|
301
440
|
for (let r of a) await t({
|
|
302
441
|
configFile: !1,
|
|
303
442
|
root: n,
|
|
304
443
|
plugins: [
|
|
305
|
-
...
|
|
444
|
+
...X(),
|
|
306
445
|
...e?.plugins ?? [],
|
|
307
|
-
|
|
308
|
-
|
|
446
|
+
V(),
|
|
447
|
+
W(c)
|
|
309
448
|
],
|
|
310
449
|
...e?.viteConfig,
|
|
311
450
|
build: {
|
|
312
451
|
lib: {
|
|
313
|
-
entry:
|
|
452
|
+
entry: Y(n, r.name, r.entry),
|
|
314
453
|
formats: ["es"],
|
|
315
454
|
fileName: r.name,
|
|
316
455
|
cssFileName: r.name
|
|
317
456
|
},
|
|
318
|
-
rollupOptions: { external:
|
|
457
|
+
rollupOptions: { external: L },
|
|
319
458
|
outDir: i,
|
|
320
459
|
emptyOutDir: !1,
|
|
321
460
|
copyPublicDir: !1,
|
|
322
461
|
...e?.viteConfig?.build
|
|
323
462
|
},
|
|
324
463
|
logLevel: "warn"
|
|
325
|
-
}),
|
|
326
|
-
outFile:
|
|
327
|
-
hashFile:
|
|
464
|
+
}), J(i, r.name), await M({
|
|
465
|
+
outFile: h(i, `${r.name}.js`),
|
|
466
|
+
hashFile: h(m(r.entry), ".schema-hash"),
|
|
328
467
|
widgetName: r.name,
|
|
329
|
-
manifestPath:
|
|
468
|
+
manifestPath: h(m(r.entry), "manifest.json"),
|
|
469
|
+
session: e?.session
|
|
330
470
|
});
|
|
331
|
-
|
|
471
|
+
Q(r, i);
|
|
332
472
|
}
|
|
333
|
-
function
|
|
473
|
+
function ae(e) {
|
|
334
474
|
let t = e?.entry ?? "src/index.tsx", n = {
|
|
335
475
|
name: "glasshome-widget:build",
|
|
336
476
|
apply: "build",
|
|
@@ -338,12 +478,12 @@ function Q(e) {
|
|
|
338
478
|
let e = process.cwd();
|
|
339
479
|
return { build: {
|
|
340
480
|
lib: {
|
|
341
|
-
entry:
|
|
481
|
+
entry: Y(e, "index", _(e, t)),
|
|
342
482
|
formats: ["es"],
|
|
343
483
|
fileName: "index",
|
|
344
484
|
cssFileName: "index"
|
|
345
485
|
},
|
|
346
|
-
rollupOptions: { external:
|
|
486
|
+
rollupOptions: { external: L }
|
|
347
487
|
} };
|
|
348
488
|
}
|
|
349
489
|
}, r = {
|
|
@@ -351,18 +491,18 @@ function Q(e) {
|
|
|
351
491
|
apply: "serve",
|
|
352
492
|
enforce: "pre",
|
|
353
493
|
config() {
|
|
354
|
-
let e =
|
|
494
|
+
let e = I(), t = process.cwd();
|
|
355
495
|
return { server: { fs: { allow: [
|
|
356
496
|
e,
|
|
357
497
|
t,
|
|
358
|
-
|
|
498
|
+
_(t, "..", "..")
|
|
359
499
|
] } } };
|
|
360
500
|
},
|
|
361
501
|
configureServer(e) {
|
|
362
|
-
let t =
|
|
502
|
+
let t = I(), n = h(t, "preview.html");
|
|
363
503
|
e.middlewares.use(async (t, r, i) => {
|
|
364
504
|
if (t.url === "/" || t.url === "/index.html") try {
|
|
365
|
-
let i =
|
|
505
|
+
let i = c(n, "utf-8");
|
|
366
506
|
i = await e.transformIndexHtml(t.url, i), r.setHeader("Content-Type", "text/html"), r.statusCode = 200, r.end(i);
|
|
367
507
|
} catch (e) {
|
|
368
508
|
i(e);
|
|
@@ -371,37 +511,37 @@ function Q(e) {
|
|
|
371
511
|
});
|
|
372
512
|
},
|
|
373
513
|
resolveId(e) {
|
|
374
|
-
if (e ===
|
|
375
|
-
let e =
|
|
376
|
-
return
|
|
514
|
+
if (e === P) {
|
|
515
|
+
let e = I();
|
|
516
|
+
return F(h(e, "host.tsx"));
|
|
377
517
|
}
|
|
378
|
-
if (e ===
|
|
518
|
+
if (e === ie) return N;
|
|
379
519
|
},
|
|
380
520
|
load(e) {
|
|
381
|
-
if (e ===
|
|
521
|
+
if (e === N) return `export { default } from "${F(_(process.cwd(), t))}";`;
|
|
382
522
|
}
|
|
383
523
|
}, i = {
|
|
384
524
|
name: "glasshome-widget:schema",
|
|
385
525
|
apply: "build",
|
|
386
526
|
async closeBundle() {
|
|
387
|
-
|
|
388
|
-
outFile:
|
|
389
|
-
hashFile:
|
|
527
|
+
J(_(process.cwd(), "dist"), "index"), await M({
|
|
528
|
+
outFile: _(process.cwd(), "dist", "index.js"),
|
|
529
|
+
hashFile: _(process.cwd(), ".schema-hash"),
|
|
390
530
|
widgetName: "index",
|
|
391
|
-
manifestPath:
|
|
531
|
+
manifestPath: _(process.cwd(), "manifest.json")
|
|
392
532
|
});
|
|
393
533
|
}
|
|
394
534
|
};
|
|
395
535
|
return [
|
|
396
|
-
...
|
|
536
|
+
...X(),
|
|
397
537
|
n,
|
|
398
|
-
|
|
399
|
-
|
|
538
|
+
V(),
|
|
539
|
+
W(),
|
|
400
540
|
i,
|
|
401
541
|
r
|
|
402
542
|
];
|
|
403
543
|
}
|
|
404
|
-
function
|
|
544
|
+
function oe(e) {
|
|
405
545
|
let t = e?.srcDir ?? "src", n = e?.outDir ?? "dist", r = [];
|
|
406
546
|
return [{
|
|
407
547
|
name: "glasshome-widgets:build",
|
|
@@ -420,7 +560,7 @@ function $(e) {
|
|
|
420
560
|
if (e === "\0glasshome-noop") return "export {}";
|
|
421
561
|
},
|
|
422
562
|
async closeBundle() {
|
|
423
|
-
await
|
|
563
|
+
await $({
|
|
424
564
|
srcDir: t,
|
|
425
565
|
outDir: n,
|
|
426
566
|
plugins: r
|
|
@@ -429,4 +569,4 @@ function $(e) {
|
|
|
429
569
|
}];
|
|
430
570
|
}
|
|
431
571
|
//#endregion
|
|
432
|
-
export {
|
|
572
|
+
export { D as MAX_EXAMPLES, $ as buildWidgets, re as createIntrospectSession, U as createUiImportTracker, Z as discoverWidgets, Q as generateRegistry, ae as glasshomeWidget, oe as glasshomeWidgets, T as introspectOnce, B as isDirectSyncLayerImportSource, H as isDirectUiImportSource, L as isWidgetExternal, M as runSchemaGuard };
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads a built widget bundle's definition under a fake DOM.
|
|
3
|
+
*
|
|
4
|
+
* A widget bundle cannot be imported by the build process: `solid-js/web`
|
|
5
|
+
* resolves to its server build under Node's conditions and throws the moment
|
|
6
|
+
* the module initialises, and browser conditions then need a DOM for the
|
|
7
|
+
* templates Solid creates at import time. Both callers (the one-shot
|
|
8
|
+
* `introspect.ts` CLI and the persistent `introspect-worker.ts`) run under
|
|
9
|
+
* `--conditions browser` and install a DOM before importing.
|
|
10
|
+
*/
|
|
11
|
+
export interface ExampleConfigIssue {
|
|
12
|
+
index: number;
|
|
13
|
+
label?: string;
|
|
14
|
+
problems: string[];
|
|
15
|
+
}
|
|
16
|
+
export interface WidgetIntrospection {
|
|
17
|
+
manifest: ({
|
|
18
|
+
name?: string;
|
|
19
|
+
configVersion?: number;
|
|
20
|
+
examples?: unknown;
|
|
21
|
+
} & Record<string, unknown>) | null;
|
|
22
|
+
/** JSON Schema derived from the widget's configSchema, when it has one. */
|
|
23
|
+
jsonSchema: object | null;
|
|
24
|
+
/** Examples whose config the widget's own configSchema rejects. */
|
|
25
|
+
exampleConfigIssues: ExampleConfigIssue[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Install a fresh DOM. Unconditional: the persistent worker calls this per
|
|
29
|
+
* request, and skipping already-set keys would leak the previous widget's
|
|
30
|
+
* mutated window into the next one.
|
|
31
|
+
*/
|
|
32
|
+
export declare function installDom(): Promise<void>;
|
|
33
|
+
export declare function introspectBundle(bundlePath: string, cacheBust?: string): Promise<WidgetIntrospection>;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { WidgetIntrospection } from "./introspect-core";
|
|
2
|
+
export type IntrospectResult = {
|
|
3
|
+
ok: true;
|
|
4
|
+
value: WidgetIntrospection;
|
|
5
|
+
} | {
|
|
6
|
+
ok: false;
|
|
7
|
+
reason: string;
|
|
8
|
+
};
|
|
9
|
+
export interface IntrospectSessionOptions {
|
|
10
|
+
/** Respawn once the worker's RSS crosses this, between requests only. */
|
|
11
|
+
rssLimitBytes?: number;
|
|
12
|
+
/** Per-request ceiling; a module-eval hang can only be cured by a kill. */
|
|
13
|
+
timeoutMs?: number;
|
|
14
|
+
/** Log spawn and import durations above this. */
|
|
15
|
+
slowMs?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface IntrospectSession {
|
|
18
|
+
introspect(outFile: string): Promise<IntrospectResult>;
|
|
19
|
+
dispose(): Promise<void>;
|
|
20
|
+
readonly childPid: number | null;
|
|
21
|
+
}
|
|
22
|
+
/** One process per check. The path `build`, `capture` and the fallback take. */
|
|
23
|
+
export declare function introspectOnce(outFile: string): IntrospectResult;
|
|
24
|
+
/**
|
|
25
|
+
* A worker reused across rebuilds, for callers that own a session.
|
|
26
|
+
*
|
|
27
|
+
* Only `bun widget connect`'s watch loop does: it is the one call site that
|
|
28
|
+
* re-pays the per-check process boot tax on every save.
|
|
29
|
+
*/
|
|
30
|
+
export declare function createIntrospectSession(options?: IntrospectSessionOptions): IntrospectSession;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Long-lived introspection worker for `bun widget connect`.
|
|
3
|
+
*
|
|
4
|
+
* Newline-delimited JSON over stdio. Every request carries an id: a widget
|
|
5
|
+
* bundle can print at module-eval time, and without id pairing one stray line
|
|
6
|
+
* offsets every later response.
|
|
7
|
+
*
|
|
8
|
+
* Usage: bun --conditions browser introspect-worker.js
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { n as e, t } from "../introspect-core-DYv9Uufi.js";
|
|
2
|
+
//#region src/vite/introspect-worker.ts
|
|
3
|
+
var n = process.stdout.write.bind(process.stdout);
|
|
4
|
+
process.stdout.write = ((e, ...t) => process.stderr.write(e, ...t));
|
|
5
|
+
function r(e) {
|
|
6
|
+
n(`${JSON.stringify(e)}\n`);
|
|
7
|
+
}
|
|
8
|
+
function i(e) {
|
|
9
|
+
return e instanceof Error ? e.message : String(e);
|
|
10
|
+
}
|
|
11
|
+
var a = null, o = 0, s = Promise.resolve();
|
|
12
|
+
async function c(n, s) {
|
|
13
|
+
a = n;
|
|
14
|
+
let c = performance.now();
|
|
15
|
+
try {
|
|
16
|
+
await t(), r({
|
|
17
|
+
id: n,
|
|
18
|
+
ok: !0,
|
|
19
|
+
value: await e(s, String(++o)),
|
|
20
|
+
rss: process.memoryUsage().rss,
|
|
21
|
+
importMs: Math.round(performance.now() - c)
|
|
22
|
+
});
|
|
23
|
+
} catch (e) {
|
|
24
|
+
r({
|
|
25
|
+
id: n,
|
|
26
|
+
ok: !1,
|
|
27
|
+
reason: i(e),
|
|
28
|
+
rss: process.memoryUsage().rss,
|
|
29
|
+
importMs: Math.round(performance.now() - c)
|
|
30
|
+
});
|
|
31
|
+
} finally {
|
|
32
|
+
a = null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function l(e) {
|
|
36
|
+
let t;
|
|
37
|
+
try {
|
|
38
|
+
t = JSON.parse(e);
|
|
39
|
+
} catch {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
if (typeof t.id != "number" || typeof t.outFile != "string") return;
|
|
43
|
+
let { id: n, outFile: r } = t;
|
|
44
|
+
s = s.then(() => c(n, r));
|
|
45
|
+
}
|
|
46
|
+
function u(e) {
|
|
47
|
+
a !== null && r({
|
|
48
|
+
id: a,
|
|
49
|
+
ok: !1,
|
|
50
|
+
reason: i(e),
|
|
51
|
+
rss: process.memoryUsage().rss,
|
|
52
|
+
importMs: 0
|
|
53
|
+
}), process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
process.on("uncaughtException", u), process.on("unhandledRejection", u);
|
|
56
|
+
var d = "";
|
|
57
|
+
process.stdin.setEncoding("utf-8"), process.stdin.on("data", (e) => {
|
|
58
|
+
d += e;
|
|
59
|
+
let t = d.indexOf("\n");
|
|
60
|
+
for (; t >= 0;) {
|
|
61
|
+
let e = d.slice(0, t).trim();
|
|
62
|
+
d = d.slice(t + 1), e && l(e), t = d.indexOf("\n");
|
|
63
|
+
}
|
|
64
|
+
}), process.stdin.on("end", () => process.exit(0)), process.stdin.on("close", () => process.exit(0)), process.stdin.resume();
|
|
65
|
+
var f = process.ppid;
|
|
66
|
+
setInterval(() => {
|
|
67
|
+
try {
|
|
68
|
+
process.kill(f, 0);
|
|
69
|
+
} catch {
|
|
70
|
+
process.exit(0);
|
|
71
|
+
}
|
|
72
|
+
}, 5e3), r({
|
|
73
|
+
id: 0,
|
|
74
|
+
ready: !0
|
|
75
|
+
});
|
|
76
|
+
//#endregion
|
|
@@ -1,21 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Reads a built widget bundle's definition and prints it as JSON.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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.
|
|
4
|
+
* One-shot counterpart to introspect-worker.ts: a fresh process per check, used
|
|
5
|
+
* by `bun widget build`, the render worker's capture, and as the
|
|
6
|
+
* GLASSHOME_WIDGET_NO_WORKER fallback.
|
|
13
7
|
*
|
|
14
8
|
* Usage: bun --conditions browser introspect.js <bundle.js>
|
|
15
|
-
* Prints: { manifest, jsonSchema } on stdout, or exits
|
|
9
|
+
* Prints: { manifest, jsonSchema, exampleConfigIssues } on stdout, or exits
|
|
10
|
+
* non-zero with a reason.
|
|
16
11
|
*/
|
|
17
|
-
export
|
|
18
|
-
index: number;
|
|
19
|
-
label?: string;
|
|
20
|
-
problems: string[];
|
|
21
|
-
}
|
|
12
|
+
export {};
|
package/dist/vite/introspect.js
CHANGED
|
@@ -1,59 +1,10 @@
|
|
|
1
|
+
import { n as e, t } from "../introspect-core-DYv9Uufi.js";
|
|
1
2
|
//#region src/vite/introspect.ts
|
|
2
|
-
function e(e) {
|
|
3
|
-
return typeof e?.safeParse == "function";
|
|
4
|
-
}
|
|
5
|
-
function t(t, n) {
|
|
6
|
-
if (!e(t) || !Array.isArray(n)) return [];
|
|
7
|
-
let r = [];
|
|
8
|
-
for (let [e, i] of n.entries()) {
|
|
9
|
-
let n = i?.config;
|
|
10
|
-
if (typeof n != "object" || !n) continue;
|
|
11
|
-
let a = t.safeParse(n);
|
|
12
|
-
a.success || r.push({
|
|
13
|
-
index: e,
|
|
14
|
-
label: i.label,
|
|
15
|
-
problems: (a.error?.issues ?? []).map((e) => {
|
|
16
|
-
let t = e.path.map(String).join(".");
|
|
17
|
-
return t ? `${t}: ${e.message}` : e.message;
|
|
18
|
-
})
|
|
19
|
-
});
|
|
20
|
-
}
|
|
21
|
-
return r;
|
|
22
|
-
}
|
|
23
3
|
async function n() {
|
|
24
|
-
let
|
|
25
|
-
|
|
26
|
-
"window",
|
|
27
|
-
"document",
|
|
28
|
-
"navigator",
|
|
29
|
-
"location",
|
|
30
|
-
"customElements",
|
|
31
|
-
"HTMLElement",
|
|
32
|
-
"Element",
|
|
33
|
-
"Node",
|
|
34
|
-
"CSS",
|
|
35
|
-
"getComputedStyle",
|
|
36
|
-
"requestAnimationFrame",
|
|
37
|
-
"cancelAnimationFrame",
|
|
38
|
-
"matchMedia"
|
|
39
|
-
]) globalThis[e] === void 0 && (globalThis[e] = t[e]);
|
|
40
|
-
}
|
|
41
|
-
async function r() {
|
|
42
|
-
let e = process.argv[2];
|
|
43
|
-
e || (process.stderr.write("introspect: no bundle path given\n"), process.exit(2)), await n();
|
|
44
|
-
let r = (await import(e)).default, i = null;
|
|
45
|
-
if (r?.configSchema) {
|
|
46
|
-
let { z: e } = await import("zod");
|
|
47
|
-
i = e.toJSONSchema(r.configSchema, { unrepresentable: "any" });
|
|
48
|
-
}
|
|
49
|
-
let a = {
|
|
50
|
-
manifest: r?.manifest ?? null,
|
|
51
|
-
jsonSchema: i,
|
|
52
|
-
exampleConfigIssues: t(r?.configSchema, r?.manifest?.examples)
|
|
53
|
-
};
|
|
54
|
-
process.stdout.write(JSON.stringify(a));
|
|
4
|
+
let n = process.argv[2];
|
|
5
|
+
n || (process.stderr.write("introspect: no bundle path given\n"), process.exit(2)), await t(), process.stdout.write(JSON.stringify(await e(n)));
|
|
55
6
|
}
|
|
56
|
-
|
|
7
|
+
n().catch((e) => {
|
|
57
8
|
process.stderr.write(`${e instanceof Error ? e.message : String(e)}\n`), process.exit(1);
|
|
58
9
|
});
|
|
59
10
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@glasshome/widget-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.11.0",
|
|
4
4
|
"description": "SDK for building GlassHome dashboard widgets with SolidJS",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"glasshome",
|
|
@@ -63,11 +63,6 @@
|
|
|
63
63
|
"@glasshome/ui": "1.3.0",
|
|
64
64
|
"solid-js": "^1.9.11"
|
|
65
65
|
},
|
|
66
|
-
"peerDependenciesMeta": {
|
|
67
|
-
"@glasshome/ui": {
|
|
68
|
-
"optional": true
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
66
|
"dependencies": {
|
|
72
67
|
"@glasshome/widget-contract": "0.2.0",
|
|
73
68
|
"@modular-forms/solid": "^0.25.1",
|