@camstack/addon-google-services 0.2.9 → 0.2.10
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/google-services.addon.js +304 -11
- package/dist/google-services.addon.mjs +304 -11
- package/package.json +1 -1
|
@@ -5542,7 +5542,7 @@ var ZodIssueCode = {
|
|
|
5542
5542
|
var ZodFirstPartyTypeKind;
|
|
5543
5543
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5544
5544
|
//#endregion
|
|
5545
|
-
//#region ../types/dist/sleep-
|
|
5545
|
+
//#region ../types/dist/sleep-BOjuyoPC.mjs
|
|
5546
5546
|
/**
|
|
5547
5547
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5548
5548
|
* window to float samples (D455).
|
|
@@ -8771,7 +8771,7 @@ function userError(code, params, englishFallback) {
|
|
|
8771
8771
|
return new CamstackError(code, params, englishFallback);
|
|
8772
8772
|
}
|
|
8773
8773
|
//#endregion
|
|
8774
|
-
//#region ../types/dist/err-msg
|
|
8774
|
+
//#region ../types/dist/err-msg-BXKzRBwg.mjs
|
|
8775
8775
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
8776
8776
|
DeviceType["Camera"] = "camera";
|
|
8777
8777
|
DeviceType["Hub"] = "hub";
|
|
@@ -8863,6 +8863,10 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
8863
8863
|
* native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
|
|
8864
8864
|
* integrations sharing the same food/desiccant/hopper surface. */
|
|
8865
8865
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
8866
|
+
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
8867
|
+
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
8868
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations. */
|
|
8869
|
+
DeviceType["Dishwasher"] = "dishwasher";
|
|
8866
8870
|
return DeviceType;
|
|
8867
8871
|
}({});
|
|
8868
8872
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -9110,7 +9114,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
9110
9114
|
return DeviceRole;
|
|
9111
9115
|
}({});
|
|
9112
9116
|
//#endregion
|
|
9113
|
-
//#region ../types/dist/composition-
|
|
9117
|
+
//#region ../types/dist/composition-CB6PMT9p.mjs
|
|
9114
9118
|
/**
|
|
9115
9119
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
9116
9120
|
*
|
|
@@ -13632,8 +13636,13 @@ var AlertSeveritySchema = _enum([
|
|
|
13632
13636
|
"info",
|
|
13633
13637
|
"success",
|
|
13634
13638
|
"warning",
|
|
13635
|
-
"error"
|
|
13639
|
+
"error",
|
|
13640
|
+
"critical"
|
|
13636
13641
|
]);
|
|
13642
|
+
var AlertActionSchema = object({
|
|
13643
|
+
label: string(),
|
|
13644
|
+
href: string().optional()
|
|
13645
|
+
});
|
|
13637
13646
|
var AlertStatusSchema = _enum([
|
|
13638
13647
|
"active",
|
|
13639
13648
|
"in-progress",
|
|
@@ -13651,6 +13660,7 @@ var AlertSchema = object({
|
|
|
13651
13660
|
severity: AlertSeveritySchema,
|
|
13652
13661
|
title: string(),
|
|
13653
13662
|
message: string(),
|
|
13663
|
+
action: AlertActionSchema.optional(),
|
|
13654
13664
|
status: AlertStatusSchema,
|
|
13655
13665
|
progress: number().optional(),
|
|
13656
13666
|
read: boolean(),
|
|
@@ -53647,7 +53657,7 @@ var BatteryStatusSchema = object({
|
|
|
53647
53657
|
*/
|
|
53648
53658
|
binary: boolean().optional()
|
|
53649
53659
|
});
|
|
53650
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, method(object({
|
|
53660
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, method(object({
|
|
53651
53661
|
deviceId: number(),
|
|
53652
53662
|
/** Bound on the wait. Sensible range 3000–10000ms. */
|
|
53653
53663
|
timeoutMs: number().int().min(500).max(3e4).default(8e3)
|
|
@@ -54533,6 +54543,98 @@ object({
|
|
|
54533
54543
|
deviceId: number(),
|
|
54534
54544
|
status: DeviceStatusSchema
|
|
54535
54545
|
});
|
|
54546
|
+
/**
|
|
54547
|
+
* Smart-dishwasher cap — program lifecycle, door / remote-start gates,
|
|
54548
|
+
* consumable levels (salt, rinse aid) and common program options.
|
|
54549
|
+
*
|
|
54550
|
+
* Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
|
|
54551
|
+
* by any integration that exposes the same program / option surface.
|
|
54552
|
+
*
|
|
54553
|
+
* `kind: 'poll'` — cloud REST APIs typically have no push channel; the
|
|
54554
|
+
* provider refreshes the slice on an interval and eagerly after commands.
|
|
54555
|
+
*/
|
|
54556
|
+
var DishwasherStateSchema = _enum([
|
|
54557
|
+
"idle",
|
|
54558
|
+
"running",
|
|
54559
|
+
"paused",
|
|
54560
|
+
"finished",
|
|
54561
|
+
"error",
|
|
54562
|
+
"unavailable"
|
|
54563
|
+
]);
|
|
54564
|
+
var DishwasherConsumableLevelSchema = _enum([
|
|
54565
|
+
"ok",
|
|
54566
|
+
"low",
|
|
54567
|
+
"empty"
|
|
54568
|
+
]);
|
|
54569
|
+
object({
|
|
54570
|
+
state: DishwasherStateSchema,
|
|
54571
|
+
/** Active program id/name, or null when none selected / unknown. */
|
|
54572
|
+
program: string().nullable(),
|
|
54573
|
+
/** Program tokens the hardware accepts — drives the UI selector. */
|
|
54574
|
+
availablePrograms: array(string()),
|
|
54575
|
+
/** Minutes remaining on the active cycle, or null when not running. */
|
|
54576
|
+
remainingMinutes: number().int().nonnegative().nullable(),
|
|
54577
|
+
/** Cycle completion 0..100, or null when not applicable. */
|
|
54578
|
+
progressPercent: number().min(0).max(100).nullable(),
|
|
54579
|
+
/** True when the door is reported open. */
|
|
54580
|
+
doorOpen: boolean(),
|
|
54581
|
+
/** True when remote start is allowed (door closed, power on, etc.). */
|
|
54582
|
+
remoteStartAllowed: boolean(),
|
|
54583
|
+
/** Main power / switched-on state. */
|
|
54584
|
+
powerOn: boolean(),
|
|
54585
|
+
saltLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
54586
|
+
rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
54587
|
+
halfLoad: boolean(),
|
|
54588
|
+
hygienePlus: boolean(),
|
|
54589
|
+
errorCode: number().nullable(),
|
|
54590
|
+
errorLabel: string().nullable(),
|
|
54591
|
+
lastFetchedAt: number()
|
|
54592
|
+
});
|
|
54593
|
+
DeviceType.Dishwasher, method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
54594
|
+
kind: "mutation",
|
|
54595
|
+
auth: "protected"
|
|
54596
|
+
}), method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
54597
|
+
kind: "mutation",
|
|
54598
|
+
auth: "protected"
|
|
54599
|
+
}), method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
54600
|
+
kind: "mutation",
|
|
54601
|
+
auth: "protected"
|
|
54602
|
+
}), method(object({
|
|
54603
|
+
deviceId: number().int().nonnegative(),
|
|
54604
|
+
program: string().min(1)
|
|
54605
|
+
}), _void(), {
|
|
54606
|
+
kind: "mutation",
|
|
54607
|
+
auth: "protected"
|
|
54608
|
+
}), method(object({
|
|
54609
|
+
deviceId: number().int().nonnegative(),
|
|
54610
|
+
on: boolean()
|
|
54611
|
+
}), _void(), {
|
|
54612
|
+
kind: "mutation",
|
|
54613
|
+
auth: "protected"
|
|
54614
|
+
}), method(object({
|
|
54615
|
+
deviceId: number().int().nonnegative(),
|
|
54616
|
+
on: boolean()
|
|
54617
|
+
}), _void(), {
|
|
54618
|
+
kind: "mutation",
|
|
54619
|
+
auth: "protected"
|
|
54620
|
+
}), method(object({
|
|
54621
|
+
deviceId: number().int().nonnegative(),
|
|
54622
|
+
on: boolean()
|
|
54623
|
+
}), _void(), {
|
|
54624
|
+
kind: "mutation",
|
|
54625
|
+
auth: "protected"
|
|
54626
|
+
}), method(object({
|
|
54627
|
+
deviceId: number().int().nonnegative(),
|
|
54628
|
+
key: string().min(1),
|
|
54629
|
+
value: union([
|
|
54630
|
+
boolean(),
|
|
54631
|
+
string(),
|
|
54632
|
+
number()
|
|
54633
|
+
])
|
|
54634
|
+
}), _void(), {
|
|
54635
|
+
kind: "mutation",
|
|
54636
|
+
auth: "protected"
|
|
54637
|
+
});
|
|
54536
54638
|
object({
|
|
54537
54639
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
54538
54640
|
lastPressedAt: number().nullable(),
|
|
@@ -55098,6 +55200,13 @@ object({
|
|
|
55098
55200
|
lastChangedAt: number()
|
|
55099
55201
|
});
|
|
55100
55202
|
DeviceType.Sensor;
|
|
55203
|
+
object({
|
|
55204
|
+
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
55205
|
+
position: number().min(0).max(100).nullable(),
|
|
55206
|
+
/** Ms epoch when the slice was last updated (push or poll). */
|
|
55207
|
+
lastFetchedAt: number()
|
|
55208
|
+
});
|
|
55209
|
+
DeviceType.Thermostat;
|
|
55101
55210
|
object({
|
|
55102
55211
|
/** Whether the humidifier is currently on. */
|
|
55103
55212
|
on: boolean(),
|
|
@@ -62164,7 +62273,7 @@ var AccessoryKind = {
|
|
|
62164
62273
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
62165
62274
|
};
|
|
62166
62275
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
62167
|
-
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
|
|
62276
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
|
|
62168
62277
|
new Set(Object.values(DeviceType));
|
|
62169
62278
|
Object.freeze({
|
|
62170
62279
|
"accessories.getStatus": {
|
|
@@ -64585,6 +64694,60 @@ Object.freeze({
|
|
|
64585
64694
|
addonId: null,
|
|
64586
64695
|
access: "view"
|
|
64587
64696
|
},
|
|
64697
|
+
"dishwasher.getStatus": {
|
|
64698
|
+
capName: "dishwasher",
|
|
64699
|
+
capScope: "device",
|
|
64700
|
+
addonId: null,
|
|
64701
|
+
access: "view"
|
|
64702
|
+
},
|
|
64703
|
+
"dishwasher.pause": {
|
|
64704
|
+
capName: "dishwasher",
|
|
64705
|
+
capScope: "device",
|
|
64706
|
+
addonId: null,
|
|
64707
|
+
access: "create"
|
|
64708
|
+
},
|
|
64709
|
+
"dishwasher.setHalfLoad": {
|
|
64710
|
+
capName: "dishwasher",
|
|
64711
|
+
capScope: "device",
|
|
64712
|
+
addonId: null,
|
|
64713
|
+
access: "create"
|
|
64714
|
+
},
|
|
64715
|
+
"dishwasher.setHygienePlus": {
|
|
64716
|
+
capName: "dishwasher",
|
|
64717
|
+
capScope: "device",
|
|
64718
|
+
addonId: null,
|
|
64719
|
+
access: "create"
|
|
64720
|
+
},
|
|
64721
|
+
"dishwasher.setOption": {
|
|
64722
|
+
capName: "dishwasher",
|
|
64723
|
+
capScope: "device",
|
|
64724
|
+
addonId: null,
|
|
64725
|
+
access: "create"
|
|
64726
|
+
},
|
|
64727
|
+
"dishwasher.setPower": {
|
|
64728
|
+
capName: "dishwasher",
|
|
64729
|
+
capScope: "device",
|
|
64730
|
+
addonId: null,
|
|
64731
|
+
access: "create"
|
|
64732
|
+
},
|
|
64733
|
+
"dishwasher.setProgram": {
|
|
64734
|
+
capName: "dishwasher",
|
|
64735
|
+
capScope: "device",
|
|
64736
|
+
addonId: null,
|
|
64737
|
+
access: "create"
|
|
64738
|
+
},
|
|
64739
|
+
"dishwasher.start": {
|
|
64740
|
+
capName: "dishwasher",
|
|
64741
|
+
capScope: "device",
|
|
64742
|
+
addonId: null,
|
|
64743
|
+
access: "create"
|
|
64744
|
+
},
|
|
64745
|
+
"dishwasher.stop": {
|
|
64746
|
+
capName: "dishwasher",
|
|
64747
|
+
capScope: "device",
|
|
64748
|
+
addonId: null,
|
|
64749
|
+
access: "create"
|
|
64750
|
+
},
|
|
64588
64751
|
"doorbell.getStatus": {
|
|
64589
64752
|
capName: "doorbell",
|
|
64590
64753
|
capScope: "device",
|
|
@@ -64795,6 +64958,12 @@ Object.freeze({
|
|
|
64795
64958
|
addonId: null,
|
|
64796
64959
|
access: "view"
|
|
64797
64960
|
},
|
|
64961
|
+
"heatingValve.getStatus": {
|
|
64962
|
+
capName: "heating-valve",
|
|
64963
|
+
capScope: "device",
|
|
64964
|
+
addonId: null,
|
|
64965
|
+
access: "view"
|
|
64966
|
+
},
|
|
64798
64967
|
"humidifier.getStatus": {
|
|
64799
64968
|
capName: "humidifier",
|
|
64800
64969
|
capScope: "device",
|
|
@@ -70382,7 +70551,7 @@ Object.freeze({
|
|
|
70382
70551
|
access: "create"
|
|
70383
70552
|
}
|
|
70384
70553
|
});
|
|
70385
|
-
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
|
|
70554
|
+
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
|
|
70386
70555
|
DeviceFeature.BatteryOperated;
|
|
70387
70556
|
Object.freeze({
|
|
70388
70557
|
"accessories.getStatus": [{
|
|
@@ -71206,6 +71375,51 @@ Object.freeze({
|
|
|
71206
71375
|
form: "single",
|
|
71207
71376
|
optional: false
|
|
71208
71377
|
}],
|
|
71378
|
+
"dishwasher.getStatus": [{
|
|
71379
|
+
name: "deviceId",
|
|
71380
|
+
form: "single",
|
|
71381
|
+
optional: false
|
|
71382
|
+
}],
|
|
71383
|
+
"dishwasher.pause": [{
|
|
71384
|
+
name: "deviceId",
|
|
71385
|
+
form: "single",
|
|
71386
|
+
optional: false
|
|
71387
|
+
}],
|
|
71388
|
+
"dishwasher.setHalfLoad": [{
|
|
71389
|
+
name: "deviceId",
|
|
71390
|
+
form: "single",
|
|
71391
|
+
optional: false
|
|
71392
|
+
}],
|
|
71393
|
+
"dishwasher.setHygienePlus": [{
|
|
71394
|
+
name: "deviceId",
|
|
71395
|
+
form: "single",
|
|
71396
|
+
optional: false
|
|
71397
|
+
}],
|
|
71398
|
+
"dishwasher.setOption": [{
|
|
71399
|
+
name: "deviceId",
|
|
71400
|
+
form: "single",
|
|
71401
|
+
optional: false
|
|
71402
|
+
}],
|
|
71403
|
+
"dishwasher.setPower": [{
|
|
71404
|
+
name: "deviceId",
|
|
71405
|
+
form: "single",
|
|
71406
|
+
optional: false
|
|
71407
|
+
}],
|
|
71408
|
+
"dishwasher.setProgram": [{
|
|
71409
|
+
name: "deviceId",
|
|
71410
|
+
form: "single",
|
|
71411
|
+
optional: false
|
|
71412
|
+
}],
|
|
71413
|
+
"dishwasher.start": [{
|
|
71414
|
+
name: "deviceId",
|
|
71415
|
+
form: "single",
|
|
71416
|
+
optional: false
|
|
71417
|
+
}],
|
|
71418
|
+
"dishwasher.stop": [{
|
|
71419
|
+
name: "deviceId",
|
|
71420
|
+
form: "single",
|
|
71421
|
+
optional: false
|
|
71422
|
+
}],
|
|
71209
71423
|
"doorbell.getStatus": [{
|
|
71210
71424
|
name: "deviceId",
|
|
71211
71425
|
form: "single",
|
|
@@ -71275,6 +71489,11 @@ Object.freeze({
|
|
|
71275
71489
|
form: "single",
|
|
71276
71490
|
optional: false
|
|
71277
71491
|
}],
|
|
71492
|
+
"heatingValve.getStatus": [{
|
|
71493
|
+
name: "deviceId",
|
|
71494
|
+
form: "single",
|
|
71495
|
+
optional: false
|
|
71496
|
+
}],
|
|
71278
71497
|
"humidifier.getStatus": [{
|
|
71279
71498
|
name: "deviceId",
|
|
71280
71499
|
form: "single",
|
|
@@ -74970,6 +75189,40 @@ function createGmailSmtpProvider(deps) {
|
|
|
74970
75189
|
};
|
|
74971
75190
|
}
|
|
74972
75191
|
//#endregion
|
|
75192
|
+
//#region src/google-broker-reconnect-alert.ts
|
|
75193
|
+
function googleBrokerReconnectAlertId(brokerId) {
|
|
75194
|
+
return `google-broker:${brokerId}`;
|
|
75195
|
+
}
|
|
75196
|
+
function isInvalidGrantRefreshError(err) {
|
|
75197
|
+
return (err instanceof Error ? err.message : String(err)).includes("invalid_grant");
|
|
75198
|
+
}
|
|
75199
|
+
function buildGoogleBrokerReconnectAlert(brokerId, brokerName) {
|
|
75200
|
+
const pushLine = `${brokerName}: Google session expired — sign in again`;
|
|
75201
|
+
return {
|
|
75202
|
+
id: googleBrokerReconnectAlertId(brokerId),
|
|
75203
|
+
category: "google.broker-reconnect",
|
|
75204
|
+
severity: "critical",
|
|
75205
|
+
title: "Google needs a new sign-in",
|
|
75206
|
+
message: `${brokerName} needs you to sign in to Google again.`,
|
|
75207
|
+
action: {
|
|
75208
|
+
label: "Sign in again",
|
|
75209
|
+
href: `/addon/google-services/oauth/start?brokerId=${encodeURIComponent(brokerId)}`
|
|
75210
|
+
},
|
|
75211
|
+
status: "active",
|
|
75212
|
+
read: false,
|
|
75213
|
+
createdAt: Date.now(),
|
|
75214
|
+
updatedAt: Date.now(),
|
|
75215
|
+
source: {
|
|
75216
|
+
type: "google-broker",
|
|
75217
|
+
id: brokerId
|
|
75218
|
+
},
|
|
75219
|
+
metadata: {
|
|
75220
|
+
episodeKey: "reconnect",
|
|
75221
|
+
pushLine
|
|
75222
|
+
}
|
|
75223
|
+
};
|
|
75224
|
+
}
|
|
75225
|
+
//#endregion
|
|
74973
75226
|
//#region src/google-oauth.ts
|
|
74974
75227
|
/**
|
|
74975
75228
|
* Google OAuth2 authorization-code + refresh for Calendar API.
|
|
@@ -75585,6 +75838,7 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
75585
75838
|
};
|
|
75586
75839
|
this.registry.setOauth(next);
|
|
75587
75840
|
await this.persistOauthAccounts();
|
|
75841
|
+
if (next.refreshToken.length > 0) this.resolveGoogleBrokerReconnectAlert(brokerId);
|
|
75588
75842
|
if (next.accountEmail && (entry.name === "Google account" || entry.name.startsWith("google_"))) {
|
|
75589
75843
|
const renamed = {
|
|
75590
75844
|
...entry,
|
|
@@ -75717,6 +75971,39 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
75717
75971
|
}
|
|
75718
75972
|
return out.toSorted((a, b) => a.label.localeCompare(b.label));
|
|
75719
75973
|
}
|
|
75974
|
+
async emitGoogleBrokerReconnectAlert(brokerId, brokerName) {
|
|
75975
|
+
const emit = this.ctx.api.alerts?.emit;
|
|
75976
|
+
if (emit === void 0) {
|
|
75977
|
+
this.ctx.logger.warn("google broker reconnect alert skipped — alerts capability missing", { meta: { brokerId } });
|
|
75978
|
+
return;
|
|
75979
|
+
}
|
|
75980
|
+
try {
|
|
75981
|
+
await emit.mutate(buildGoogleBrokerReconnectAlert(brokerId, brokerName));
|
|
75982
|
+
} catch (err) {
|
|
75983
|
+
this.ctx.logger.warn("google broker reconnect alert emit failed", { meta: {
|
|
75984
|
+
brokerId,
|
|
75985
|
+
error: err instanceof Error ? err.message : String(err)
|
|
75986
|
+
} });
|
|
75987
|
+
}
|
|
75988
|
+
}
|
|
75989
|
+
async resolveGoogleBrokerReconnectAlert(brokerId) {
|
|
75990
|
+
const update = this.ctx.api.alerts?.update;
|
|
75991
|
+
if (update === void 0) return;
|
|
75992
|
+
try {
|
|
75993
|
+
await update.mutate({
|
|
75994
|
+
alertId: googleBrokerReconnectAlertId(brokerId),
|
|
75995
|
+
patch: {
|
|
75996
|
+
status: "completed",
|
|
75997
|
+
read: true
|
|
75998
|
+
}
|
|
75999
|
+
});
|
|
76000
|
+
} catch (err) {
|
|
76001
|
+
this.ctx.logger.warn("google broker reconnect alert resolve failed", { meta: {
|
|
76002
|
+
brokerId,
|
|
76003
|
+
error: err instanceof Error ? err.message : String(err)
|
|
76004
|
+
} });
|
|
76005
|
+
}
|
|
76006
|
+
}
|
|
75720
76007
|
async ensureAccessToken(brokerId, opts = {}) {
|
|
75721
76008
|
const entry = this.registry.getEntry(brokerId);
|
|
75722
76009
|
const oauth = this.registry.getOauth(brokerId);
|
|
@@ -75729,10 +76016,16 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
75729
76016
|
accountEmail: oauth.accountEmail
|
|
75730
76017
|
};
|
|
75731
76018
|
if (!opts.forceRefresh && !needsRefresh(state)) return state.accessToken;
|
|
75732
|
-
|
|
75733
|
-
|
|
75734
|
-
|
|
75735
|
-
|
|
76019
|
+
let tokens;
|
|
76020
|
+
try {
|
|
76021
|
+
tokens = await refreshAccessToken({
|
|
76022
|
+
clientId: entry.clientId.trim(),
|
|
76023
|
+
clientSecret: entry.clientSecret.trim()
|
|
76024
|
+
}, state.refreshToken);
|
|
76025
|
+
} catch (err) {
|
|
76026
|
+
if (isInvalidGrantRefreshError(err)) this.emitGoogleBrokerReconnectAlert(brokerId, entry.name);
|
|
76027
|
+
throw err;
|
|
76028
|
+
}
|
|
75736
76029
|
if (typeof tokens.access_token !== "string" || tokens.access_token.trim().length === 0) throw new Error("Google token refresh returned an empty access_token — Sign out and Sign in again");
|
|
75737
76030
|
const nextState = applyTokenResponse(state, tokens);
|
|
75738
76031
|
this.registry.setOauth({
|
|
@@ -5538,7 +5538,7 @@ var ZodIssueCode = {
|
|
|
5538
5538
|
var ZodFirstPartyTypeKind;
|
|
5539
5539
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5540
5540
|
//#endregion
|
|
5541
|
-
//#region ../types/dist/sleep-
|
|
5541
|
+
//#region ../types/dist/sleep-BOjuyoPC.mjs
|
|
5542
5542
|
/**
|
|
5543
5543
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5544
5544
|
* window to float samples (D455).
|
|
@@ -8767,7 +8767,7 @@ function userError(code, params, englishFallback) {
|
|
|
8767
8767
|
return new CamstackError(code, params, englishFallback);
|
|
8768
8768
|
}
|
|
8769
8769
|
//#endregion
|
|
8770
|
-
//#region ../types/dist/err-msg
|
|
8770
|
+
//#region ../types/dist/err-msg-BXKzRBwg.mjs
|
|
8771
8771
|
var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
8772
8772
|
DeviceType["Camera"] = "camera";
|
|
8773
8773
|
DeviceType["Hub"] = "hub";
|
|
@@ -8859,6 +8859,10 @@ var DeviceType = /* @__PURE__ */ function(DeviceType) {
|
|
|
8859
8859
|
* native PetKit (`nodepetkit` `FeederDevice`), reusable by other feeder
|
|
8860
8860
|
* integrations sharing the same food/desiccant/hopper surface. */
|
|
8861
8861
|
DeviceType["PetFeeder"] = "pet-feeder";
|
|
8862
|
+
/** Built-in dishwasher — program lifecycle, door / remote-start gates,
|
|
8863
|
+
* salt and rinse-aid levels. Installed with the `dishwasher` cap.
|
|
8864
|
+
* Sources: native Bosch Home Connect, reusable by similar integrations. */
|
|
8865
|
+
DeviceType["Dishwasher"] = "dishwasher";
|
|
8862
8866
|
return DeviceType;
|
|
8863
8867
|
}({});
|
|
8864
8868
|
var DeviceFeature = /* @__PURE__ */ function(DeviceFeature) {
|
|
@@ -9106,7 +9110,7 @@ var DeviceRole = /* @__PURE__ */ function(DeviceRole) {
|
|
|
9106
9110
|
return DeviceRole;
|
|
9107
9111
|
}({});
|
|
9108
9112
|
//#endregion
|
|
9109
|
-
//#region ../types/dist/composition-
|
|
9113
|
+
//#region ../types/dist/composition-CB6PMT9p.mjs
|
|
9110
9114
|
/**
|
|
9111
9115
|
* The ffmpeg build every CamStack node downloads, per platform and arch.
|
|
9112
9116
|
*
|
|
@@ -13628,8 +13632,13 @@ var AlertSeveritySchema = _enum([
|
|
|
13628
13632
|
"info",
|
|
13629
13633
|
"success",
|
|
13630
13634
|
"warning",
|
|
13631
|
-
"error"
|
|
13635
|
+
"error",
|
|
13636
|
+
"critical"
|
|
13632
13637
|
]);
|
|
13638
|
+
var AlertActionSchema = object({
|
|
13639
|
+
label: string(),
|
|
13640
|
+
href: string().optional()
|
|
13641
|
+
});
|
|
13633
13642
|
var AlertStatusSchema = _enum([
|
|
13634
13643
|
"active",
|
|
13635
13644
|
"in-progress",
|
|
@@ -13647,6 +13656,7 @@ var AlertSchema = object({
|
|
|
13647
13656
|
severity: AlertSeveritySchema,
|
|
13648
13657
|
title: string(),
|
|
13649
13658
|
message: string(),
|
|
13659
|
+
action: AlertActionSchema.optional(),
|
|
13650
13660
|
status: AlertStatusSchema,
|
|
13651
13661
|
progress: number().optional(),
|
|
13652
13662
|
read: boolean(),
|
|
@@ -53643,7 +53653,7 @@ var BatteryStatusSchema = object({
|
|
|
53643
53653
|
*/
|
|
53644
53654
|
binary: boolean().optional()
|
|
53645
53655
|
});
|
|
53646
|
-
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, method(object({
|
|
53656
|
+
DeviceType.Camera, DeviceType.Sensor, DeviceType.Button, DeviceType.Switch, DeviceType.PetFeeder, DeviceType.Container, DeviceType.Thermostat, method(object({
|
|
53647
53657
|
deviceId: number(),
|
|
53648
53658
|
/** Bound on the wait. Sensible range 3000–10000ms. */
|
|
53649
53659
|
timeoutMs: number().int().min(500).max(3e4).default(8e3)
|
|
@@ -54529,6 +54539,98 @@ object({
|
|
|
54529
54539
|
deviceId: number(),
|
|
54530
54540
|
status: DeviceStatusSchema
|
|
54531
54541
|
});
|
|
54542
|
+
/**
|
|
54543
|
+
* Smart-dishwasher cap — program lifecycle, door / remote-start gates,
|
|
54544
|
+
* consumable levels (salt, rinse aid) and common program options.
|
|
54545
|
+
*
|
|
54546
|
+
* Sources: native Bosch Home Connect (`dishwasher` device type). Reusable
|
|
54547
|
+
* by any integration that exposes the same program / option surface.
|
|
54548
|
+
*
|
|
54549
|
+
* `kind: 'poll'` — cloud REST APIs typically have no push channel; the
|
|
54550
|
+
* provider refreshes the slice on an interval and eagerly after commands.
|
|
54551
|
+
*/
|
|
54552
|
+
var DishwasherStateSchema = _enum([
|
|
54553
|
+
"idle",
|
|
54554
|
+
"running",
|
|
54555
|
+
"paused",
|
|
54556
|
+
"finished",
|
|
54557
|
+
"error",
|
|
54558
|
+
"unavailable"
|
|
54559
|
+
]);
|
|
54560
|
+
var DishwasherConsumableLevelSchema = _enum([
|
|
54561
|
+
"ok",
|
|
54562
|
+
"low",
|
|
54563
|
+
"empty"
|
|
54564
|
+
]);
|
|
54565
|
+
object({
|
|
54566
|
+
state: DishwasherStateSchema,
|
|
54567
|
+
/** Active program id/name, or null when none selected / unknown. */
|
|
54568
|
+
program: string().nullable(),
|
|
54569
|
+
/** Program tokens the hardware accepts — drives the UI selector. */
|
|
54570
|
+
availablePrograms: array(string()),
|
|
54571
|
+
/** Minutes remaining on the active cycle, or null when not running. */
|
|
54572
|
+
remainingMinutes: number().int().nonnegative().nullable(),
|
|
54573
|
+
/** Cycle completion 0..100, or null when not applicable. */
|
|
54574
|
+
progressPercent: number().min(0).max(100).nullable(),
|
|
54575
|
+
/** True when the door is reported open. */
|
|
54576
|
+
doorOpen: boolean(),
|
|
54577
|
+
/** True when remote start is allowed (door closed, power on, etc.). */
|
|
54578
|
+
remoteStartAllowed: boolean(),
|
|
54579
|
+
/** Main power / switched-on state. */
|
|
54580
|
+
powerOn: boolean(),
|
|
54581
|
+
saltLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
54582
|
+
rinseAidLevel: DishwasherConsumableLevelSchema.nullable(),
|
|
54583
|
+
halfLoad: boolean(),
|
|
54584
|
+
hygienePlus: boolean(),
|
|
54585
|
+
errorCode: number().nullable(),
|
|
54586
|
+
errorLabel: string().nullable(),
|
|
54587
|
+
lastFetchedAt: number()
|
|
54588
|
+
});
|
|
54589
|
+
DeviceType.Dishwasher, method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
54590
|
+
kind: "mutation",
|
|
54591
|
+
auth: "protected"
|
|
54592
|
+
}), method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
54593
|
+
kind: "mutation",
|
|
54594
|
+
auth: "protected"
|
|
54595
|
+
}), method(object({ deviceId: number().int().nonnegative() }), _void(), {
|
|
54596
|
+
kind: "mutation",
|
|
54597
|
+
auth: "protected"
|
|
54598
|
+
}), method(object({
|
|
54599
|
+
deviceId: number().int().nonnegative(),
|
|
54600
|
+
program: string().min(1)
|
|
54601
|
+
}), _void(), {
|
|
54602
|
+
kind: "mutation",
|
|
54603
|
+
auth: "protected"
|
|
54604
|
+
}), method(object({
|
|
54605
|
+
deviceId: number().int().nonnegative(),
|
|
54606
|
+
on: boolean()
|
|
54607
|
+
}), _void(), {
|
|
54608
|
+
kind: "mutation",
|
|
54609
|
+
auth: "protected"
|
|
54610
|
+
}), method(object({
|
|
54611
|
+
deviceId: number().int().nonnegative(),
|
|
54612
|
+
on: boolean()
|
|
54613
|
+
}), _void(), {
|
|
54614
|
+
kind: "mutation",
|
|
54615
|
+
auth: "protected"
|
|
54616
|
+
}), method(object({
|
|
54617
|
+
deviceId: number().int().nonnegative(),
|
|
54618
|
+
on: boolean()
|
|
54619
|
+
}), _void(), {
|
|
54620
|
+
kind: "mutation",
|
|
54621
|
+
auth: "protected"
|
|
54622
|
+
}), method(object({
|
|
54623
|
+
deviceId: number().int().nonnegative(),
|
|
54624
|
+
key: string().min(1),
|
|
54625
|
+
value: union([
|
|
54626
|
+
boolean(),
|
|
54627
|
+
string(),
|
|
54628
|
+
number()
|
|
54629
|
+
])
|
|
54630
|
+
}), _void(), {
|
|
54631
|
+
kind: "mutation",
|
|
54632
|
+
auth: "protected"
|
|
54633
|
+
});
|
|
54532
54634
|
object({
|
|
54533
54635
|
/** Ms epoch of the last press. null = never observed since this provider started. */
|
|
54534
54636
|
lastPressedAt: number().nullable(),
|
|
@@ -55094,6 +55196,13 @@ object({
|
|
|
55094
55196
|
lastChangedAt: number()
|
|
55095
55197
|
});
|
|
55096
55198
|
DeviceType.Sensor;
|
|
55199
|
+
object({
|
|
55200
|
+
/** Radiator valve opening 0 (closed) .. 100 (open). Null = not yet known. */
|
|
55201
|
+
position: number().min(0).max(100).nullable(),
|
|
55202
|
+
/** Ms epoch when the slice was last updated (push or poll). */
|
|
55203
|
+
lastFetchedAt: number()
|
|
55204
|
+
});
|
|
55205
|
+
DeviceType.Thermostat;
|
|
55097
55206
|
object({
|
|
55098
55207
|
/** Whether the humidifier is currently on. */
|
|
55099
55208
|
on: boolean(),
|
|
@@ -62160,7 +62269,7 @@ var AccessoryKind = {
|
|
|
62160
62269
|
PrivacyMask: DeviceRole.PrivacyMask
|
|
62161
62270
|
};
|
|
62162
62271
|
AccessoryKind.Siren, AccessoryKind.Floodlight, AccessoryKind.Spotlight, AccessoryKind.PirSensor, AccessoryKind.Chime, AccessoryKind.Autotrack, AccessoryKind.Nightvision, AccessoryKind.PrivacyMask;
|
|
62163
|
-
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
|
|
62272
|
+
DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Camera, DeviceType.Hub, DeviceType.Switch, DeviceType.Siren, DeviceType.Light, DeviceType.Fan, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
|
|
62164
62273
|
new Set(Object.values(DeviceType));
|
|
62165
62274
|
Object.freeze({
|
|
62166
62275
|
"accessories.getStatus": {
|
|
@@ -64581,6 +64690,60 @@ Object.freeze({
|
|
|
64581
64690
|
addonId: null,
|
|
64582
64691
|
access: "view"
|
|
64583
64692
|
},
|
|
64693
|
+
"dishwasher.getStatus": {
|
|
64694
|
+
capName: "dishwasher",
|
|
64695
|
+
capScope: "device",
|
|
64696
|
+
addonId: null,
|
|
64697
|
+
access: "view"
|
|
64698
|
+
},
|
|
64699
|
+
"dishwasher.pause": {
|
|
64700
|
+
capName: "dishwasher",
|
|
64701
|
+
capScope: "device",
|
|
64702
|
+
addonId: null,
|
|
64703
|
+
access: "create"
|
|
64704
|
+
},
|
|
64705
|
+
"dishwasher.setHalfLoad": {
|
|
64706
|
+
capName: "dishwasher",
|
|
64707
|
+
capScope: "device",
|
|
64708
|
+
addonId: null,
|
|
64709
|
+
access: "create"
|
|
64710
|
+
},
|
|
64711
|
+
"dishwasher.setHygienePlus": {
|
|
64712
|
+
capName: "dishwasher",
|
|
64713
|
+
capScope: "device",
|
|
64714
|
+
addonId: null,
|
|
64715
|
+
access: "create"
|
|
64716
|
+
},
|
|
64717
|
+
"dishwasher.setOption": {
|
|
64718
|
+
capName: "dishwasher",
|
|
64719
|
+
capScope: "device",
|
|
64720
|
+
addonId: null,
|
|
64721
|
+
access: "create"
|
|
64722
|
+
},
|
|
64723
|
+
"dishwasher.setPower": {
|
|
64724
|
+
capName: "dishwasher",
|
|
64725
|
+
capScope: "device",
|
|
64726
|
+
addonId: null,
|
|
64727
|
+
access: "create"
|
|
64728
|
+
},
|
|
64729
|
+
"dishwasher.setProgram": {
|
|
64730
|
+
capName: "dishwasher",
|
|
64731
|
+
capScope: "device",
|
|
64732
|
+
addonId: null,
|
|
64733
|
+
access: "create"
|
|
64734
|
+
},
|
|
64735
|
+
"dishwasher.start": {
|
|
64736
|
+
capName: "dishwasher",
|
|
64737
|
+
capScope: "device",
|
|
64738
|
+
addonId: null,
|
|
64739
|
+
access: "create"
|
|
64740
|
+
},
|
|
64741
|
+
"dishwasher.stop": {
|
|
64742
|
+
capName: "dishwasher",
|
|
64743
|
+
capScope: "device",
|
|
64744
|
+
addonId: null,
|
|
64745
|
+
access: "create"
|
|
64746
|
+
},
|
|
64584
64747
|
"doorbell.getStatus": {
|
|
64585
64748
|
capName: "doorbell",
|
|
64586
64749
|
capScope: "device",
|
|
@@ -64791,6 +64954,12 @@ Object.freeze({
|
|
|
64791
64954
|
addonId: null,
|
|
64792
64955
|
access: "view"
|
|
64793
64956
|
},
|
|
64957
|
+
"heatingValve.getStatus": {
|
|
64958
|
+
capName: "heating-valve",
|
|
64959
|
+
capScope: "device",
|
|
64960
|
+
addonId: null,
|
|
64961
|
+
access: "view"
|
|
64962
|
+
},
|
|
64794
64963
|
"humidifier.getStatus": {
|
|
64795
64964
|
capName: "humidifier",
|
|
64796
64965
|
capScope: "device",
|
|
@@ -70378,7 +70547,7 @@ Object.freeze({
|
|
|
70378
70547
|
access: "create"
|
|
70379
70548
|
}
|
|
70380
70549
|
});
|
|
70381
|
-
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder;
|
|
70550
|
+
DeviceType.Camera, DeviceType.Hub, DeviceType.Light, DeviceType.Siren, DeviceType.Switch, DeviceType.Sensor, DeviceType.Thermostat, DeviceType.Climate, DeviceType.Button, DeviceType.EventEmitter, DeviceType.Update, DeviceType.Generic, DeviceType.Notifier, DeviceType.Script, DeviceType.Automation, DeviceType.Lock, DeviceType.Cover, DeviceType.Valve, DeviceType.Humidifier, DeviceType.WaterHeater, DeviceType.Fan, DeviceType.MediaPlayer, DeviceType.AlarmPanel, DeviceType.Control, DeviceType.Presence, DeviceType.Weather, DeviceType.Vacuum, DeviceType.LawnMower, DeviceType.Container, DeviceType.Image, DeviceType.PetFeeder, DeviceType.Dishwasher;
|
|
70382
70551
|
DeviceFeature.BatteryOperated;
|
|
70383
70552
|
Object.freeze({
|
|
70384
70553
|
"accessories.getStatus": [{
|
|
@@ -71202,6 +71371,51 @@ Object.freeze({
|
|
|
71202
71371
|
form: "single",
|
|
71203
71372
|
optional: false
|
|
71204
71373
|
}],
|
|
71374
|
+
"dishwasher.getStatus": [{
|
|
71375
|
+
name: "deviceId",
|
|
71376
|
+
form: "single",
|
|
71377
|
+
optional: false
|
|
71378
|
+
}],
|
|
71379
|
+
"dishwasher.pause": [{
|
|
71380
|
+
name: "deviceId",
|
|
71381
|
+
form: "single",
|
|
71382
|
+
optional: false
|
|
71383
|
+
}],
|
|
71384
|
+
"dishwasher.setHalfLoad": [{
|
|
71385
|
+
name: "deviceId",
|
|
71386
|
+
form: "single",
|
|
71387
|
+
optional: false
|
|
71388
|
+
}],
|
|
71389
|
+
"dishwasher.setHygienePlus": [{
|
|
71390
|
+
name: "deviceId",
|
|
71391
|
+
form: "single",
|
|
71392
|
+
optional: false
|
|
71393
|
+
}],
|
|
71394
|
+
"dishwasher.setOption": [{
|
|
71395
|
+
name: "deviceId",
|
|
71396
|
+
form: "single",
|
|
71397
|
+
optional: false
|
|
71398
|
+
}],
|
|
71399
|
+
"dishwasher.setPower": [{
|
|
71400
|
+
name: "deviceId",
|
|
71401
|
+
form: "single",
|
|
71402
|
+
optional: false
|
|
71403
|
+
}],
|
|
71404
|
+
"dishwasher.setProgram": [{
|
|
71405
|
+
name: "deviceId",
|
|
71406
|
+
form: "single",
|
|
71407
|
+
optional: false
|
|
71408
|
+
}],
|
|
71409
|
+
"dishwasher.start": [{
|
|
71410
|
+
name: "deviceId",
|
|
71411
|
+
form: "single",
|
|
71412
|
+
optional: false
|
|
71413
|
+
}],
|
|
71414
|
+
"dishwasher.stop": [{
|
|
71415
|
+
name: "deviceId",
|
|
71416
|
+
form: "single",
|
|
71417
|
+
optional: false
|
|
71418
|
+
}],
|
|
71205
71419
|
"doorbell.getStatus": [{
|
|
71206
71420
|
name: "deviceId",
|
|
71207
71421
|
form: "single",
|
|
@@ -71271,6 +71485,11 @@ Object.freeze({
|
|
|
71271
71485
|
form: "single",
|
|
71272
71486
|
optional: false
|
|
71273
71487
|
}],
|
|
71488
|
+
"heatingValve.getStatus": [{
|
|
71489
|
+
name: "deviceId",
|
|
71490
|
+
form: "single",
|
|
71491
|
+
optional: false
|
|
71492
|
+
}],
|
|
71274
71493
|
"humidifier.getStatus": [{
|
|
71275
71494
|
name: "deviceId",
|
|
71276
71495
|
form: "single",
|
|
@@ -74966,6 +75185,40 @@ function createGmailSmtpProvider(deps) {
|
|
|
74966
75185
|
};
|
|
74967
75186
|
}
|
|
74968
75187
|
//#endregion
|
|
75188
|
+
//#region src/google-broker-reconnect-alert.ts
|
|
75189
|
+
function googleBrokerReconnectAlertId(brokerId) {
|
|
75190
|
+
return `google-broker:${brokerId}`;
|
|
75191
|
+
}
|
|
75192
|
+
function isInvalidGrantRefreshError(err) {
|
|
75193
|
+
return (err instanceof Error ? err.message : String(err)).includes("invalid_grant");
|
|
75194
|
+
}
|
|
75195
|
+
function buildGoogleBrokerReconnectAlert(brokerId, brokerName) {
|
|
75196
|
+
const pushLine = `${brokerName}: Google session expired — sign in again`;
|
|
75197
|
+
return {
|
|
75198
|
+
id: googleBrokerReconnectAlertId(brokerId),
|
|
75199
|
+
category: "google.broker-reconnect",
|
|
75200
|
+
severity: "critical",
|
|
75201
|
+
title: "Google needs a new sign-in",
|
|
75202
|
+
message: `${brokerName} needs you to sign in to Google again.`,
|
|
75203
|
+
action: {
|
|
75204
|
+
label: "Sign in again",
|
|
75205
|
+
href: `/addon/google-services/oauth/start?brokerId=${encodeURIComponent(brokerId)}`
|
|
75206
|
+
},
|
|
75207
|
+
status: "active",
|
|
75208
|
+
read: false,
|
|
75209
|
+
createdAt: Date.now(),
|
|
75210
|
+
updatedAt: Date.now(),
|
|
75211
|
+
source: {
|
|
75212
|
+
type: "google-broker",
|
|
75213
|
+
id: brokerId
|
|
75214
|
+
},
|
|
75215
|
+
metadata: {
|
|
75216
|
+
episodeKey: "reconnect",
|
|
75217
|
+
pushLine
|
|
75218
|
+
}
|
|
75219
|
+
};
|
|
75220
|
+
}
|
|
75221
|
+
//#endregion
|
|
74969
75222
|
//#region src/google-oauth.ts
|
|
74970
75223
|
/**
|
|
74971
75224
|
* Google OAuth2 authorization-code + refresh for Calendar API.
|
|
@@ -75581,6 +75834,7 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
75581
75834
|
};
|
|
75582
75835
|
this.registry.setOauth(next);
|
|
75583
75836
|
await this.persistOauthAccounts();
|
|
75837
|
+
if (next.refreshToken.length > 0) this.resolveGoogleBrokerReconnectAlert(brokerId);
|
|
75584
75838
|
if (next.accountEmail && (entry.name === "Google account" || entry.name.startsWith("google_"))) {
|
|
75585
75839
|
const renamed = {
|
|
75586
75840
|
...entry,
|
|
@@ -75713,6 +75967,39 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
75713
75967
|
}
|
|
75714
75968
|
return out.toSorted((a, b) => a.label.localeCompare(b.label));
|
|
75715
75969
|
}
|
|
75970
|
+
async emitGoogleBrokerReconnectAlert(brokerId, brokerName) {
|
|
75971
|
+
const emit = this.ctx.api.alerts?.emit;
|
|
75972
|
+
if (emit === void 0) {
|
|
75973
|
+
this.ctx.logger.warn("google broker reconnect alert skipped — alerts capability missing", { meta: { brokerId } });
|
|
75974
|
+
return;
|
|
75975
|
+
}
|
|
75976
|
+
try {
|
|
75977
|
+
await emit.mutate(buildGoogleBrokerReconnectAlert(brokerId, brokerName));
|
|
75978
|
+
} catch (err) {
|
|
75979
|
+
this.ctx.logger.warn("google broker reconnect alert emit failed", { meta: {
|
|
75980
|
+
brokerId,
|
|
75981
|
+
error: err instanceof Error ? err.message : String(err)
|
|
75982
|
+
} });
|
|
75983
|
+
}
|
|
75984
|
+
}
|
|
75985
|
+
async resolveGoogleBrokerReconnectAlert(brokerId) {
|
|
75986
|
+
const update = this.ctx.api.alerts?.update;
|
|
75987
|
+
if (update === void 0) return;
|
|
75988
|
+
try {
|
|
75989
|
+
await update.mutate({
|
|
75990
|
+
alertId: googleBrokerReconnectAlertId(brokerId),
|
|
75991
|
+
patch: {
|
|
75992
|
+
status: "completed",
|
|
75993
|
+
read: true
|
|
75994
|
+
}
|
|
75995
|
+
});
|
|
75996
|
+
} catch (err) {
|
|
75997
|
+
this.ctx.logger.warn("google broker reconnect alert resolve failed", { meta: {
|
|
75998
|
+
brokerId,
|
|
75999
|
+
error: err instanceof Error ? err.message : String(err)
|
|
76000
|
+
} });
|
|
76001
|
+
}
|
|
76002
|
+
}
|
|
75716
76003
|
async ensureAccessToken(brokerId, opts = {}) {
|
|
75717
76004
|
const entry = this.registry.getEntry(brokerId);
|
|
75718
76005
|
const oauth = this.registry.getOauth(brokerId);
|
|
@@ -75725,10 +76012,16 @@ var GoogleServicesAddon = class extends BaseAddon {
|
|
|
75725
76012
|
accountEmail: oauth.accountEmail
|
|
75726
76013
|
};
|
|
75727
76014
|
if (!opts.forceRefresh && !needsRefresh(state)) return state.accessToken;
|
|
75728
|
-
|
|
75729
|
-
|
|
75730
|
-
|
|
75731
|
-
|
|
76015
|
+
let tokens;
|
|
76016
|
+
try {
|
|
76017
|
+
tokens = await refreshAccessToken({
|
|
76018
|
+
clientId: entry.clientId.trim(),
|
|
76019
|
+
clientSecret: entry.clientSecret.trim()
|
|
76020
|
+
}, state.refreshToken);
|
|
76021
|
+
} catch (err) {
|
|
76022
|
+
if (isInvalidGrantRefreshError(err)) this.emitGoogleBrokerReconnectAlert(brokerId, entry.name);
|
|
76023
|
+
throw err;
|
|
76024
|
+
}
|
|
75732
76025
|
if (typeof tokens.access_token !== "string" || tokens.access_token.trim().length === 0) throw new Error("Google token refresh returned an empty access_token — Sign out and Sign in again");
|
|
75733
76026
|
const nextState = applyTokenResponse(state, tokens);
|
|
75734
76027
|
this.registry.setOauth({
|
package/package.json
CHANGED