@camstack/addon-provider-bosch 0.1.20 → 0.1.22
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/{account-integration-offline-DvuqXgc8.mjs → account-integration-offline-34gaYDfb.mjs} +44 -2
- package/dist/{account-integration-offline-7DUtQrPy.js → account-integration-offline-DZLHsBZF.js} +55 -1
- package/dist/{dist-CYBUFKeW.js → dist-CRlugVId.js} +569 -104
- package/dist/{dist-B75tWQLF.mjs → dist-DGlq0nuG.mjs} +552 -105
- package/dist/home-connect/addon.js +128 -106
- package/dist/home-connect/addon.mjs +128 -106
- package/dist/homecom/addon.js +557 -433
- package/dist/homecom/addon.mjs +557 -433
- package/dist/shc/addon.js +331 -38
- package/dist/shc/addon.mjs +331 -38
- package/i18n/en.json +23 -19
- package/i18n/it.json +23 -19
- package/package.json +4 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as
|
|
2
|
-
import { n as cascadeRemoveDevicesForIntegration, r as
|
|
1
|
+
import { A as _enum, C as DeviceType, D as defineCustomActions, E as customAction, F as record, I as string, L as union, M as literal, O as isSecretMarker, P as object, R as unknown, S as DeviceRole, T as createEvent, _ as runningFromDishwasherOperation, c as connectionTestCapability, d as dishwasherCapability, f as enumSensorCapability, g as powerMeterCapability, h as numericSensorCapability, i as RUNNING_STATE_COLD, j as array, k as isSecretMarkerLike, l as consumablesCapability, n as BaseDeviceProvider, o as binaryCapability, p as eventEmitterCapability, r as DishwasherOperationStateSchema, t as BaseDevice, u as deviceAdoptionCapability, v as runningStateCapability, w as errMsg, z as EventCategory } from "../dist-DGlq0nuG.mjs";
|
|
2
|
+
import { a as parseOAuthCallback, i as loginFailureForAttempt, n as cascadeRemoveDevicesForIntegration, r as createSignInAttemptStore, t as setIntegrationDevicesOnline } from "../account-integration-offline-34gaYDfb.mjs";
|
|
3
3
|
import { createHash, randomBytes } from "node:crypto";
|
|
4
4
|
import { connect } from "node:tls";
|
|
5
5
|
import { inflateRawSync } from "node:zlib";
|
|
@@ -7,21 +7,20 @@ import { lookup } from "node:dns/promises";
|
|
|
7
7
|
//#region src/home-connect/custom-actions.ts
|
|
8
8
|
var homeConnectActions = defineCustomActions({
|
|
9
9
|
beginSignIn: customAction(object({}), object({
|
|
10
|
+
attemptId: string().min(1),
|
|
10
11
|
authorizeUrl: string().min(1),
|
|
11
|
-
verifier: string().min(1),
|
|
12
|
-
state: string().min(1),
|
|
13
12
|
summary: string()
|
|
14
13
|
}), {
|
|
15
14
|
kind: "mutation",
|
|
16
15
|
auth: "admin"
|
|
17
16
|
}),
|
|
18
17
|
finishSignIn: customAction(object({
|
|
19
|
-
|
|
20
|
-
callback: string().min(1)
|
|
21
|
-
state: string().min(1)
|
|
18
|
+
attemptId: string().min(1),
|
|
19
|
+
callback: string().min(1)
|
|
22
20
|
}), object({
|
|
23
21
|
token: string().min(1).meta({ secret: true }),
|
|
24
22
|
refresh: string().optional().meta({ secret: true }),
|
|
23
|
+
accountLabel: string(),
|
|
25
24
|
/** JSON of the paired appliances — no credential on it. */
|
|
26
25
|
appliances: string().min(1),
|
|
27
26
|
/** JSON of `haId -> { psk, iv64? }`; stored in the keychain, never in `appliances`. */
|
|
@@ -30,6 +29,13 @@ var homeConnectActions = defineCustomActions({
|
|
|
30
29
|
}), {
|
|
31
30
|
kind: "mutation",
|
|
32
31
|
auth: "admin"
|
|
32
|
+
}),
|
|
33
|
+
signOut: customAction(object({}), object({
|
|
34
|
+
signedOut: literal(true),
|
|
35
|
+
summary: string()
|
|
36
|
+
}), {
|
|
37
|
+
kind: "mutation",
|
|
38
|
+
auth: "admin"
|
|
33
39
|
})
|
|
34
40
|
});
|
|
35
41
|
//#endregion
|
|
@@ -601,11 +607,15 @@ var HOME_CONNECT_IDDF_URL = (haId) => `https://eu.services.home-connect.com/api/
|
|
|
601
607
|
//#endregion
|
|
602
608
|
//#region src/home-connect/home-connect-login.ts
|
|
603
609
|
/** Public OAuth client ids from the Home Connect app login (hcpy). */
|
|
604
|
-
var
|
|
605
|
-
var
|
|
610
|
+
var HOME_CONNECT_CLIENT_ID = "9B75AC9EC512F36C84256AC47D813E2C1DD0D6520DF774B020E1E6E2EB29B1F3";
|
|
611
|
+
var HOME_CONNECT_OAUTH_BASE = "https://api.home-connect.com/security/oauth/";
|
|
606
612
|
var ASSET_BASE = "https://eu.services.home-connect.com/";
|
|
607
|
-
var
|
|
608
|
-
var
|
|
613
|
+
var HOME_CONNECT_REDIRECT_URI = "hcauth://auth/prod";
|
|
614
|
+
var HOME_CONNECT_AUTHORIZE_SCOPE = "Control DeleteAppliance IdentifyAppliance Images Monitor ReadAccount ReadOrigApi Settings WriteAppliance WriteOrigApi";
|
|
615
|
+
var APP_ID$1 = HOME_CONNECT_CLIENT_ID;
|
|
616
|
+
var OAUTH_BASE = HOME_CONNECT_OAUTH_BASE;
|
|
617
|
+
var REDIRECT_URI = HOME_CONNECT_REDIRECT_URI;
|
|
618
|
+
var AUTHORIZE_SCOPE = HOME_CONNECT_AUTHORIZE_SCOPE;
|
|
609
619
|
var CookieJar = class {
|
|
610
620
|
#cookies = /* @__PURE__ */ new Map();
|
|
611
621
|
absorb(headers) {
|
|
@@ -811,6 +821,7 @@ async function fetchHomeConnectAccount(creds, fetchImpl = homeConnectLoginFetch)
|
|
|
811
821
|
token,
|
|
812
822
|
refresh,
|
|
813
823
|
appliances,
|
|
824
|
+
accountId: homeConnectAccountLabel(token),
|
|
814
825
|
summary: accountSummary(appliances)
|
|
815
826
|
};
|
|
816
827
|
} catch (err) {
|
|
@@ -823,9 +834,18 @@ async function fetchHomeConnectAccount(creds, fetchImpl = homeConnectLoginFetch)
|
|
|
823
834
|
token: next.token,
|
|
824
835
|
refresh: next.refresh,
|
|
825
836
|
appliances,
|
|
837
|
+
accountId: homeConnectAccountLabel(next.token),
|
|
826
838
|
summary: accountSummary(appliances)
|
|
827
839
|
};
|
|
828
840
|
}
|
|
841
|
+
/** The JWT `sub`, or empty when the token has none. Never throws. */
|
|
842
|
+
function homeConnectAccountLabel(token) {
|
|
843
|
+
try {
|
|
844
|
+
return accountIdFromAccessToken(token);
|
|
845
|
+
} catch {
|
|
846
|
+
return "";
|
|
847
|
+
}
|
|
848
|
+
}
|
|
829
849
|
/**
|
|
830
850
|
* Exchange the refresh token for a new access token. Never throws; a failure says why and
|
|
831
851
|
* carries no credential. A response without a new refresh token keeps the one that was used.
|
|
@@ -948,6 +968,24 @@ async function completeHomeConnectSignIn(input, fetchImpl = homeConnectLoginFetc
|
|
|
948
968
|
}
|
|
949
969
|
return fetchHomeConnectAccount(tokensFromBody(token.body), fetchImpl);
|
|
950
970
|
}
|
|
971
|
+
/** What the form is allowed to see. The verifier stays in `store`. */
|
|
972
|
+
function publishHomeConnectSignIn(store, nowMs) {
|
|
973
|
+
const started = beginHomeConnectSignIn();
|
|
974
|
+
return {
|
|
975
|
+
attemptId: store.put(started.verifier, started.state, nowMs),
|
|
976
|
+
authorizeUrl: started.authorizeUrl
|
|
977
|
+
};
|
|
978
|
+
}
|
|
979
|
+
async function finishHomeConnectSignIn(input, store, fetchImpl = homeConnectLoginFetch) {
|
|
980
|
+
const taken = store.take(input.attemptId, input.nowMs);
|
|
981
|
+
if (!taken.ok) throw new HomeConnectLoginError(loginFailureForAttempt(taken.reason));
|
|
982
|
+
return completeHomeConnectSignIn({
|
|
983
|
+
verifier: taken.attempt.verifier,
|
|
984
|
+
callback: input.callback,
|
|
985
|
+
state: taken.attempt.state
|
|
986
|
+
}, fetchImpl);
|
|
987
|
+
}
|
|
988
|
+
var homeConnectSignInAttempts = createSignInAttemptStore();
|
|
951
989
|
//#endregion
|
|
952
990
|
//#region src/home-connect/home-connect-discovery.ts
|
|
953
991
|
/** Dishwasher accessory label: `Dishwasher` plus the appliance name. */
|
|
@@ -1191,7 +1229,9 @@ var homeConnectStoredApplianceSchema = homeConnectApplianceRowSchema.extend({
|
|
|
1191
1229
|
var homeConnectConfigSchema = object({
|
|
1192
1230
|
token: string().min(1).describe("Home Connect access token").meta({ secret: true }),
|
|
1193
1231
|
refresh: string().optional().describe("Home Connect refresh token").meta({ secret: true }),
|
|
1194
|
-
appliances: array(homeConnectStoredApplianceSchema).optional()
|
|
1232
|
+
appliances: array(homeConnectStoredApplianceSchema).optional(),
|
|
1233
|
+
/** Shown on the sign-in field. The JWT subject, not a credential. */
|
|
1234
|
+
accountLabel: string().optional()
|
|
1195
1235
|
});
|
|
1196
1236
|
function parseJsonValue(raw) {
|
|
1197
1237
|
if (typeof raw !== "string") return raw;
|
|
@@ -1392,103 +1432,49 @@ function sameHomeConnectConnection(a, b) {
|
|
|
1392
1432
|
var HOME_CONNECT_PAIRED_ONLY = "__paired_only__";
|
|
1393
1433
|
function buildHomeConnectFormSchema() {
|
|
1394
1434
|
const pairedOnly = {
|
|
1395
|
-
field: "
|
|
1435
|
+
field: "__hidden__",
|
|
1396
1436
|
equals: HOME_CONNECT_PAIRED_ONLY
|
|
1397
1437
|
};
|
|
1398
1438
|
return { sections: [{
|
|
1399
1439
|
id: "gateway",
|
|
1400
1440
|
title: "Home Connect",
|
|
1401
1441
|
titleKey: "provider-bosch:home-connect.s_gateway.title",
|
|
1402
|
-
description: "
|
|
1442
|
+
description: "Sign in with your Home Connect account. Paste the address the browser stops on (hcauth://auth/prod?code=…).",
|
|
1403
1443
|
descriptionKey: "provider-bosch:home-connect.s_gateway.description",
|
|
1404
1444
|
columns: 1,
|
|
1405
1445
|
fields: [
|
|
1406
1446
|
{
|
|
1407
|
-
type: "
|
|
1447
|
+
type: "account-sign-in",
|
|
1408
1448
|
addonId: "bosch-home-connect",
|
|
1409
|
-
key: "__home-connect-
|
|
1449
|
+
key: "__home-connect-sign-in",
|
|
1410
1450
|
label: "Home Connect",
|
|
1411
|
-
labelKey: "provider-bosch:home-connect.s_gateway.__home-connect-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
label: "Login link",
|
|
1426
|
-
labelKey: "provider-bosch:home-connect.s_gateway.authorizeUrl.label",
|
|
1427
|
-
required: false,
|
|
1428
|
-
omitFromSettings: true
|
|
1429
|
-
},
|
|
1430
|
-
{
|
|
1431
|
-
type: "textarea",
|
|
1432
|
-
key: "callback",
|
|
1433
|
-
label: "Redirect address or code",
|
|
1434
|
-
labelKey: "provider-bosch:home-connect.s_gateway.callback.label",
|
|
1435
|
-
required: false,
|
|
1436
|
-
placeholder: "hcauth://auth/prod?code=…&state=…",
|
|
1437
|
-
omitFromSettings: true
|
|
1438
|
-
},
|
|
1439
|
-
{
|
|
1440
|
-
type: "password",
|
|
1441
|
-
key: "state",
|
|
1442
|
-
label: "Login state",
|
|
1443
|
-
labelKey: "provider-bosch:home-connect.s_gateway.state.label",
|
|
1444
|
-
required: false,
|
|
1445
|
-
omitFromSettings: true,
|
|
1446
|
-
showWhen: pairedOnly
|
|
1447
|
-
},
|
|
1448
|
-
{
|
|
1449
|
-
type: "password",
|
|
1450
|
-
key: "verifier",
|
|
1451
|
-
label: "Login verifier",
|
|
1452
|
-
labelKey: "provider-bosch:home-connect.s_gateway.verifier.label",
|
|
1453
|
-
required: false,
|
|
1454
|
-
omitFromSettings: true,
|
|
1455
|
-
showWhen: pairedOnly
|
|
1456
|
-
},
|
|
1457
|
-
{
|
|
1458
|
-
type: "addon-action-button",
|
|
1459
|
-
addonId: "bosch-home-connect",
|
|
1460
|
-
key: "__home-connect-finish",
|
|
1461
|
-
label: "Finish",
|
|
1462
|
-
labelKey: "provider-bosch:home-connect.s_gateway.__home-connect-finish.label",
|
|
1463
|
-
buttonLabel: "Complete sign-in",
|
|
1464
|
-
action: "finishSignIn",
|
|
1465
|
-
variant: "primary",
|
|
1466
|
-
paramsFromForm: {
|
|
1467
|
-
verifier: "verifier",
|
|
1468
|
-
callback: "callback",
|
|
1469
|
-
state: "state"
|
|
1470
|
-
},
|
|
1451
|
+
labelKey: "provider-bosch:home-connect.s_gateway.__home-connect-sign-in.label",
|
|
1452
|
+
providerLabel: "Home Connect",
|
|
1453
|
+
beginAction: "beginSignIn",
|
|
1454
|
+
completeAction: "finishSignIn",
|
|
1455
|
+
signOutAction: "signOut",
|
|
1456
|
+
accountKey: "accountLabel",
|
|
1457
|
+
countFromKey: "appliances",
|
|
1458
|
+
countNoun: "appliance",
|
|
1459
|
+
pastePlaceholder: "hcauth://auth/prod?code=…&state=…",
|
|
1460
|
+
secretKeys: [
|
|
1461
|
+
"token",
|
|
1462
|
+
"refresh",
|
|
1463
|
+
APPLIANCE_SECRETS_KEY
|
|
1464
|
+
],
|
|
1471
1465
|
assignResult: {
|
|
1472
1466
|
token: "token",
|
|
1473
1467
|
refresh: "refresh",
|
|
1468
|
+
accountLabel: "accountLabel",
|
|
1474
1469
|
appliances: "appliances",
|
|
1475
1470
|
[APPLIANCE_SECRETS_KEY]: APPLIANCE_SECRETS_KEY
|
|
1476
|
-
}
|
|
1477
|
-
successMessage: "{summary}"
|
|
1478
|
-
},
|
|
1479
|
-
{
|
|
1480
|
-
type: "password",
|
|
1481
|
-
key: "token",
|
|
1482
|
-
label: "Access token",
|
|
1483
|
-
labelKey: "provider-bosch:home-connect.s_gateway.token.label",
|
|
1484
|
-
required: true,
|
|
1485
|
-
showWhen: pairedOnly
|
|
1471
|
+
}
|
|
1486
1472
|
},
|
|
1487
1473
|
{
|
|
1488
|
-
type: "
|
|
1489
|
-
key: "
|
|
1490
|
-
label: "
|
|
1491
|
-
labelKey: "provider-bosch:home-connect.s_gateway.
|
|
1474
|
+
type: "text",
|
|
1475
|
+
key: "accountLabel",
|
|
1476
|
+
label: "Account",
|
|
1477
|
+
labelKey: "provider-bosch:home-connect.s_gateway.accountLabel.label",
|
|
1492
1478
|
required: false,
|
|
1493
1479
|
showWhen: pairedOnly
|
|
1494
1480
|
},
|
|
@@ -1497,15 +1483,38 @@ function buildHomeConnectFormSchema() {
|
|
|
1497
1483
|
key: "appliances",
|
|
1498
1484
|
label: "Appliances",
|
|
1499
1485
|
labelKey: "provider-bosch:home-connect.s_gateway.appliances.label",
|
|
1500
|
-
required:
|
|
1486
|
+
required: false,
|
|
1501
1487
|
showWhen: pairedOnly
|
|
1502
1488
|
},
|
|
1503
1489
|
{
|
|
1504
1490
|
type: "password",
|
|
1505
1491
|
key: APPLIANCE_SECRETS_KEY,
|
|
1506
1492
|
label: "Appliance keys",
|
|
1507
|
-
required:
|
|
1493
|
+
required: false,
|
|
1508
1494
|
showWhen: pairedOnly
|
|
1495
|
+
},
|
|
1496
|
+
{
|
|
1497
|
+
type: "group",
|
|
1498
|
+
key: "__home-connect-advanced",
|
|
1499
|
+
label: "Advanced",
|
|
1500
|
+
labelKey: "provider-bosch:home-connect.s_gateway.__home-connect-advanced.label",
|
|
1501
|
+
style: "accordion",
|
|
1502
|
+
defaultCollapsed: true,
|
|
1503
|
+
fields: [{
|
|
1504
|
+
type: "password",
|
|
1505
|
+
key: "token",
|
|
1506
|
+
label: "Access token",
|
|
1507
|
+
labelKey: "provider-bosch:home-connect.s_gateway.token.label",
|
|
1508
|
+
required: false,
|
|
1509
|
+
showToggle: false
|
|
1510
|
+
}, {
|
|
1511
|
+
type: "password",
|
|
1512
|
+
key: "refresh",
|
|
1513
|
+
label: "Refresh token",
|
|
1514
|
+
labelKey: "provider-bosch:home-connect.s_gateway.refresh.label",
|
|
1515
|
+
required: false,
|
|
1516
|
+
showToggle: false
|
|
1517
|
+
}]
|
|
1509
1518
|
}
|
|
1510
1519
|
]
|
|
1511
1520
|
}] };
|
|
@@ -4611,6 +4620,7 @@ var homeConnectDishwasherSchema = object({
|
|
|
4611
4620
|
});
|
|
4612
4621
|
var DISH_CAP = "dishwasher";
|
|
4613
4622
|
var CONSUMABLES_CAP = "consumables";
|
|
4623
|
+
var RUNNING_CAP = "running-state";
|
|
4614
4624
|
var CONSUMABLES_EMPTY = {
|
|
4615
4625
|
items: [],
|
|
4616
4626
|
lastChangedAt: 0,
|
|
@@ -4646,7 +4656,9 @@ var HomeConnectDishwasherDevice = class extends BaseDevice {
|
|
|
4646
4656
|
await super.onActivate();
|
|
4647
4657
|
this.registerDishwasherCap();
|
|
4648
4658
|
this.registerConsumablesCap();
|
|
4659
|
+
this.registerRunningCap();
|
|
4649
4660
|
this.runtimeState.setCapState(DISH_CAP, COLD_DISHWASHER_STATUS);
|
|
4661
|
+
this.runtimeState.setCapState(RUNNING_CAP, RUNNING_STATE_COLD);
|
|
4650
4662
|
this.markOnline(false);
|
|
4651
4663
|
this.#unwatch = homeConnectConnections.watch(this.#brokerId, this.#haId, (event) => this.recomputeSlice(event));
|
|
4652
4664
|
this.recomputeSlice({ kind: "client" });
|
|
@@ -4676,6 +4688,7 @@ var HomeConnectDishwasherDevice = class extends BaseDevice {
|
|
|
4676
4688
|
lastValueAt
|
|
4677
4689
|
});
|
|
4678
4690
|
this.runtimeState.setCapState(DISH_CAP, slice);
|
|
4691
|
+
this.publishRunningSlice(slice);
|
|
4679
4692
|
this.writeConsumables(dishwasherConsumablesFromFeatures(view));
|
|
4680
4693
|
this.markOnline(slice.availability !== "offline");
|
|
4681
4694
|
}
|
|
@@ -4778,6 +4791,15 @@ var HomeConnectDishwasherDevice = class extends BaseDevice {
|
|
|
4778
4791
|
setOption: async ({ key, value }) => this.writeKey(this.requireClient(), key, value)
|
|
4779
4792
|
});
|
|
4780
4793
|
}
|
|
4794
|
+
registerRunningCap() {
|
|
4795
|
+
this.ctx.registerNativeCap(runningStateCapability, { getStatus: async () => this.runtimeState.getCapState(RUNNING_CAP) ?? RUNNING_STATE_COLD });
|
|
4796
|
+
}
|
|
4797
|
+
publishRunningSlice(slice) {
|
|
4798
|
+
const fetchedAt = Date.now();
|
|
4799
|
+
const previous = this.runtimeState.getCapState(RUNNING_CAP);
|
|
4800
|
+
const next = runningFromDishwasherOperation(slice.operationState, slice.program, previous, fetchedAt, slice.remainingSeconds);
|
|
4801
|
+
this.runtimeState.setCapState(RUNNING_CAP, next);
|
|
4802
|
+
}
|
|
4781
4803
|
};
|
|
4782
4804
|
//#endregion
|
|
4783
4805
|
//#region src/home-connect/devices/home-connect-event-device.ts
|
|
@@ -5241,21 +5263,16 @@ var BoschHomeConnectProviderAddon = class extends BaseDeviceProvider {
|
|
|
5241
5263
|
],
|
|
5242
5264
|
customActions: homeConnectActions,
|
|
5243
5265
|
actionHandlers: {
|
|
5244
|
-
beginSignIn: async () => {
|
|
5245
|
-
|
|
5246
|
-
|
|
5247
|
-
|
|
5248
|
-
verifier: started.verifier,
|
|
5249
|
-
state: started.state,
|
|
5250
|
-
summary: "Open the link in the browser and sign in."
|
|
5251
|
-
};
|
|
5252
|
-
},
|
|
5266
|
+
beginSignIn: async () => ({
|
|
5267
|
+
...publishHomeConnectSignIn(homeConnectSignInAttempts, Date.now()),
|
|
5268
|
+
summary: "Open the link in the browser and sign in."
|
|
5269
|
+
}),
|
|
5253
5270
|
finishSignIn: async (input) => {
|
|
5254
|
-
const account = await
|
|
5255
|
-
|
|
5271
|
+
const account = await finishHomeConnectSignIn({
|
|
5272
|
+
attemptId: input.attemptId,
|
|
5256
5273
|
callback: input.callback,
|
|
5257
|
-
|
|
5258
|
-
});
|
|
5274
|
+
nowMs: Date.now()
|
|
5275
|
+
}, homeConnectSignInAttempts);
|
|
5259
5276
|
const { rows, secrets } = splitApplianceSecrets(account.appliances.map((app) => ({
|
|
5260
5277
|
haId: app.haId,
|
|
5261
5278
|
name: app.name,
|
|
@@ -5269,11 +5286,16 @@ var BoschHomeConnectProviderAddon = class extends BaseDeviceProvider {
|
|
|
5269
5286
|
return {
|
|
5270
5287
|
token: account.token,
|
|
5271
5288
|
...account.refresh.length > 0 ? { refresh: account.refresh } : {},
|
|
5289
|
+
accountLabel: account.accountId,
|
|
5272
5290
|
appliances: JSON.stringify(rows),
|
|
5273
5291
|
applianceSecrets: JSON.stringify(secrets),
|
|
5274
5292
|
summary: account.summary
|
|
5275
5293
|
};
|
|
5276
|
-
}
|
|
5294
|
+
},
|
|
5295
|
+
signOut: async () => ({
|
|
5296
|
+
signedOut: true,
|
|
5297
|
+
summary: "Signed out."
|
|
5298
|
+
})
|
|
5277
5299
|
}
|
|
5278
5300
|
};
|
|
5279
5301
|
}
|