@camstack/addon-provider-bosch 0.1.20 → 0.1.21

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.
@@ -1,6 +1,6 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_dist = require("../dist-CYBUFKeW.js");
3
- const require_account_integration_offline = require("../account-integration-offline-7DUtQrPy.js");
2
+ const require_dist = require("../dist-CFPbdUpa.js");
3
+ const require_account_integration_offline = require("../account-integration-offline-CEg0JOfN.js");
4
4
  let node_crypto = require("node:crypto");
5
5
  let node_tls = require("node:tls");
6
6
  let node_zlib = require("node:zlib");
@@ -8,21 +8,20 @@ let node_dns_promises = require("node:dns/promises");
8
8
  //#region src/home-connect/custom-actions.ts
9
9
  var homeConnectActions = require_dist.defineCustomActions({
10
10
  beginSignIn: require_dist.customAction(require_dist.object({}), require_dist.object({
11
+ attemptId: require_dist.string().min(1),
11
12
  authorizeUrl: require_dist.string().min(1),
12
- verifier: require_dist.string().min(1),
13
- state: require_dist.string().min(1),
14
13
  summary: require_dist.string()
15
14
  }), {
16
15
  kind: "mutation",
17
16
  auth: "admin"
18
17
  }),
19
18
  finishSignIn: require_dist.customAction(require_dist.object({
20
- verifier: require_dist.string().min(1),
21
- callback: require_dist.string().min(1),
22
- state: require_dist.string().min(1)
19
+ attemptId: require_dist.string().min(1),
20
+ callback: require_dist.string().min(1)
23
21
  }), require_dist.object({
24
22
  token: require_dist.string().min(1).meta({ secret: true }),
25
23
  refresh: require_dist.string().optional().meta({ secret: true }),
24
+ accountLabel: require_dist.string(),
26
25
  /** JSON of the paired appliances — no credential on it. */
27
26
  appliances: require_dist.string().min(1),
28
27
  /** JSON of `haId -> { psk, iv64? }`; stored in the keychain, never in `appliances`. */
@@ -31,6 +30,13 @@ var homeConnectActions = require_dist.defineCustomActions({
31
30
  }), {
32
31
  kind: "mutation",
33
32
  auth: "admin"
33
+ }),
34
+ signOut: require_dist.customAction(require_dist.object({}), require_dist.object({
35
+ signedOut: require_dist.literal(true),
36
+ summary: require_dist.string()
37
+ }), {
38
+ kind: "mutation",
39
+ auth: "admin"
34
40
  })
35
41
  });
36
42
  //#endregion
@@ -602,11 +608,15 @@ var HOME_CONNECT_IDDF_URL = (haId) => `https://eu.services.home-connect.com/api/
602
608
  //#endregion
603
609
  //#region src/home-connect/home-connect-login.ts
604
610
  /** Public OAuth client ids from the Home Connect app login (hcpy). */
605
- var APP_ID$1 = "9B75AC9EC512F36C84256AC47D813E2C1DD0D6520DF774B020E1E6E2EB29B1F3";
606
- var OAUTH_BASE = "https://api.home-connect.com/security/oauth/";
611
+ var HOME_CONNECT_CLIENT_ID = "9B75AC9EC512F36C84256AC47D813E2C1DD0D6520DF774B020E1E6E2EB29B1F3";
612
+ var HOME_CONNECT_OAUTH_BASE = "https://api.home-connect.com/security/oauth/";
607
613
  var ASSET_BASE = "https://eu.services.home-connect.com/";
608
- var REDIRECT_URI = "hcauth://auth/prod";
609
- var AUTHORIZE_SCOPE = "Control DeleteAppliance IdentifyAppliance Images Monitor ReadAccount ReadOrigApi Settings WriteAppliance WriteOrigApi";
614
+ var HOME_CONNECT_REDIRECT_URI = "hcauth://auth/prod";
615
+ var HOME_CONNECT_AUTHORIZE_SCOPE = "Control DeleteAppliance IdentifyAppliance Images Monitor ReadAccount ReadOrigApi Settings WriteAppliance WriteOrigApi";
616
+ var APP_ID$1 = HOME_CONNECT_CLIENT_ID;
617
+ var OAUTH_BASE = HOME_CONNECT_OAUTH_BASE;
618
+ var REDIRECT_URI = HOME_CONNECT_REDIRECT_URI;
619
+ var AUTHORIZE_SCOPE = HOME_CONNECT_AUTHORIZE_SCOPE;
610
620
  var CookieJar = class {
611
621
  #cookies = /* @__PURE__ */ new Map();
612
622
  absorb(headers) {
@@ -812,6 +822,7 @@ async function fetchHomeConnectAccount(creds, fetchImpl = homeConnectLoginFetch)
812
822
  token,
813
823
  refresh,
814
824
  appliances,
825
+ accountId: homeConnectAccountLabel(token),
815
826
  summary: accountSummary(appliances)
816
827
  };
817
828
  } catch (err) {
@@ -824,9 +835,18 @@ async function fetchHomeConnectAccount(creds, fetchImpl = homeConnectLoginFetch)
824
835
  token: next.token,
825
836
  refresh: next.refresh,
826
837
  appliances,
838
+ accountId: homeConnectAccountLabel(next.token),
827
839
  summary: accountSummary(appliances)
828
840
  };
829
841
  }
842
+ /** The JWT `sub`, or empty when the token has none. Never throws. */
843
+ function homeConnectAccountLabel(token) {
844
+ try {
845
+ return accountIdFromAccessToken(token);
846
+ } catch {
847
+ return "";
848
+ }
849
+ }
830
850
  /**
831
851
  * Exchange the refresh token for a new access token. Never throws; a failure says why and
832
852
  * carries no credential. A response without a new refresh token keeps the one that was used.
@@ -949,6 +969,24 @@ async function completeHomeConnectSignIn(input, fetchImpl = homeConnectLoginFetc
949
969
  }
950
970
  return fetchHomeConnectAccount(tokensFromBody(token.body), fetchImpl);
951
971
  }
972
+ /** What the form is allowed to see. The verifier stays in `store`. */
973
+ function publishHomeConnectSignIn(store, nowMs) {
974
+ const started = beginHomeConnectSignIn();
975
+ return {
976
+ attemptId: store.put(started.verifier, started.state, nowMs),
977
+ authorizeUrl: started.authorizeUrl
978
+ };
979
+ }
980
+ async function finishHomeConnectSignIn(input, store, fetchImpl = homeConnectLoginFetch) {
981
+ const taken = store.take(input.attemptId, input.nowMs);
982
+ if (!taken.ok) throw new HomeConnectLoginError(require_account_integration_offline.loginFailureForAttempt(taken.reason));
983
+ return completeHomeConnectSignIn({
984
+ verifier: taken.attempt.verifier,
985
+ callback: input.callback,
986
+ state: taken.attempt.state
987
+ }, fetchImpl);
988
+ }
989
+ var homeConnectSignInAttempts = require_account_integration_offline.createSignInAttemptStore();
952
990
  //#endregion
953
991
  //#region src/home-connect/home-connect-discovery.ts
954
992
  /** Dishwasher accessory label: `Dishwasher` plus the appliance name. */
@@ -1192,7 +1230,9 @@ var homeConnectStoredApplianceSchema = homeConnectApplianceRowSchema.extend({
1192
1230
  var homeConnectConfigSchema = require_dist.object({
1193
1231
  token: require_dist.string().min(1).describe("Home Connect access token").meta({ secret: true }),
1194
1232
  refresh: require_dist.string().optional().describe("Home Connect refresh token").meta({ secret: true }),
1195
- appliances: require_dist.array(homeConnectStoredApplianceSchema).optional()
1233
+ appliances: require_dist.array(homeConnectStoredApplianceSchema).optional(),
1234
+ /** Shown on the sign-in field. The JWT subject, not a credential. */
1235
+ accountLabel: require_dist.string().optional()
1196
1236
  });
1197
1237
  function parseJsonValue(raw) {
1198
1238
  if (typeof raw !== "string") return raw;
@@ -1393,103 +1433,49 @@ function sameHomeConnectConnection(a, b) {
1393
1433
  var HOME_CONNECT_PAIRED_ONLY = "__paired_only__";
1394
1434
  function buildHomeConnectFormSchema() {
1395
1435
  const pairedOnly = {
1396
- field: "authorizeUrl",
1436
+ field: "__hidden__",
1397
1437
  equals: HOME_CONNECT_PAIRED_ONLY
1398
1438
  };
1399
1439
  return { sections: [{
1400
1440
  id: "gateway",
1401
1441
  title: "Home Connect",
1402
1442
  titleKey: "provider-bosch:home-connect.s_gateway.title",
1403
- description: "Open the login link, sign in, then paste the address the browser stops on (hcauth://auth/prod?code=…). Chrome: DevTools > Network > last redirect > Location.",
1443
+ description: "Sign in with your Home Connect account. Paste the address the browser stops on (hcauth://auth/prod?code=…).",
1404
1444
  descriptionKey: "provider-bosch:home-connect.s_gateway.description",
1405
1445
  columns: 1,
1406
1446
  fields: [
1407
1447
  {
1408
- type: "addon-action-button",
1448
+ type: "account-sign-in",
1409
1449
  addonId: "bosch-home-connect",
1410
- key: "__home-connect-begin",
1450
+ key: "__home-connect-sign-in",
1411
1451
  label: "Home Connect",
1412
- labelKey: "provider-bosch:home-connect.s_gateway.__home-connect-begin.label",
1413
- buttonLabel: "Create login link",
1414
- action: "beginSignIn",
1415
- variant: "primary",
1416
- assignResult: {
1417
- authorizeUrl: "authorizeUrl",
1418
- verifier: "verifier",
1419
- state: "state"
1420
- },
1421
- successMessage: "Open the link in Chrome and sign in."
1422
- },
1423
- {
1424
- type: "textarea",
1425
- key: "authorizeUrl",
1426
- label: "Login link",
1427
- labelKey: "provider-bosch:home-connect.s_gateway.authorizeUrl.label",
1428
- required: false,
1429
- omitFromSettings: true
1430
- },
1431
- {
1432
- type: "textarea",
1433
- key: "callback",
1434
- label: "Redirect address or code",
1435
- labelKey: "provider-bosch:home-connect.s_gateway.callback.label",
1436
- required: false,
1437
- placeholder: "hcauth://auth/prod?code=…&state=…",
1438
- omitFromSettings: true
1439
- },
1440
- {
1441
- type: "password",
1442
- key: "state",
1443
- label: "Login state",
1444
- labelKey: "provider-bosch:home-connect.s_gateway.state.label",
1445
- required: false,
1446
- omitFromSettings: true,
1447
- showWhen: pairedOnly
1448
- },
1449
- {
1450
- type: "password",
1451
- key: "verifier",
1452
- label: "Login verifier",
1453
- labelKey: "provider-bosch:home-connect.s_gateway.verifier.label",
1454
- required: false,
1455
- omitFromSettings: true,
1456
- showWhen: pairedOnly
1457
- },
1458
- {
1459
- type: "addon-action-button",
1460
- addonId: "bosch-home-connect",
1461
- key: "__home-connect-finish",
1462
- label: "Finish",
1463
- labelKey: "provider-bosch:home-connect.s_gateway.__home-connect-finish.label",
1464
- buttonLabel: "Complete sign-in",
1465
- action: "finishSignIn",
1466
- variant: "primary",
1467
- paramsFromForm: {
1468
- verifier: "verifier",
1469
- callback: "callback",
1470
- state: "state"
1471
- },
1452
+ labelKey: "provider-bosch:home-connect.s_gateway.__home-connect-sign-in.label",
1453
+ providerLabel: "Home Connect",
1454
+ beginAction: "beginSignIn",
1455
+ completeAction: "finishSignIn",
1456
+ signOutAction: "signOut",
1457
+ accountKey: "accountLabel",
1458
+ countFromKey: "appliances",
1459
+ countNoun: "appliance",
1460
+ pastePlaceholder: "hcauth://auth/prod?code=…&state=…",
1461
+ secretKeys: [
1462
+ "token",
1463
+ "refresh",
1464
+ APPLIANCE_SECRETS_KEY
1465
+ ],
1472
1466
  assignResult: {
1473
1467
  token: "token",
1474
1468
  refresh: "refresh",
1469
+ accountLabel: "accountLabel",
1475
1470
  appliances: "appliances",
1476
1471
  [APPLIANCE_SECRETS_KEY]: APPLIANCE_SECRETS_KEY
1477
- },
1478
- successMessage: "{summary}"
1479
- },
1480
- {
1481
- type: "password",
1482
- key: "token",
1483
- label: "Access token",
1484
- labelKey: "provider-bosch:home-connect.s_gateway.token.label",
1485
- required: true,
1486
- showWhen: pairedOnly
1472
+ }
1487
1473
  },
1488
1474
  {
1489
- type: "password",
1490
- key: "refresh",
1491
- label: "Refresh token",
1492
- labelKey: "provider-bosch:home-connect.s_gateway.refresh.label",
1475
+ type: "text",
1476
+ key: "accountLabel",
1477
+ label: "Account",
1478
+ labelKey: "provider-bosch:home-connect.s_gateway.accountLabel.label",
1493
1479
  required: false,
1494
1480
  showWhen: pairedOnly
1495
1481
  },
@@ -1498,15 +1484,38 @@ function buildHomeConnectFormSchema() {
1498
1484
  key: "appliances",
1499
1485
  label: "Appliances",
1500
1486
  labelKey: "provider-bosch:home-connect.s_gateway.appliances.label",
1501
- required: true,
1487
+ required: false,
1502
1488
  showWhen: pairedOnly
1503
1489
  },
1504
1490
  {
1505
1491
  type: "password",
1506
1492
  key: APPLIANCE_SECRETS_KEY,
1507
1493
  label: "Appliance keys",
1508
- required: true,
1494
+ required: false,
1509
1495
  showWhen: pairedOnly
1496
+ },
1497
+ {
1498
+ type: "group",
1499
+ key: "__home-connect-advanced",
1500
+ label: "Advanced",
1501
+ labelKey: "provider-bosch:home-connect.s_gateway.__home-connect-advanced.label",
1502
+ style: "accordion",
1503
+ defaultCollapsed: true,
1504
+ fields: [{
1505
+ type: "password",
1506
+ key: "token",
1507
+ label: "Access token",
1508
+ labelKey: "provider-bosch:home-connect.s_gateway.token.label",
1509
+ required: false,
1510
+ showToggle: false
1511
+ }, {
1512
+ type: "password",
1513
+ key: "refresh",
1514
+ label: "Refresh token",
1515
+ labelKey: "provider-bosch:home-connect.s_gateway.refresh.label",
1516
+ required: false,
1517
+ showToggle: false
1518
+ }]
1510
1519
  }
1511
1520
  ]
1512
1521
  }] };
@@ -4612,6 +4621,14 @@ var homeConnectDishwasherSchema = require_dist.object({
4612
4621
  });
4613
4622
  var DISH_CAP = "dishwasher";
4614
4623
  var CONSUMABLES_CAP = "consumables";
4624
+ var RUNNING_CAP = "running-state";
4625
+ var RUNNING_COLD = {
4626
+ running: null,
4627
+ since: null,
4628
+ source: "native",
4629
+ phase: null,
4630
+ lastFetchedAt: 0
4631
+ };
4615
4632
  var CONSUMABLES_EMPTY = {
4616
4633
  items: [],
4617
4634
  lastChangedAt: 0,
@@ -4647,7 +4664,12 @@ var HomeConnectDishwasherDevice = class extends require_dist.BaseDevice {
4647
4664
  await super.onActivate();
4648
4665
  this.registerDishwasherCap();
4649
4666
  this.registerConsumablesCap();
4667
+ this.registerRunningCap();
4650
4668
  this.runtimeState.setCapState(DISH_CAP, COLD_DISHWASHER_STATUS);
4669
+ this.runtimeState.setCapState(RUNNING_CAP, {
4670
+ ...RUNNING_COLD,
4671
+ lastFetchedAt: Date.now()
4672
+ });
4651
4673
  this.markOnline(false);
4652
4674
  this.#unwatch = homeConnectConnections.watch(this.#brokerId, this.#haId, (event) => this.recomputeSlice(event));
4653
4675
  this.recomputeSlice({ kind: "client" });
@@ -4677,6 +4699,7 @@ var HomeConnectDishwasherDevice = class extends require_dist.BaseDevice {
4677
4699
  lastValueAt
4678
4700
  });
4679
4701
  this.runtimeState.setCapState(DISH_CAP, slice);
4702
+ this.publishRunningSlice(slice, lastValueAt);
4680
4703
  this.writeConsumables(dishwasherConsumablesFromFeatures(view));
4681
4704
  this.markOnline(slice.availability !== "offline");
4682
4705
  }
@@ -4779,6 +4802,14 @@ var HomeConnectDishwasherDevice = class extends require_dist.BaseDevice {
4779
4802
  setOption: async ({ key, value }) => this.writeKey(this.requireClient(), key, value)
4780
4803
  });
4781
4804
  }
4805
+ registerRunningCap() {
4806
+ this.ctx.registerNativeCap(require_dist.runningStateCapability, { getStatus: async () => this.runtimeState.getCapState(RUNNING_CAP) ?? RUNNING_COLD });
4807
+ }
4808
+ publishRunningSlice(slice, sinceMs) {
4809
+ const previous = this.runtimeState.getCapState(RUNNING_CAP);
4810
+ const next = require_dist.runningFromDishwasherOperation(slice.operationState, slice.program, previous, sinceMs);
4811
+ this.runtimeState.setCapState(RUNNING_CAP, next);
4812
+ }
4782
4813
  };
4783
4814
  //#endregion
4784
4815
  //#region src/home-connect/devices/home-connect-event-device.ts
@@ -5242,21 +5273,16 @@ var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvide
5242
5273
  ],
5243
5274
  customActions: homeConnectActions,
5244
5275
  actionHandlers: {
5245
- beginSignIn: async () => {
5246
- const started = beginHomeConnectSignIn();
5247
- return {
5248
- authorizeUrl: started.authorizeUrl,
5249
- verifier: started.verifier,
5250
- state: started.state,
5251
- summary: "Open the link in the browser and sign in."
5252
- };
5253
- },
5276
+ beginSignIn: async () => ({
5277
+ ...publishHomeConnectSignIn(homeConnectSignInAttempts, Date.now()),
5278
+ summary: "Open the link in the browser and sign in."
5279
+ }),
5254
5280
  finishSignIn: async (input) => {
5255
- const account = await completeHomeConnectSignIn({
5256
- verifier: input.verifier,
5281
+ const account = await finishHomeConnectSignIn({
5282
+ attemptId: input.attemptId,
5257
5283
  callback: input.callback,
5258
- state: input.state
5259
- });
5284
+ nowMs: Date.now()
5285
+ }, homeConnectSignInAttempts);
5260
5286
  const { rows, secrets } = splitApplianceSecrets(account.appliances.map((app) => ({
5261
5287
  haId: app.haId,
5262
5288
  name: app.name,
@@ -5270,11 +5296,16 @@ var BoschHomeConnectProviderAddon = class extends require_dist.BaseDeviceProvide
5270
5296
  return {
5271
5297
  token: account.token,
5272
5298
  ...account.refresh.length > 0 ? { refresh: account.refresh } : {},
5299
+ accountLabel: account.accountId,
5273
5300
  appliances: JSON.stringify(rows),
5274
5301
  applianceSecrets: JSON.stringify(secrets),
5275
5302
  summary: account.summary
5276
5303
  };
5277
- }
5304
+ },
5305
+ signOut: async () => ({
5306
+ signedOut: true,
5307
+ summary: "Signed out."
5308
+ })
5278
5309
  }
5279
5310
  };
5280
5311
  }