@glasshome/sync-layer 0.2.1 → 0.2.2

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 CHANGED
@@ -1,5 +1,5 @@
1
1
  import { ENERGY_ENTITY_IDS, createDemoFixtures, demoEnergyPreferences, energyEntityValue, formatEnergyState, isEnergyEntity, isSunUp, resetStore, setState, simulateEnergy, state, sunEvents, synthesizeEnergyHistory, synthesizeEnergyStatistics } from "./demo-data-CavpxBw3.js";
2
- import { runHaBridgeWorker } from "./worker-main-C93MR-AO.js";
2
+ import { runHaBridgeWorker } from "./worker-main-BYGgbA7k.js";
3
3
  import { createConnection, createLongLivedTokenAuth, getAuth } from "home-assistant-js-websocket";
4
4
  import { produce, reconcile } from "solid-js/store";
5
5
 
@@ -2870,7 +2870,8 @@ function createHaBridge(worker, events = {}) {
2870
2870
  k: "connect",
2871
2871
  url: opts.url,
2872
2872
  mode: opts.mode,
2873
- proxyWsPath: opts.proxyWsPath
2873
+ proxyWsPath: opts.proxyWsPath,
2874
+ proxyTicket: opts.proxyTicket
2874
2875
  });
2875
2876
  });
2876
2877
  },
@@ -15,6 +15,7 @@ export interface BridgeConnectOptions {
15
15
  url: string;
16
16
  mode: AuthMode;
17
17
  proxyWsPath?: string;
18
+ proxyTicket?: string;
18
19
  }
19
20
  export interface BridgeEvents {
20
21
  onConnState?: (state: ConnState) => void;
@@ -31,8 +31,13 @@ export type MainToWorker = {
31
31
  k: "connect";
32
32
  url: string;
33
33
  mode: AuthMode;
34
- /** Same-origin WS path to use instead of the HA host (tunnel proxy). */
34
+ /** Proxy WS endpoint to use instead of the HA host. A path (web, resolved
35
+ * same-origin) or an absolute ws(s)/http(s) URL (native, where the worker
36
+ * origin is localhost, not dash-server). */
35
37
  proxyWsPath?: string;
38
+ /** Short-lived ticket authorizing the proxy WS + broker mint when a
39
+ * cross-origin cookie/bearer can't ride them (native). */
40
+ proxyTicket?: string;
36
41
  } | {
37
42
  k: "send";
38
43
  id: number;
@@ -1,3 +1,3 @@
1
- import { runHaBridgeWorker } from "../worker-main-C93MR-AO.js";
1
+ import { runHaBridgeWorker } from "../worker-main-BYGgbA7k.js";
2
2
 
3
3
  export { runHaBridgeWorker };
@@ -129,14 +129,18 @@ function isHaWireMessage(value) {
129
129
  return typeof value === "object" && value !== null && typeof value.type === "string";
130
130
  }
131
131
  var BrokeredAuth = class extends Auth {
132
- constructor(mintUrl, data) {
132
+ constructor(mintUrl, data, ticket) {
133
133
  super(data);
134
134
  this.mintUrl = mintUrl;
135
+ this.ticket = ticket;
135
136
  }
136
137
  async refreshAccessToken() {
137
138
  const res = await fetch(this.mintUrl, {
138
- credentials: "same-origin",
139
- headers: { accept: "application/json" }
139
+ credentials: "include",
140
+ headers: {
141
+ accept: "application/json",
142
+ ...this.ticket ? { "x-proxy-ticket": this.ticket } : {}
143
+ }
140
144
  });
141
145
  if (!res.ok) throw new Error(`Token broker responded ${res.status}`);
142
146
  if (!res.headers.get("content-type")?.includes("application/json")) throw new Error(`Token broker did not return JSON (is ${this.mintUrl} reachable?)`);
@@ -152,6 +156,19 @@ var BrokeredAuth = class extends Auth {
152
156
  };
153
157
  }
154
158
  };
159
+ /** Resolve the proxy WS endpoint. Accepts a same-origin path (web) or an
160
+ * absolute ws(s)/http(s) URL (native), and appends the auth ticket if given. */
161
+ function buildProxyWsUrl(scope, proxyWsPath, ticket) {
162
+ let base;
163
+ if (/^wss?:\/\//i.test(proxyWsPath)) base = proxyWsPath;
164
+ else if (/^https?:\/\//i.test(proxyWsPath)) base = proxyWsPath.replace(/^http/i, "ws");
165
+ else {
166
+ const proto = scope.location.protocol === "https:" ? "wss:" : "ws:";
167
+ base = `${proto}//${scope.location.host}${proxyWsPath}`;
168
+ }
169
+ if (ticket) base += `${base.includes("?") ? "&" : "?"}ticket=${encodeURIComponent(ticket)}`;
170
+ return base;
171
+ }
155
172
  function runHaBridgeWorker(scope) {
156
173
  let conn = null;
157
174
  const widgets = /* @__PURE__ */ new Map();
@@ -264,7 +281,7 @@ function runHaBridgeWorker(scope) {
264
281
  resumeVisible = null;
265
282
  }
266
283
  }
267
- async function buildAuth(url, mode) {
284
+ async function buildAuth(url, mode, ticket) {
268
285
  switch (mode.kind) {
269
286
  case "token": return new Auth({
270
287
  hassUrl: url,
@@ -281,7 +298,7 @@ function runHaBridgeWorker(scope) {
281
298
  refresh_token: "",
282
299
  expires: 0,
283
300
  expires_in: 0
284
- });
301
+ }, ticket);
285
302
  case "oauth": {
286
303
  const data = mode.data ?? await loadTokens();
287
304
  if (!data) return "needs-auth";
@@ -292,8 +309,8 @@ function runHaBridgeWorker(scope) {
292
309
  }
293
310
  }
294
311
  }
295
- async function connect(url, mode, proxyWsPath) {
296
- const auth = await buildAuth(url, mode);
312
+ async function connect(url, mode, proxyWsPath, proxyTicket) {
313
+ const auth = await buildAuth(url, mode, proxyTicket);
297
314
  if (auth === "needs-auth") {
298
315
  post({
299
316
  k: "connect_result",
@@ -312,9 +329,9 @@ function runHaBridgeWorker(scope) {
312
329
  });
313
330
  return;
314
331
  }
315
- const socketFactory = proxyWsPath ? (options) => {
316
- const proto = scope.location.protocol === "https:" ? "wss:" : "ws:";
317
- const proxied = new Proxy(options.auth, { get: (target, prop) => prop === "wsUrl" ? `${proto}//${scope.location.host}${proxyWsPath}` : Reflect.get(target, prop) });
332
+ const proxyWsUrl = proxyWsPath ? buildProxyWsUrl(scope, proxyWsPath, proxyTicket) : null;
333
+ const socketFactory = proxyWsUrl ? (options) => {
334
+ const proxied = new Proxy(options.auth, { get: (target, prop) => prop === "wsUrl" ? proxyWsUrl : Reflect.get(target, prop) });
318
335
  return createSocket({
319
336
  ...options,
320
337
  auth: proxied
@@ -368,7 +385,7 @@ function runHaBridgeWorker(scope) {
368
385
  const msg = ev.data;
369
386
  switch (msg.k) {
370
387
  case "connect":
371
- await connect(msg.url, msg.mode, msg.proxyWsPath);
388
+ await connect(msg.url, msg.mode, msg.proxyWsPath, msg.proxyTicket);
372
389
  break;
373
390
  case "send": {
374
391
  if (!conn || !isHaWireMessage(msg.message)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glasshome/sync-layer",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "description": "Type-safe, reactive state synchronization layer for Home Assistant",
5
5
  "repository": {
6
6
  "type": "git",