@camstack/addon-import-alexa 0.2.156 → 0.2.158
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/CHANGELOG.md +13 -0
- package/dist/{MotionZonesSettings-Dyw_F0Ju.mjs → MotionZonesSettings-Z-NRG681.mjs} +2 -2
- package/dist/{PrivacyMaskSettings-C9KxtiCR.mjs → PrivacyMaskSettings-DiS2hPpi.mjs} +4 -4
- package/dist/{SceneMonitorEditor-DjpiE85o.mjs → SceneMonitorEditor-BYYK_XwY.mjs} +3 -3
- package/dist/_stub.js +129 -127
- package/dist/{_virtual_mf-localSharedImportMap___mfe_internal__addon_import_alexa_page-CUA1yb0b.mjs → _virtual_mf-localSharedImportMap___mfe_internal__addon_import_alexa_page-B4G6E4Vs.mjs} +3 -3
- package/dist/_virtual_mf___mfe_internal__addon_import_alexa_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-DCV5s91A.mjs +26 -0
- package/dist/addon.js +968 -154
- package/dist/addon.mjs +968 -154
- package/dist/{hostInit-CNFwYsQP.mjs → hostInit-DWBMKrvf.mjs} +2 -2
- package/dist/{player-overlays-CCqJsHN5.mjs → player-overlays-5MrLqX2i.mjs} +1 -1
- package/dist/remoteEntry.js +1 -1
- package/dist/{responsive-B5IteB4F.mjs → responsive-CsfyZVWS.mjs} +1 -1
- package/dist/{scene-monitor-copy-BerJ-ceE.mjs → scene-monitor-copy-DOuMmSwJ.mjs} +1 -1
- package/dist/{square-DSKSvnQQ.mjs → square-BGn7yRva.mjs} +1 -1
- package/dist/{trash-2-BRgPXKlX.mjs → trash-2-BiBTPv8Y.mjs} +1 -1
- package/dist/{virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_import_alexa_page__remoteEntry_js-DIl5ZN8E.mjs → virtual_mf-REMOTE_ENTRY_ID___mfe_internal__addon_import_alexa_page__remoteEntry_js-BniKFfAU.mjs} +1 -1
- package/package.json +2 -2
- package/dist/_virtual_mf___mfe_internal__addon_import_alexa_page__loadShare___mf_0_camstack_mf_1_types__loadShare__.js-AHN4fFeN.mjs +0 -26
package/dist/addon.js
CHANGED
|
@@ -34,8 +34,6 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
34
34
|
var __toCommonJS = (mod) => __hasOwnProp.call(mod, "module.exports") ? mod["module.exports"] : __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
35
35
|
//#endregion
|
|
36
36
|
let node_crypto = require("node:crypto");
|
|
37
|
-
let node_os = require("node:os");
|
|
38
|
-
node_os = __toESM(node_os, 1);
|
|
39
37
|
let node_fs = require("node:fs");
|
|
40
38
|
node_fs = __toESM(node_fs, 1);
|
|
41
39
|
let node_path = require("node:path");
|
|
@@ -43,10 +41,12 @@ let node_path$1 = __toESM(node_path, 1);
|
|
|
43
41
|
node_path = __toESM(node_path);
|
|
44
42
|
let node_fs_promises = require("node:fs/promises");
|
|
45
43
|
node_fs_promises = __toESM(node_fs_promises, 1);
|
|
44
|
+
let node_os = require("node:os");
|
|
45
|
+
node_os = __toESM(node_os, 1);
|
|
46
46
|
let node_child_process = require("node:child_process");
|
|
47
47
|
require("node:zlib");
|
|
48
48
|
let node_url = require("node:url");
|
|
49
|
-
//#region ../types/dist/event-category-
|
|
49
|
+
//#region ../types/dist/event-category-hdMR7CTW.mjs
|
|
50
50
|
var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
51
51
|
EventCategory["SystemBoot"] = "system.boot";
|
|
52
52
|
EventCategory["SystemAddonsReady"] = "system.addons-ready";
|
|
@@ -811,6 +811,11 @@ var EventCategory = /* @__PURE__ */ function(EventCategory) {
|
|
|
811
811
|
*/
|
|
812
812
|
EventCategory["AccessoriesChanged"] = "accessories.onAccessoriesChanged";
|
|
813
813
|
/**
|
|
814
|
+
* An action run started or ended. Emitted by the `actions` surface.
|
|
815
|
+
* Payload: `ActionRunChanged` (`{ actionId, runId, isRunning, outcome?, lastRunAt, lastError }`).
|
|
816
|
+
*/
|
|
817
|
+
EventCategory["ActionsRunChanged"] = "actions.onRunChanged";
|
|
818
|
+
/**
|
|
814
819
|
* Progress update from a running model conversion job.
|
|
815
820
|
* Payload: `{ kind: 'model-convert', phase, sessionId?, pct?, detail? }`.
|
|
816
821
|
* Emitted by `addon-model-studio` on the converting node.
|
|
@@ -5622,7 +5627,7 @@ var ZodIssueCode = {
|
|
|
5622
5627
|
var ZodFirstPartyTypeKind;
|
|
5623
5628
|
ZodFirstPartyTypeKind || (ZodFirstPartyTypeKind = {});
|
|
5624
5629
|
//#endregion
|
|
5625
|
-
//#region ../types/dist/sleep-
|
|
5630
|
+
//#region ../types/dist/sleep-BHjNez61.mjs
|
|
5626
5631
|
/**
|
|
5627
5632
|
* The audio chunk plane's byte format, and the ONE expansion from a coded
|
|
5628
5633
|
* window to float samples (D455).
|
|
@@ -8952,6 +8957,8 @@ Object.freeze({ "doorbell": "lastPressedAt" });
|
|
|
8952
8957
|
/** Every capability name, so addon code can check a name without the schema graph. */
|
|
8953
8958
|
var CAP_NAMES = Object.freeze([
|
|
8954
8959
|
"accessories",
|
|
8960
|
+
"action-source",
|
|
8961
|
+
"actions",
|
|
8955
8962
|
"addon-pages",
|
|
8956
8963
|
"addon-pages-source",
|
|
8957
8964
|
"addon-routes",
|
|
@@ -15939,7 +15946,23 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
|
|
|
15939
15946
|
kind: literal("schedule"),
|
|
15940
15947
|
cron: string().min(1).max(120)
|
|
15941
15948
|
}),
|
|
15942
|
-
object({ kind: literal("manual") })
|
|
15949
|
+
object({ kind: literal("manual") }),
|
|
15950
|
+
object({
|
|
15951
|
+
kind: literal("detection"),
|
|
15952
|
+
/** Class names. A macro class (`animal`, `vehicle`, `person`, `package`)
|
|
15953
|
+
* matches every raw class that maps to it; any other name matches
|
|
15954
|
+
* exactly. */
|
|
15955
|
+
classes: array(string().min(1)).min(1),
|
|
15956
|
+
deviceIds: array(number().int().nonnegative()).min(1),
|
|
15957
|
+
/** The track must have visited at least one of these zones. */
|
|
15958
|
+
zones: array(string().min(1)).min(1).optional(),
|
|
15959
|
+
/** Best-so-far confidence the track must reach. */
|
|
15960
|
+
minScore: number().min(0).max(1).optional()
|
|
15961
|
+
}),
|
|
15962
|
+
object({
|
|
15963
|
+
kind: literal("interval"),
|
|
15964
|
+
minutes: number().int().min(1).max(1440)
|
|
15965
|
+
})
|
|
15943
15966
|
]);
|
|
15944
15967
|
/**
|
|
15945
15968
|
* One action step.
|
|
@@ -15959,28 +15982,47 @@ var AutomationTriggerSchema = discriminatedUnion("kind", [
|
|
|
15959
15982
|
* is called. The runner still receives a number and is untouched; the
|
|
15960
15983
|
* resolution is the recipe's job, not the runner's.
|
|
15961
15984
|
*/
|
|
15985
|
+
var AutomationWaitStepSchema = object({
|
|
15986
|
+
kind: literal("wait"),
|
|
15987
|
+
seconds: number().min(0).max(300)
|
|
15988
|
+
});
|
|
15989
|
+
var AutomationCapStepSchema = object({
|
|
15990
|
+
kind: literal("cap"),
|
|
15991
|
+
/**
|
|
15992
|
+
* One device, several same-family devices (locks / climate family / …),
|
|
15993
|
+
* or `{ $var }` for the device that triggered the run. An array is
|
|
15994
|
+
* fan-out at codegen — each id gets the same cap.method call.
|
|
15995
|
+
*/
|
|
15996
|
+
deviceId: union([
|
|
15997
|
+
number().int(),
|
|
15998
|
+
array(number().int()).min(1),
|
|
15999
|
+
object({ $var: string().min(1) })
|
|
16000
|
+
]),
|
|
16001
|
+
cap: string().min(1),
|
|
16002
|
+
method: string().min(1),
|
|
16003
|
+
/** Values may carry `{{vars.x}}` slots, or be exactly `{ $var: 'name' }`, which
|
|
16004
|
+
* SUBSTITUTE and do not evaluate (§3.2.3). Anything beyond substitution is
|
|
16005
|
+
* the expression leaf. */
|
|
16006
|
+
args: record(string(), unknown()).optional()
|
|
16007
|
+
});
|
|
16008
|
+
/**
|
|
16009
|
+
* The steps an internal Action may contain: cap and wait, and nothing that can
|
|
16010
|
+
* call back into an Action — so an Action can never reach itself (no cycles).
|
|
16011
|
+
*/
|
|
16012
|
+
var ActionStepSchema = discriminatedUnion("kind", [AutomationWaitStepSchema, AutomationCapStepSchema]);
|
|
15962
16013
|
var AutomationActionSchema = discriminatedUnion("kind", [
|
|
16014
|
+
AutomationWaitStepSchema,
|
|
16015
|
+
AutomationCapStepSchema,
|
|
15963
16016
|
object({
|
|
15964
|
-
kind: literal("
|
|
15965
|
-
|
|
15966
|
-
|
|
15967
|
-
|
|
15968
|
-
|
|
15969
|
-
|
|
15970
|
-
|
|
15971
|
-
|
|
15972
|
-
|
|
15973
|
-
*/
|
|
15974
|
-
deviceId: union([
|
|
15975
|
-
number().int(),
|
|
15976
|
-
array(number().int()).min(1),
|
|
15977
|
-
object({ $var: string().min(1) })
|
|
15978
|
-
]),
|
|
15979
|
-
cap: string().min(1),
|
|
15980
|
-
method: string().min(1),
|
|
15981
|
-
/** Values may carry `{{vars.x}}` slots, which SUBSTITUTE and do not
|
|
15982
|
-
* evaluate (§3.2.3). Anything beyond substitution is the expression leaf. */
|
|
15983
|
-
args: record(string(), unknown()).optional()
|
|
16017
|
+
kind: literal("action"),
|
|
16018
|
+
/** An entry of the `actions` surface (`internal:<uuid>` or `<addonId>:<localId>`). */
|
|
16019
|
+
actionId: string().min(1),
|
|
16020
|
+
/** Values for the action's declared variables; the others take their default. */
|
|
16021
|
+
variables: record(string(), union([
|
|
16022
|
+
string(),
|
|
16023
|
+
number(),
|
|
16024
|
+
boolean()
|
|
16025
|
+
])).optional()
|
|
15984
16026
|
}),
|
|
15985
16027
|
object({
|
|
15986
16028
|
kind: literal("code"),
|
|
@@ -15989,10 +16031,356 @@ var AutomationActionSchema = discriminatedUnion("kind", [
|
|
|
15989
16031
|
code: string().min(1).max(2e4)
|
|
15990
16032
|
})
|
|
15991
16033
|
]);
|
|
16034
|
+
/**
|
|
16035
|
+
* How a trigger that arrives while the automation is busy (or cooling down) is
|
|
16036
|
+
* handled. One of the automation's execution modes, never a property of its
|
|
16037
|
+
* actions. Absent means `single`.
|
|
16038
|
+
*
|
|
16039
|
+
* - `single` — drop the trigger while a run is in progress (traced + logged).
|
|
16040
|
+
* - `restart` — abort the run in progress (at its next step boundary), start fresh.
|
|
16041
|
+
* - `queued` — queue up to `max` triggers, drop the rest (traced).
|
|
16042
|
+
* - `parallel` — up to `max` runs at once, drop the rest (traced).
|
|
16043
|
+
* - `cooldown` — `single`, and no new run until `minutes` after the last run
|
|
16044
|
+
* STARTED; persisted across a restart. A manual trigger bypasses only this
|
|
16045
|
+
* wait, never the single/queued limits.
|
|
16046
|
+
*/
|
|
16047
|
+
var AutomationRunModeSchema = discriminatedUnion("mode", [
|
|
16048
|
+
object({ mode: literal("single") }),
|
|
16049
|
+
object({ mode: literal("restart") }),
|
|
16050
|
+
object({
|
|
16051
|
+
mode: literal("queued"),
|
|
16052
|
+
max: number().int().min(1).max(10)
|
|
16053
|
+
}),
|
|
16054
|
+
object({
|
|
16055
|
+
mode: literal("parallel"),
|
|
16056
|
+
max: number().int().min(1).max(10)
|
|
16057
|
+
}),
|
|
16058
|
+
object({
|
|
16059
|
+
mode: literal("cooldown"),
|
|
16060
|
+
minutes: number().int().min(1).max(1440)
|
|
16061
|
+
})
|
|
16062
|
+
]);
|
|
15992
16063
|
var AutomationRecipeSchema = object({
|
|
15993
16064
|
triggers: array(AutomationTriggerSchema),
|
|
15994
16065
|
conditions: AutomationConditionSchema.optional(),
|
|
15995
|
-
actions: array(AutomationActionSchema)
|
|
16066
|
+
actions: array(AutomationActionSchema),
|
|
16067
|
+
runMode: AutomationRunModeSchema.optional(),
|
|
16068
|
+
/** How many run traces the automation keeps (default {@link DEFAULT_TRACE_KEEP}). */
|
|
16069
|
+
keepTraces: number().int().min(1).max(100).optional()
|
|
16070
|
+
});
|
|
16071
|
+
new Set([
|
|
16072
|
+
{
|
|
16073
|
+
id: "person",
|
|
16074
|
+
name: "Person"
|
|
16075
|
+
},
|
|
16076
|
+
{
|
|
16077
|
+
id: "vehicle",
|
|
16078
|
+
name: "Vehicle"
|
|
16079
|
+
},
|
|
16080
|
+
{
|
|
16081
|
+
id: "animal",
|
|
16082
|
+
name: "Animal"
|
|
16083
|
+
},
|
|
16084
|
+
{
|
|
16085
|
+
id: "package",
|
|
16086
|
+
name: "Package"
|
|
16087
|
+
}
|
|
16088
|
+
].map((l) => l.id));
|
|
16089
|
+
var COCO_TO_MACRO = {
|
|
16090
|
+
mapping: {
|
|
16091
|
+
person: "person",
|
|
16092
|
+
bicycle: "vehicle",
|
|
16093
|
+
car: "vehicle",
|
|
16094
|
+
motorcycle: "vehicle",
|
|
16095
|
+
airplane: "vehicle",
|
|
16096
|
+
bus: "vehicle",
|
|
16097
|
+
train: "vehicle",
|
|
16098
|
+
truck: "vehicle",
|
|
16099
|
+
boat: "vehicle",
|
|
16100
|
+
bird: "animal",
|
|
16101
|
+
cat: "animal",
|
|
16102
|
+
dog: "animal",
|
|
16103
|
+
horse: "animal",
|
|
16104
|
+
sheep: "animal",
|
|
16105
|
+
cow: "animal",
|
|
16106
|
+
elephant: "animal",
|
|
16107
|
+
bear: "animal",
|
|
16108
|
+
zebra: "animal",
|
|
16109
|
+
giraffe: "animal",
|
|
16110
|
+
suitcase: "package",
|
|
16111
|
+
backpack: "package",
|
|
16112
|
+
handbag: "package"
|
|
16113
|
+
},
|
|
16114
|
+
preserveOriginal: false
|
|
16115
|
+
};
|
|
16116
|
+
new Set(Object.values(COCO_TO_MACRO.mapping));
|
|
16117
|
+
/**
|
|
16118
|
+
* Run traces — what an automation (or, later, an Action run) DID, node by node,
|
|
16119
|
+
* so the editor can paint every block green or red with its reason.
|
|
16120
|
+
*
|
|
16121
|
+
* A trace is data, not a log: it covers the WHOLE tree — the trigger stage,
|
|
16122
|
+
* every condition node (containers and leaves, including the ones a
|
|
16123
|
+
* short-circuit never reached), the run-mode verdict and every action step —
|
|
16124
|
+
* each addressed by a stable path (`conditions.0.1`, `actions.2`, or `steps.N`
|
|
16125
|
+
* for an Action run). Skipped
|
|
16126
|
+
* evaluations are traced too, and identical consecutive skips collapse into a
|
|
16127
|
+
* repeat count so a trigger that fails every 5 minutes cannot flush real runs.
|
|
16128
|
+
*
|
|
16129
|
+
* {@link AutomationStepTraceSchema} is deliberately free of automation
|
|
16130
|
+
* vocabulary so an Action run records the same step shape.
|
|
16131
|
+
*/
|
|
16132
|
+
/** A value a trace may show: JSON primitives and short lists, nothing deeper. */
|
|
16133
|
+
var TraceValueSchema = union([
|
|
16134
|
+
string(),
|
|
16135
|
+
number(),
|
|
16136
|
+
boolean(),
|
|
16137
|
+
_null(),
|
|
16138
|
+
array(union([string(), number()]))
|
|
16139
|
+
]);
|
|
16140
|
+
var AutomationRunOutcomeSchema = _enum([
|
|
16141
|
+
"ran",
|
|
16142
|
+
"skipped-trigger",
|
|
16143
|
+
"skipped-conditions",
|
|
16144
|
+
"skipped-cooldown",
|
|
16145
|
+
"skipped-overlap",
|
|
16146
|
+
"failed",
|
|
16147
|
+
"aborted"
|
|
16148
|
+
]);
|
|
16149
|
+
/** `not-evaluated` = a short-circuit never reached the node. */
|
|
16150
|
+
var TraceNodeOutcomeSchema = _enum([
|
|
16151
|
+
"pass",
|
|
16152
|
+
"fail",
|
|
16153
|
+
"not-evaluated"
|
|
16154
|
+
]);
|
|
16155
|
+
var AutomationTriggerTraceSchema = object({
|
|
16156
|
+
kind: string().min(1),
|
|
16157
|
+
outcome: _enum(["pass", "fail"]),
|
|
16158
|
+
/** Why an event was rejected ("class person not in [dog]") or what fired. */
|
|
16159
|
+
reason: string(),
|
|
16160
|
+
/** deviceId, className, trackId, score … — only what the trigger exposes. */
|
|
16161
|
+
vars: record(string(), TraceValueSchema)
|
|
16162
|
+
});
|
|
16163
|
+
var AutomationConditionTraceNodeSchema = object({
|
|
16164
|
+
/** `conditions` for the root, `conditions.<i>` for its i-th child, … */
|
|
16165
|
+
path: string().min(1),
|
|
16166
|
+
kind: _enum([
|
|
16167
|
+
"all",
|
|
16168
|
+
"any",
|
|
16169
|
+
"not",
|
|
16170
|
+
"condition",
|
|
16171
|
+
"expression"
|
|
16172
|
+
]),
|
|
16173
|
+
outcome: TraceNodeOutcomeSchema,
|
|
16174
|
+
reason: string(),
|
|
16175
|
+
deviceId: number().int().optional(),
|
|
16176
|
+
cap: string().optional(),
|
|
16177
|
+
fieldPath: string().optional(),
|
|
16178
|
+
operator: string().optional(),
|
|
16179
|
+
expected: TraceValueSchema.optional(),
|
|
16180
|
+
/** What the mirror held; `null` when it held nothing (unknown). */
|
|
16181
|
+
observed: TraceValueSchema.optional()
|
|
16182
|
+
});
|
|
16183
|
+
var AutomationRunVerdictSchema = object({
|
|
16184
|
+
mode: AutomationRunModeSchema,
|
|
16185
|
+
decision: _enum([
|
|
16186
|
+
"run",
|
|
16187
|
+
"queued",
|
|
16188
|
+
"restart",
|
|
16189
|
+
"drop",
|
|
16190
|
+
"cooldown",
|
|
16191
|
+
"bypass"
|
|
16192
|
+
]),
|
|
16193
|
+
reason: string()
|
|
16194
|
+
});
|
|
16195
|
+
/** One executed (or not-run) step — shared by automations and Action runs. */
|
|
16196
|
+
var AutomationStepTraceSchema = object({
|
|
16197
|
+
/** `actions.<i>` */
|
|
16198
|
+
path: string().min(1),
|
|
16199
|
+
kind: string().min(1),
|
|
16200
|
+
cap: string().optional(),
|
|
16201
|
+
method: string().optional(),
|
|
16202
|
+
deviceId: number().int().optional(),
|
|
16203
|
+
startedAt: number().optional(),
|
|
16204
|
+
endedAt: number().optional(),
|
|
16205
|
+
outcome: _enum([
|
|
16206
|
+
"ok",
|
|
16207
|
+
"error",
|
|
16208
|
+
"not-run"
|
|
16209
|
+
]),
|
|
16210
|
+
message: string().optional()
|
|
16211
|
+
});
|
|
16212
|
+
var AutomationRunTraceSchema = object({
|
|
16213
|
+
runId: string().min(1),
|
|
16214
|
+
startedAt: number(),
|
|
16215
|
+
endedAt: number(),
|
|
16216
|
+
trigger: AutomationTriggerTraceSchema,
|
|
16217
|
+
conditions: array(AutomationConditionTraceNodeSchema),
|
|
16218
|
+
verdict: AutomationRunVerdictSchema.optional(),
|
|
16219
|
+
steps: array(AutomationStepTraceSchema),
|
|
16220
|
+
outcome: AutomationRunOutcomeSchema,
|
|
16221
|
+
/** How many identical consecutive skips this trace stands for (>= 1). */
|
|
16222
|
+
repeat: number().int().min(1),
|
|
16223
|
+
/** When the latest of those repeats happened. */
|
|
16224
|
+
lastAt: number()
|
|
16225
|
+
});
|
|
16226
|
+
/**
|
|
16227
|
+
* What the hub's `runs` ledger holds for one owner (`automation:<blockId>` or
|
|
16228
|
+
* `action:<actionId>`): the cooldown stamp and the trace ring.
|
|
16229
|
+
*/
|
|
16230
|
+
var AutomationStateDocSchema = object({
|
|
16231
|
+
version: literal(1),
|
|
16232
|
+
lastRunStartedAt: number().nullable(),
|
|
16233
|
+
traces: array(AutomationRunTraceSchema)
|
|
16234
|
+
});
|
|
16235
|
+
/**
|
|
16236
|
+
* Actions — named, runnable things an operator (or an automation) can start,
|
|
16237
|
+
* declared as LIST ENTRIES, never as devices.
|
|
16238
|
+
*
|
|
16239
|
+
* An entry is either **internal** (a short list of cap/wait steps kept in the
|
|
16240
|
+
* hub's `actions` record kind) or declared by an addon through the
|
|
16241
|
+
* `action-source` collection (a Home Assistant script, a scene …). The one
|
|
16242
|
+
* surface the UI and automations talk to is the `actions` cap; it keeps no
|
|
16243
|
+
* catalog of its own (D3) — every `list` asks the providers live.
|
|
16244
|
+
*
|
|
16245
|
+
* This file is the data half: the entry schema, the variables an entry may
|
|
16246
|
+
* declare, and the pure resolution of the values a run was given. It holds no
|
|
16247
|
+
* runtime.
|
|
16248
|
+
*/
|
|
16249
|
+
/** What a variable's value is. `select` takes one of `options`. */
|
|
16250
|
+
var ActionVariableTypeSchema = _enum([
|
|
16251
|
+
"string",
|
|
16252
|
+
"number",
|
|
16253
|
+
"boolean",
|
|
16254
|
+
"select"
|
|
16255
|
+
]);
|
|
16256
|
+
var ACTION_VARIABLE_NAME_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
|
|
16257
|
+
var ActionVariableValueSchema = union([
|
|
16258
|
+
string(),
|
|
16259
|
+
number(),
|
|
16260
|
+
boolean()
|
|
16261
|
+
]);
|
|
16262
|
+
/**
|
|
16263
|
+
* One declared variable. Steps reference it as `{ $var: 'name' }` (the whole
|
|
16264
|
+
* value) or `{{vars.name}}` (inside a string) in their args.
|
|
16265
|
+
*/
|
|
16266
|
+
var ActionVariableSchema = object({
|
|
16267
|
+
name: string().regex(ACTION_VARIABLE_NAME_RE),
|
|
16268
|
+
label: string().min(1).max(120).optional(),
|
|
16269
|
+
type: ActionVariableTypeSchema,
|
|
16270
|
+
required: boolean().optional(),
|
|
16271
|
+
default: ActionVariableValueSchema.optional(),
|
|
16272
|
+
/** The allowed values of a `select`. */
|
|
16273
|
+
options: array(string().min(1)).min(1).optional()
|
|
16274
|
+
}).superRefine((v, ctx) => {
|
|
16275
|
+
if (v.type === "select" && v.options === void 0) ctx.addIssue({
|
|
16276
|
+
code: "custom",
|
|
16277
|
+
message: "a select variable needs options",
|
|
16278
|
+
path: ["options"]
|
|
16279
|
+
});
|
|
16280
|
+
if (v.default !== void 0 && variableValueError(v, v.default) !== null) ctx.addIssue({
|
|
16281
|
+
code: "custom",
|
|
16282
|
+
message: variableValueError(v, v.default) ?? "invalid default",
|
|
16283
|
+
path: ["default"]
|
|
16284
|
+
});
|
|
16285
|
+
});
|
|
16286
|
+
/** Why `value` is not a legal value for the variable, or null when it is. */
|
|
16287
|
+
function variableValueError(variable, value) {
|
|
16288
|
+
switch (variable.type) {
|
|
16289
|
+
case "string": return typeof value === "string" ? null : `variable "${variable.name}" must be a string`;
|
|
16290
|
+
case "number": return typeof value === "number" && Number.isFinite(value) ? null : `variable "${variable.name}" must be a number`;
|
|
16291
|
+
case "boolean": return typeof value === "boolean" ? null : `variable "${variable.name}" must be true or false`;
|
|
16292
|
+
case "select": return typeof value === "string" && (variable.options ?? []).includes(value) ? null : `variable "${variable.name}" must be one of ${(variable.options ?? []).join(", ")}`;
|
|
16293
|
+
}
|
|
16294
|
+
}
|
|
16295
|
+
var ActionSourceKindSchema = _enum(["internal", "addon"]);
|
|
16296
|
+
function isInternalActionId(actionId) {
|
|
16297
|
+
return actionId.startsWith("internal:") && actionId.length > 9;
|
|
16298
|
+
}
|
|
16299
|
+
/** The addon behind a `<addonId>:<localId>` id, or null for anything else (internal included). */
|
|
16300
|
+
function addonIdOfActionId(actionId) {
|
|
16301
|
+
if (isInternalActionId(actionId)) return null;
|
|
16302
|
+
const at = actionId.indexOf(":");
|
|
16303
|
+
return at > 0 && at < actionId.length - 1 ? actionId.slice(0, at) : null;
|
|
16304
|
+
}
|
|
16305
|
+
var ActionStatusSchema = object({
|
|
16306
|
+
isRunning: boolean(),
|
|
16307
|
+
/** Ms epoch the latest run STARTED; null when it never ran. */
|
|
16308
|
+
lastRunAt: number().nullable(),
|
|
16309
|
+
/** The latest run's failure; null on success or when it never ran. */
|
|
16310
|
+
lastError: string().nullable()
|
|
16311
|
+
});
|
|
16312
|
+
var ActionEntrySchema = object({
|
|
16313
|
+
/** `internal:<uuid>` or `<addonId>:<localId>`. */
|
|
16314
|
+
id: string().min(3),
|
|
16315
|
+
name: string().min(1).max(120),
|
|
16316
|
+
/** The addon that declared it; `core-blocks` for an internal one. */
|
|
16317
|
+
addonId: string().min(1),
|
|
16318
|
+
source: ActionSourceKindSchema,
|
|
16319
|
+
/** An addon-declared entry is edited where it was declared. */
|
|
16320
|
+
readOnly: boolean(),
|
|
16321
|
+
/** Internal only: cap and wait steps. No action-in-action, so no cycles. */
|
|
16322
|
+
steps: array(ActionStepSchema).min(1).max(50).optional(),
|
|
16323
|
+
variables: array(ActionVariableSchema).max(20).optional(),
|
|
16324
|
+
status: ActionStatusSchema
|
|
16325
|
+
}).superRefine((entry, ctx) => {
|
|
16326
|
+
if (entry.source === "internal") {
|
|
16327
|
+
if (!isInternalActionId(entry.id)) ctx.addIssue({
|
|
16328
|
+
code: "custom",
|
|
16329
|
+
message: "an internal action id is internal:<uuid>",
|
|
16330
|
+
path: ["id"]
|
|
16331
|
+
});
|
|
16332
|
+
return;
|
|
16333
|
+
}
|
|
16334
|
+
if (entry.steps !== void 0) ctx.addIssue({
|
|
16335
|
+
code: "custom",
|
|
16336
|
+
message: "only an internal action carries steps",
|
|
16337
|
+
path: ["steps"]
|
|
16338
|
+
});
|
|
16339
|
+
if (!entry.readOnly) ctx.addIssue({
|
|
16340
|
+
code: "custom",
|
|
16341
|
+
message: "an addon action is read-only here",
|
|
16342
|
+
path: ["readOnly"]
|
|
16343
|
+
});
|
|
16344
|
+
if (addonIdOfActionId(entry.id) === null) ctx.addIssue({
|
|
16345
|
+
code: "custom",
|
|
16346
|
+
message: "an addon action id is <addonId>:<localId>",
|
|
16347
|
+
path: ["id"]
|
|
16348
|
+
});
|
|
16349
|
+
});
|
|
16350
|
+
/** What an operator writes for an internal action. */
|
|
16351
|
+
var ActionInputSchema = object({
|
|
16352
|
+
name: string().min(1).max(120),
|
|
16353
|
+
steps: array(ActionStepSchema).min(1).max(50),
|
|
16354
|
+
variables: array(ActionVariableSchema).max(20).optional()
|
|
16355
|
+
});
|
|
16356
|
+
/** Who started a run. Absent = the operator pressed it. */
|
|
16357
|
+
var ActionRunOriginSchema = object({
|
|
16358
|
+
/** The automation block whose step started it. */
|
|
16359
|
+
blockId: string().min(1).optional() });
|
|
16360
|
+
/** `started` = the caller did not ask to wait. */
|
|
16361
|
+
var ActionRunOutcomeSchema = union([AutomationRunOutcomeSchema, literal("started")]);
|
|
16362
|
+
var ActionRunResultSchema = object({
|
|
16363
|
+
runId: string().min(1),
|
|
16364
|
+
outcome: ActionRunOutcomeSchema,
|
|
16365
|
+
/** Why it did not run, or what failed. */
|
|
16366
|
+
message: string().optional()
|
|
16367
|
+
});
|
|
16368
|
+
_enum([
|
|
16369
|
+
"not-found",
|
|
16370
|
+
"read-only",
|
|
16371
|
+
"invalid-variables",
|
|
16372
|
+
"invalid-steps",
|
|
16373
|
+
"not-linked",
|
|
16374
|
+
"busy"
|
|
16375
|
+
]);
|
|
16376
|
+
object({
|
|
16377
|
+
actionId: string(),
|
|
16378
|
+
runId: string(),
|
|
16379
|
+
isRunning: boolean(),
|
|
16380
|
+
/** Set when the run ended. */
|
|
16381
|
+
outcome: AutomationRunOutcomeSchema.optional(),
|
|
16382
|
+
lastRunAt: number().nullable(),
|
|
16383
|
+
lastError: string().nullable()
|
|
15996
16384
|
});
|
|
15997
16385
|
/**
|
|
15998
16386
|
* `addon-pages` — system-scoped singleton aggregator cap. Public-facing
|
|
@@ -19727,7 +20115,18 @@ method(object({}), object({ blocks: array(CoreBlockSchema) }), { auth: "admin" }
|
|
|
19727
20115
|
kind: "mutation",
|
|
19728
20116
|
auth: "admin",
|
|
19729
20117
|
access: "view"
|
|
19730
|
-
})
|
|
20118
|
+
}), method(object({
|
|
20119
|
+
blockId: string().min(1),
|
|
20120
|
+
trace: AutomationRunTraceSchema.optional(),
|
|
20121
|
+
runStartedAt: number().optional(),
|
|
20122
|
+
keepTraces: number().int().min(1).max(100).optional()
|
|
20123
|
+
}), _void(), {
|
|
20124
|
+
kind: "mutation",
|
|
20125
|
+
auth: "admin"
|
|
20126
|
+
}), method(object({ blockId: string().min(1) }), AutomationStateDocSchema, { auth: "admin" }), method(object({ blockId: string().min(1) }), object({
|
|
20127
|
+
traces: array(AutomationRunTraceSchema),
|
|
20128
|
+
lastError: string().nullable()
|
|
20129
|
+
}), { auth: "admin" });
|
|
19731
20130
|
/**
|
|
19732
20131
|
* `custom-model-registry` — collection cap exposing operator-registered
|
|
19733
20132
|
* custom detection models. Each provider (today: `addon-model-studio`)
|
|
@@ -45051,51 +45450,6 @@ var notificationOutputCapability = {
|
|
|
45051
45450
|
})
|
|
45052
45451
|
}
|
|
45053
45452
|
};
|
|
45054
|
-
new Set([
|
|
45055
|
-
{
|
|
45056
|
-
id: "person",
|
|
45057
|
-
name: "Person"
|
|
45058
|
-
},
|
|
45059
|
-
{
|
|
45060
|
-
id: "vehicle",
|
|
45061
|
-
name: "Vehicle"
|
|
45062
|
-
},
|
|
45063
|
-
{
|
|
45064
|
-
id: "animal",
|
|
45065
|
-
name: "Animal"
|
|
45066
|
-
},
|
|
45067
|
-
{
|
|
45068
|
-
id: "package",
|
|
45069
|
-
name: "Package"
|
|
45070
|
-
}
|
|
45071
|
-
].map((l) => l.id));
|
|
45072
|
-
var COCO_TO_MACRO = {
|
|
45073
|
-
mapping: {
|
|
45074
|
-
person: "person",
|
|
45075
|
-
bicycle: "vehicle",
|
|
45076
|
-
car: "vehicle",
|
|
45077
|
-
motorcycle: "vehicle",
|
|
45078
|
-
airplane: "vehicle",
|
|
45079
|
-
bus: "vehicle",
|
|
45080
|
-
train: "vehicle",
|
|
45081
|
-
truck: "vehicle",
|
|
45082
|
-
boat: "vehicle",
|
|
45083
|
-
bird: "animal",
|
|
45084
|
-
cat: "animal",
|
|
45085
|
-
dog: "animal",
|
|
45086
|
-
horse: "animal",
|
|
45087
|
-
sheep: "animal",
|
|
45088
|
-
cow: "animal",
|
|
45089
|
-
elephant: "animal",
|
|
45090
|
-
bear: "animal",
|
|
45091
|
-
zebra: "animal",
|
|
45092
|
-
giraffe: "animal",
|
|
45093
|
-
suitcase: "package",
|
|
45094
|
-
backpack: "package",
|
|
45095
|
-
handbag: "package"
|
|
45096
|
-
},
|
|
45097
|
-
preserveOriginal: false
|
|
45098
|
-
};
|
|
45099
45453
|
var AUDIO_MACRO_LABELS = [
|
|
45100
45454
|
{
|
|
45101
45455
|
id: "speech",
|
|
@@ -57901,6 +58255,84 @@ var audioMetricsCapability = {
|
|
|
57901
58255
|
*/
|
|
57902
58256
|
history: "none"
|
|
57903
58257
|
};
|
|
58258
|
+
method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
|
|
58259
|
+
actionId: string().min(1),
|
|
58260
|
+
variables: record(string(), ActionVariableValueSchema).optional()
|
|
58261
|
+
}), _void(), {
|
|
58262
|
+
kind: "mutation",
|
|
58263
|
+
auth: "admin"
|
|
58264
|
+
}), method(object({ actionId: string().min(1) }), _void(), {
|
|
58265
|
+
kind: "mutation",
|
|
58266
|
+
auth: "admin"
|
|
58267
|
+
});
|
|
58268
|
+
/**
|
|
58269
|
+
* actions — the ONE surface for runnable actions, for the UI and for
|
|
58270
|
+
* automations. Provided by the core-blocks builtin on the hub.
|
|
58271
|
+
*
|
|
58272
|
+
* An action is a LIST ENTRY, not a device (D883): either internal (cap and wait
|
|
58273
|
+
* steps, kept in the hub's `actions` record kind) or declared by an addon over
|
|
58274
|
+
* `action-source`. `list` asks every `action-source` provider LIVE and overlays
|
|
58275
|
+
* the run status from the hub's `runs` ledger; there is no catalog here to
|
|
58276
|
+
* drift (D3).
|
|
58277
|
+
*
|
|
58278
|
+
* **Permissions follow the camera, as linked devices do.** An action is linked
|
|
58279
|
+
* to cameras by the operator (`setLinks`, D356: nothing links itself). A
|
|
58280
|
+
* non-admin may `get` / `run` an action only through a camera they may see that
|
|
58281
|
+
* links it: they name the camera (`deviceId`, a top-level field so the scope
|
|
58282
|
+
* gate sees it) and the provider refuses an action that camera does not link.
|
|
58283
|
+
* An admin, and an in-process caller (an automation block), may run any action.
|
|
58284
|
+
* Every refusal is typed (`[not-linked] …`) and logged.
|
|
58285
|
+
*
|
|
58286
|
+
* A second `run` of an action that is already running is REFUSED — traced and
|
|
58287
|
+
* logged — never queued.
|
|
58288
|
+
*/
|
|
58289
|
+
var ActionIdInput = object({ actionId: string().min(1) });
|
|
58290
|
+
var ActionLinksSchema = object({
|
|
58291
|
+
deviceId: number().int().nonnegative(),
|
|
58292
|
+
actionIds: array(string().min(1)).max(100)
|
|
58293
|
+
});
|
|
58294
|
+
method(object({}), array(ActionEntrySchema), { auth: "admin" }), method(object({
|
|
58295
|
+
actionId: string().min(1),
|
|
58296
|
+
deviceId: number().int().nonnegative().optional()
|
|
58297
|
+
}), object({ action: ActionEntrySchema.nullable() }), {
|
|
58298
|
+
role: "viewer",
|
|
58299
|
+
auth: "protected",
|
|
58300
|
+
kind: "query",
|
|
58301
|
+
caller: "required"
|
|
58302
|
+
}), method(object({
|
|
58303
|
+
actionId: string().min(1),
|
|
58304
|
+
variables: record(string(), ActionVariableValueSchema).optional(),
|
|
58305
|
+
wait: boolean().optional(),
|
|
58306
|
+
origin: ActionRunOriginSchema.optional(),
|
|
58307
|
+
deviceId: number().int().nonnegative().optional()
|
|
58308
|
+
}), ActionRunResultSchema, {
|
|
58309
|
+
role: "viewer",
|
|
58310
|
+
auth: "protected",
|
|
58311
|
+
kind: "mutation",
|
|
58312
|
+
caller: "required"
|
|
58313
|
+
}), method(ActionIdInput, _void(), {
|
|
58314
|
+
kind: "mutation",
|
|
58315
|
+
auth: "admin"
|
|
58316
|
+
}), method(ActionIdInput, object({ traces: array(AutomationRunTraceSchema) }), { auth: "admin" }), method(object({ action: ActionInputSchema }), object({ action: ActionEntrySchema }), {
|
|
58317
|
+
kind: "mutation",
|
|
58318
|
+
auth: "admin"
|
|
58319
|
+
}), method(object({
|
|
58320
|
+
actionId: string().min(1),
|
|
58321
|
+
action: ActionInputSchema.partial()
|
|
58322
|
+
}), object({ action: ActionEntrySchema }), {
|
|
58323
|
+
kind: "mutation",
|
|
58324
|
+
auth: "admin"
|
|
58325
|
+
}), method(ActionIdInput, _void(), {
|
|
58326
|
+
kind: "mutation",
|
|
58327
|
+
auth: "admin"
|
|
58328
|
+
}), method(object({ deviceId: number().int().nonnegative() }), array(ActionEntrySchema), {
|
|
58329
|
+
role: "viewer",
|
|
58330
|
+
auth: "protected",
|
|
58331
|
+
kind: "query"
|
|
58332
|
+
}), method(object({ deviceId: number().int().nonnegative() }), ActionLinksSchema, { auth: "admin" }), method(ActionLinksSchema, ActionLinksSchema, {
|
|
58333
|
+
kind: "mutation",
|
|
58334
|
+
auth: "admin"
|
|
58335
|
+
});
|
|
57904
58336
|
/**
|
|
57905
58337
|
* Automation-control cap. Models HA `automation.*` entities on
|
|
57906
58338
|
* `DeviceType.Automation`. An automation is a trigger+condition+
|
|
@@ -72084,6 +72516,104 @@ Object.freeze({
|
|
|
72084
72516
|
access: "create",
|
|
72085
72517
|
role: "admin"
|
|
72086
72518
|
},
|
|
72519
|
+
"actions.create": {
|
|
72520
|
+
capName: "actions",
|
|
72521
|
+
capScope: "system",
|
|
72522
|
+
addonId: null,
|
|
72523
|
+
access: "create",
|
|
72524
|
+
role: "admin"
|
|
72525
|
+
},
|
|
72526
|
+
"actions.delete": {
|
|
72527
|
+
capName: "actions",
|
|
72528
|
+
capScope: "system",
|
|
72529
|
+
addonId: null,
|
|
72530
|
+
access: "delete",
|
|
72531
|
+
role: "admin"
|
|
72532
|
+
},
|
|
72533
|
+
"actions.get": {
|
|
72534
|
+
capName: "actions",
|
|
72535
|
+
capScope: "system",
|
|
72536
|
+
addonId: null,
|
|
72537
|
+
access: "view",
|
|
72538
|
+
role: "viewer"
|
|
72539
|
+
},
|
|
72540
|
+
"actions.getLinks": {
|
|
72541
|
+
capName: "actions",
|
|
72542
|
+
capScope: "system",
|
|
72543
|
+
addonId: null,
|
|
72544
|
+
access: "view",
|
|
72545
|
+
role: "admin"
|
|
72546
|
+
},
|
|
72547
|
+
"actions.getTraces": {
|
|
72548
|
+
capName: "actions",
|
|
72549
|
+
capScope: "system",
|
|
72550
|
+
addonId: null,
|
|
72551
|
+
access: "view",
|
|
72552
|
+
role: "admin"
|
|
72553
|
+
},
|
|
72554
|
+
"actions.list": {
|
|
72555
|
+
capName: "actions",
|
|
72556
|
+
capScope: "system",
|
|
72557
|
+
addonId: null,
|
|
72558
|
+
access: "view",
|
|
72559
|
+
role: "admin"
|
|
72560
|
+
},
|
|
72561
|
+
"actions.listForCamera": {
|
|
72562
|
+
capName: "actions",
|
|
72563
|
+
capScope: "system",
|
|
72564
|
+
addonId: null,
|
|
72565
|
+
access: "view",
|
|
72566
|
+
role: "viewer"
|
|
72567
|
+
},
|
|
72568
|
+
"actions.run": {
|
|
72569
|
+
capName: "actions",
|
|
72570
|
+
capScope: "system",
|
|
72571
|
+
addonId: null,
|
|
72572
|
+
access: "create",
|
|
72573
|
+
role: "viewer"
|
|
72574
|
+
},
|
|
72575
|
+
"actions.setLinks": {
|
|
72576
|
+
capName: "actions",
|
|
72577
|
+
capScope: "system",
|
|
72578
|
+
addonId: null,
|
|
72579
|
+
access: "create",
|
|
72580
|
+
role: "admin"
|
|
72581
|
+
},
|
|
72582
|
+
"actions.stop": {
|
|
72583
|
+
capName: "actions",
|
|
72584
|
+
capScope: "system",
|
|
72585
|
+
addonId: null,
|
|
72586
|
+
access: "create",
|
|
72587
|
+
role: "admin"
|
|
72588
|
+
},
|
|
72589
|
+
"actions.update": {
|
|
72590
|
+
capName: "actions",
|
|
72591
|
+
capScope: "system",
|
|
72592
|
+
addonId: null,
|
|
72593
|
+
access: "create",
|
|
72594
|
+
role: "admin"
|
|
72595
|
+
},
|
|
72596
|
+
"actionSource.listActions": {
|
|
72597
|
+
capName: "action-source",
|
|
72598
|
+
capScope: "system",
|
|
72599
|
+
addonId: null,
|
|
72600
|
+
access: "view",
|
|
72601
|
+
role: "admin"
|
|
72602
|
+
},
|
|
72603
|
+
"actionSource.runAction": {
|
|
72604
|
+
capName: "action-source",
|
|
72605
|
+
capScope: "system",
|
|
72606
|
+
addonId: null,
|
|
72607
|
+
access: "create",
|
|
72608
|
+
role: "admin"
|
|
72609
|
+
},
|
|
72610
|
+
"actionSource.stopAction": {
|
|
72611
|
+
capName: "action-source",
|
|
72612
|
+
capScope: "system",
|
|
72613
|
+
addonId: null,
|
|
72614
|
+
access: "create",
|
|
72615
|
+
role: "admin"
|
|
72616
|
+
},
|
|
72087
72617
|
"addonPages.listPages": {
|
|
72088
72618
|
capName: "addon-pages",
|
|
72089
72619
|
capScope: "system",
|
|
@@ -73365,6 +73895,13 @@ Object.freeze({
|
|
|
73365
73895
|
access: "view",
|
|
73366
73896
|
role: "admin"
|
|
73367
73897
|
},
|
|
73898
|
+
"coreBlocks.getAutomationRunState": {
|
|
73899
|
+
capName: "core-blocks",
|
|
73900
|
+
capScope: "system",
|
|
73901
|
+
addonId: null,
|
|
73902
|
+
access: "view",
|
|
73903
|
+
role: "admin"
|
|
73904
|
+
},
|
|
73368
73905
|
"coreBlocks.getBlockSettings": {
|
|
73369
73906
|
capName: "core-blocks",
|
|
73370
73907
|
capScope: "system",
|
|
@@ -73386,6 +73923,13 @@ Object.freeze({
|
|
|
73386
73923
|
access: "view",
|
|
73387
73924
|
role: "admin"
|
|
73388
73925
|
},
|
|
73926
|
+
"coreBlocks.getTraces": {
|
|
73927
|
+
capName: "core-blocks",
|
|
73928
|
+
capScope: "system",
|
|
73929
|
+
addonId: null,
|
|
73930
|
+
access: "view",
|
|
73931
|
+
role: "admin"
|
|
73932
|
+
},
|
|
73389
73933
|
"coreBlocks.getTypeDefs": {
|
|
73390
73934
|
capName: "core-blocks",
|
|
73391
73935
|
capScope: "system",
|
|
@@ -73421,6 +73965,13 @@ Object.freeze({
|
|
|
73421
73965
|
access: "create",
|
|
73422
73966
|
role: "admin"
|
|
73423
73967
|
},
|
|
73968
|
+
"coreBlocks.reportAutomationRun": {
|
|
73969
|
+
capName: "core-blocks",
|
|
73970
|
+
capScope: "system",
|
|
73971
|
+
addonId: null,
|
|
73972
|
+
access: "create",
|
|
73973
|
+
role: "admin"
|
|
73974
|
+
},
|
|
73424
73975
|
"coreBlocks.restart": {
|
|
73425
73976
|
capName: "core-blocks",
|
|
73426
73977
|
capScope: "system",
|
|
@@ -85575,6 +86126,8 @@ var ML = "model and training machinery — no device action";
|
|
|
85575
86126
|
var INTERNAL = "internal plumbing between addons — never operator-facing";
|
|
85576
86127
|
/** Every system-scoped cap, with why it is not a device's vocabulary. */
|
|
85577
86128
|
var SYSTEM_CAP_VOCABULARY = {
|
|
86129
|
+
"action-source": system(INTERNAL),
|
|
86130
|
+
actions: system("declared actions — run from the Actions page and from the cameras that link them"),
|
|
85578
86131
|
"addon-pages": system(UI_PLUMBING),
|
|
85579
86132
|
"addon-pages-source": system(UI_PLUMBING),
|
|
85580
86133
|
"addon-routes": system(UI_PLUMBING),
|
|
@@ -85771,6 +86324,31 @@ Object.freeze({
|
|
|
85771
86324
|
form: "single",
|
|
85772
86325
|
optional: false
|
|
85773
86326
|
}],
|
|
86327
|
+
"actions.get": [{
|
|
86328
|
+
name: "deviceId",
|
|
86329
|
+
form: "single",
|
|
86330
|
+
optional: true
|
|
86331
|
+
}],
|
|
86332
|
+
"actions.getLinks": [{
|
|
86333
|
+
name: "deviceId",
|
|
86334
|
+
form: "single",
|
|
86335
|
+
optional: false
|
|
86336
|
+
}],
|
|
86337
|
+
"actions.listForCamera": [{
|
|
86338
|
+
name: "deviceId",
|
|
86339
|
+
form: "single",
|
|
86340
|
+
optional: false
|
|
86341
|
+
}],
|
|
86342
|
+
"actions.run": [{
|
|
86343
|
+
name: "deviceId",
|
|
86344
|
+
form: "single",
|
|
86345
|
+
optional: true
|
|
86346
|
+
}],
|
|
86347
|
+
"actions.setLinks": [{
|
|
86348
|
+
name: "deviceId",
|
|
86349
|
+
form: "single",
|
|
86350
|
+
optional: false
|
|
86351
|
+
}],
|
|
85774
86352
|
"addonSettings.getDeviceSettings": [{
|
|
85775
86353
|
name: "deviceId",
|
|
85776
86354
|
form: "single",
|
|
@@ -90115,11 +90693,11 @@ var AlexaBrokerEntrySchema = object({
|
|
|
90115
90693
|
* operator's browser uses (alexa-cookie2 rewrites Amazon URLs to absolute
|
|
90116
90694
|
* `http://<proxyHost>:<proxyPort>/...`), so it is a directly-reachable host —
|
|
90117
90695
|
* the hub's LAN IP/hostname — NOT behind the hub's HTTPS data-plane mount.
|
|
90118
|
-
* Empty `proxyHost` ⇒
|
|
90119
|
-
* login-start time.
|
|
90696
|
+
* Empty `proxyHost` ⇒ the first LAN address of the hub's `appConnections`
|
|
90697
|
+
* role (local-network palette) at login-start time.
|
|
90120
90698
|
*/
|
|
90121
90699
|
var alexaProxyLoginSchema = object({
|
|
90122
|
-
proxyHost: string().default("").describe("Host/IP the browser uses to reach the login proxy (blank =
|
|
90700
|
+
proxyHost: string().default("").describe("Host/IP the browser uses to reach the login proxy (blank = the hub LAN address)"),
|
|
90123
90701
|
proxyPort: preprocess((v) => v === "" || v === null ? void 0 : v, number().int().min(1).max(65535).default(3456)).describe("Port the local Amazon-login proxy listens on (must be reachable)")
|
|
90124
90702
|
});
|
|
90125
90703
|
/**
|
|
@@ -127848,7 +128426,7 @@ var require_fix_request_body = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
127848
128426
|
* Fix proxied body if bodyParser is involved.
|
|
127849
128427
|
*/
|
|
127850
128428
|
function fixRequestBody(proxyReq, req) {
|
|
127851
|
-
if (req.
|
|
128429
|
+
if (!req.readableEnded) return;
|
|
127852
128430
|
const requestBody = req.body;
|
|
127853
128431
|
if (!requestBody) return;
|
|
127854
128432
|
const contentType = proxyReq.getHeader("Content-Type");
|
|
@@ -127943,6 +128521,12 @@ var require_proxy = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
127943
128521
|
var path$2 = require("path");
|
|
127944
128522
|
var crypto$1 = require("crypto");
|
|
127945
128523
|
var FORMERDATA_STORE_VERSION = 4;
|
|
128524
|
+
var ALEXA_APP_VERSION = "2.2.651540.0";
|
|
128525
|
+
var EXTRA_AMAZON_PROXY_HOSTS = [
|
|
128526
|
+
"amazon.com",
|
|
128527
|
+
"www.amazon.com",
|
|
128528
|
+
"alexa.amazon.com"
|
|
128529
|
+
];
|
|
127946
128530
|
function addCookies(Cookie, headers) {
|
|
127947
128531
|
if (!headers || !headers["set-cookie"]) return Cookie;
|
|
127948
128532
|
const cookies = cookieTools.parse(Cookie);
|
|
@@ -127958,6 +128542,15 @@ var require_proxy = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
127958
128542
|
Cookie = Cookie.replace(/[; ]*$/, "");
|
|
127959
128543
|
return Cookie;
|
|
127960
128544
|
}
|
|
128545
|
+
function isAmazonCookieName(name) {
|
|
128546
|
+
return /^(session-id|session-id-time|session-token|ubid-.+|lc-.+|x-.+|at-.+|sess-at-.+|frc|map-md|csrf|sid|csm-hit|i18n-prefs|sp-cdn|skin)$/.test(name);
|
|
128547
|
+
}
|
|
128548
|
+
function sanitizeAmazonCookie(cookie) {
|
|
128549
|
+
const cookies = cookieTools.parse(cookie || "");
|
|
128550
|
+
let sanitizedCookie = "";
|
|
128551
|
+
for (const name of Object.keys(cookies)) if (isAmazonCookieName(name)) sanitizedCookie += `${name}=${cookies[name]}; `;
|
|
128552
|
+
return sanitizedCookie.replace(/[; ]*$/, "");
|
|
128553
|
+
}
|
|
127961
128554
|
function customStringify(v, func, intent) {
|
|
127962
128555
|
const cache = /* @__PURE__ */ new Map();
|
|
127963
128556
|
return JSON.stringify(v, function(key, value) {
|
|
@@ -127971,6 +128564,29 @@ var require_proxy = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
127971
128564
|
}
|
|
127972
128565
|
function initAmazonProxy(_options, callbackCookie, callbackListening) {
|
|
127973
128566
|
const initialCookies = {};
|
|
128567
|
+
const proxyBase = () => `http://${_options.proxyOwnIp}:${_options.proxyPort}/`;
|
|
128568
|
+
const defaultAmazonHost = `www.${_options.baseAmazonPage}`;
|
|
128569
|
+
const amazonProxyHosts = [];
|
|
128570
|
+
function escapeRegex(data) {
|
|
128571
|
+
return data.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
128572
|
+
}
|
|
128573
|
+
function addAmazonProxyHost(host) {
|
|
128574
|
+
if (host && !amazonProxyHosts.includes(host)) amazonProxyHosts.push(host);
|
|
128575
|
+
}
|
|
128576
|
+
addAmazonProxyHost(defaultAmazonHost);
|
|
128577
|
+
addAmazonProxyHost(`alexa.${_options.baseAmazonPage}`);
|
|
128578
|
+
addAmazonProxyHost(_options.baseAmazonPage);
|
|
128579
|
+
EXTRA_AMAZON_PROXY_HOSTS.forEach(addAmazonProxyHost);
|
|
128580
|
+
function amazonHostFromProxyPath(url) {
|
|
128581
|
+
const match = (url || "").match(/^\/([^/?#]+)(?:[/?#]|$)/);
|
|
128582
|
+
if (match && amazonProxyHosts.includes(match[1])) return match[1];
|
|
128583
|
+
return null;
|
|
128584
|
+
}
|
|
128585
|
+
function amazonHostFromProxyUrl(url) {
|
|
128586
|
+
if (!url) return null;
|
|
128587
|
+
for (const host of amazonProxyHosts) if (url === `${proxyBase()}${host}` || url.startsWith(`${proxyBase()}${host}/`)) return host;
|
|
128588
|
+
return null;
|
|
128589
|
+
}
|
|
127974
128590
|
const formerDataStorePath = _options.formerDataStorePath || path$2.join(__dirname, "formerDataStore.json");
|
|
127975
128591
|
let formerDataStoreValid = false;
|
|
127976
128592
|
if (!_options.formerRegistrationData) try {
|
|
@@ -127994,7 +128610,7 @@ var require_proxy = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
127994
128610
|
_options.logger && _options.logger("Proxy Init: reuse frc from former data");
|
|
127995
128611
|
initialCookies.frc = _options.formerRegistrationData.frc;
|
|
127996
128612
|
}
|
|
127997
|
-
if (!_options.formerRegistrationData || !_options.formerRegistrationData["map-md"]) initialCookies["map-md"] = Buffer.from(
|
|
128613
|
+
if (!_options.formerRegistrationData || !_options.formerRegistrationData["map-md"]) initialCookies["map-md"] = Buffer.from(`{"device_user_dictionary":[],"device_registration_data":{"software_version":"1"},"app_identifier":{"app_version":"${ALEXA_APP_VERSION}","bundle_id":"com.amazon.echo"}}`).toString("base64");
|
|
127998
128614
|
else {
|
|
127999
128615
|
_options.logger && _options.logger("Proxy Init: reuse map-md from former data");
|
|
128000
128616
|
initialCookies["map-md"] = _options.formerRegistrationData["map-md"];
|
|
@@ -128027,11 +128643,49 @@ var require_proxy = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128027
128643
|
const code_verifier = base64URLEncode(crypto$1.randomBytes(32));
|
|
128028
128644
|
const code_challenge = base64URLEncode(sha256(code_verifier));
|
|
128029
128645
|
let proxyCookies = "";
|
|
128646
|
+
let returnedInitUrl;
|
|
128647
|
+
function buildInitialUrl() {
|
|
128648
|
+
return `https://www.${_options.baseAmazonPage}/ap/signin?openid.return_to=https%3A%2F%2Fwww.${_options.baseAmazonPage}%2Fap%2Fmaplanding&openid.assoc_handle=amzn_dp_project_dee_ios${_options.baseAmazonPageHandle}&openid.identity=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&pageId=amzn_dp_project_dee_ios${_options.baseAmazonPageHandle}&accountStatusPolicy=P1&openid.claimed_id=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0%2Fidentifier_select&openid.mode=checkid_setup&openid.ns.oa2=http%3A%2F%2Fwww.${_options.baseAmazonPage}%2Fap%2Fext%2Foauth%2F2&openid.oa2.client_id=device%3A${deviceId}&openid.ns.pape=http%3A%2F%2Fspecs.openid.net%2Fextensions%2Fpape%2F1.0&openid.oa2.response_type=code&openid.ns=http%3A%2F%2Fspecs.openid.net%2Fauth%2F2.0&openid.pape.max_auth_age=0&openid.oa2.scope=device_auth_access&openid.oa2.code_challenge_method=S256&openid.oa2.code_challenge=${code_challenge}&language=${_options.amazonPageProxyLanguage}`;
|
|
128649
|
+
}
|
|
128650
|
+
function fixEmbeddedProxyUrls(pathAndQuery) {
|
|
128651
|
+
const qIndex = pathAndQuery.indexOf("?");
|
|
128652
|
+
if (qIndex === -1) return pathAndQuery;
|
|
128653
|
+
const p = pathAndQuery.slice(0, qIndex);
|
|
128654
|
+
const qs = pathAndQuery.slice(qIndex + 1);
|
|
128655
|
+
let params;
|
|
128656
|
+
try {
|
|
128657
|
+
params = new URLSearchParams(qs);
|
|
128658
|
+
} catch (_e) {
|
|
128659
|
+
return pathAndQuery;
|
|
128660
|
+
}
|
|
128661
|
+
let changed = false;
|
|
128662
|
+
for (const key of params.keys()) {
|
|
128663
|
+
const value = params.get(key);
|
|
128664
|
+
const fixed = replaceHostsBack(value);
|
|
128665
|
+
if (fixed !== value) {
|
|
128666
|
+
params.set(key, fixed);
|
|
128667
|
+
changed = true;
|
|
128668
|
+
}
|
|
128669
|
+
}
|
|
128670
|
+
if (changed) _options.logger && _options.logger(`Alexa-Cookie: Fixed embedded proxy URL(s) in outgoing request query`);
|
|
128671
|
+
return changed ? `${p}?${params.toString()}` : pathAndQuery;
|
|
128672
|
+
}
|
|
128673
|
+
function rewriteProxyPath(url, req) {
|
|
128674
|
+
let result;
|
|
128675
|
+
const urlHost = amazonHostFromProxyPath(url);
|
|
128676
|
+
if (urlHost) result = url.replace(new RegExp(`^/${escapeRegex(urlHost)}`), "") || "/";
|
|
128677
|
+
else if (req && req.headers && req.headers.host === `${_options.proxyOwnIp}:${_options.proxyPort}` && url === "/") {
|
|
128678
|
+
const initialUrl = returnedInitUrl || buildInitialUrl();
|
|
128679
|
+
const parsed = new URL(initialUrl);
|
|
128680
|
+
result = `${parsed.pathname}${parsed.search}`;
|
|
128681
|
+
} else result = url;
|
|
128682
|
+
return fixEmbeddedProxyUrls(result);
|
|
128683
|
+
}
|
|
128030
128684
|
const optionsAlexa = {
|
|
128031
128685
|
target: `https://alexa.${_options.baseAmazonPage}`,
|
|
128032
128686
|
changeOrigin: true,
|
|
128033
128687
|
ws: false,
|
|
128034
|
-
pathRewrite:
|
|
128688
|
+
pathRewrite: rewriteProxyPath,
|
|
128035
128689
|
router,
|
|
128036
128690
|
hostRewrite: true,
|
|
128037
128691
|
followRedirects: false,
|
|
@@ -128039,17 +128693,10 @@ var require_proxy = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128039
128693
|
onError,
|
|
128040
128694
|
onProxyRes,
|
|
128041
128695
|
onProxyReq,
|
|
128042
|
-
headers: {
|
|
128043
|
-
|
|
128044
|
-
|
|
128045
|
-
"authority": `www.${_options.baseAmazonPage}`
|
|
128046
|
-
},
|
|
128047
|
-
cookieDomainRewrite: { "*": "" }
|
|
128696
|
+
headers: { "accept-language": _options.acceptLanguage },
|
|
128697
|
+
cookieDomainRewrite: { "*": "" },
|
|
128698
|
+
cookiePathRewrite: { "*": "/" }
|
|
128048
128699
|
};
|
|
128049
|
-
optionsAlexa.pathRewrite[`^/www.${_options.baseAmazonPage}`] = "";
|
|
128050
|
-
optionsAlexa.pathRewrite[`^/alexa.${_options.baseAmazonPage}`] = "";
|
|
128051
|
-
optionsAlexa.cookieDomainRewrite[`.${_options.baseAmazonPage}`] = _options.proxyOwnIp;
|
|
128052
|
-
optionsAlexa.cookieDomainRewrite[_options.baseAmazonPage] = _options.proxyOwnIp;
|
|
128053
128700
|
if (_options.logger) optionsAlexa.logProvider = function logProvider() {
|
|
128054
128701
|
return {
|
|
128055
128702
|
log: _options.logger.log || _options.logger,
|
|
@@ -128059,22 +128706,20 @@ var require_proxy = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128059
128706
|
error: _options.logger.error || _options.logger
|
|
128060
128707
|
};
|
|
128061
128708
|
};
|
|
128062
|
-
let returnedInitUrl;
|
|
128063
128709
|
function router(req) {
|
|
128064
128710
|
const url = req.originalUrl || req.url;
|
|
128065
128711
|
_options.logger && _options.logger(`Router: ${url} / ${req.method} / ${JSON.stringify(req.headers)}`);
|
|
128066
128712
|
if (req.headers.host === `${_options.proxyOwnIp}:${_options.proxyPort}`) {
|
|
128067
|
-
|
|
128068
|
-
|
|
128069
|
-
|
|
128070
|
-
|
|
128071
|
-
else if (req.headers.referer.startsWith(`http://${_options.proxyOwnIp}:${_options.proxyPort}/alexa.${_options.baseAmazonPage}/`)) return `https://alexa.${_options.baseAmazonPage}`;
|
|
128072
|
-
}
|
|
128713
|
+
const urlHost = amazonHostFromProxyPath(url);
|
|
128714
|
+
if (urlHost) return `https://${urlHost}`;
|
|
128715
|
+
const refererHost = amazonHostFromProxyUrl(req.headers.referer);
|
|
128716
|
+
if (refererHost) return `https://${refererHost}`;
|
|
128073
128717
|
if (url === "/") {
|
|
128074
|
-
returnedInitUrl =
|
|
128718
|
+
returnedInitUrl = buildInitialUrl();
|
|
128075
128719
|
_options.logger && _options.logger(`Alexa-Cookie: Initial Page Request: ${returnedInitUrl}`);
|
|
128076
|
-
|
|
128077
|
-
|
|
128720
|
+
const parsedInitUrl = new URL(returnedInitUrl);
|
|
128721
|
+
return `${parsedInitUrl.protocol}//${parsedInitUrl.host}`;
|
|
128722
|
+
} else return `https://${defaultAmazonHost}`;
|
|
128078
128723
|
}
|
|
128079
128724
|
return `https://alexa.${_options.baseAmazonPage}`;
|
|
128080
128725
|
}
|
|
@@ -128086,21 +128731,34 @@ var require_proxy = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128086
128731
|
} catch (err) {}
|
|
128087
128732
|
}
|
|
128088
128733
|
function replaceHosts(data) {
|
|
128089
|
-
const amazonRegex = new RegExp(`https?://www.${_options.baseAmazonPage}:?[0-9]*/`.replace(/\./g, "\\."), "g");
|
|
128090
|
-
const alexaRegex = new RegExp(`https?://alexa.${_options.baseAmazonPage}:?[0-9]*/`.replace(/\./g, "\\."), "g");
|
|
128091
128734
|
data = data.replace(///g, "/");
|
|
128092
|
-
|
|
128093
|
-
|
|
128735
|
+
for (const host of amazonProxyHosts) {
|
|
128736
|
+
const hostRegex = new RegExp(`https?://${escapeRegex(host)}:?[0-9]*/`, "g");
|
|
128737
|
+
data = data.replace(hostRegex, `${proxyBase()}${host}/`);
|
|
128738
|
+
}
|
|
128094
128739
|
return data;
|
|
128095
128740
|
}
|
|
128096
128741
|
function replaceHostsBack(data) {
|
|
128097
|
-
const
|
|
128098
|
-
const
|
|
128099
|
-
|
|
128100
|
-
|
|
128101
|
-
|
|
128742
|
+
const base = proxyBase();
|
|
128743
|
+
for (const host of amazonProxyHosts) {
|
|
128744
|
+
const hostRegex = new RegExp(`${escapeRegex(base)}${escapeRegex(host)}/`, "g");
|
|
128745
|
+
data = data.replace(hostRegex, `https://${host}/`);
|
|
128746
|
+
}
|
|
128747
|
+
if (data === base) data = returnedInitUrl;
|
|
128748
|
+
else if (data.startsWith(base)) data = `https://${defaultAmazonHost}/${data.slice(base.length)}`;
|
|
128102
128749
|
return data;
|
|
128103
128750
|
}
|
|
128751
|
+
function parseQueryParams(data) {
|
|
128752
|
+
const paramStart = data && data.indexOf("?");
|
|
128753
|
+
if (paramStart === -1 || paramStart === void 0) return {};
|
|
128754
|
+
return querystring$2.parse(data.substr(paramStart + 1));
|
|
128755
|
+
}
|
|
128756
|
+
function isProxySuccessUrl(data) {
|
|
128757
|
+
if (!data) return false;
|
|
128758
|
+
if (data.includes("/spa/index.html")) return true;
|
|
128759
|
+
if (!data.includes("/ap/maplanding?")) return false;
|
|
128760
|
+
return !!parseQueryParams(data)["openid.oa2.authorization_code"];
|
|
128761
|
+
}
|
|
128104
128762
|
function onProxyReq(proxyReq, req) {
|
|
128105
128763
|
const url = req.originalUrl || req.url;
|
|
128106
128764
|
if (url.endsWith(".ico") || url.endsWith(".js") || url.endsWith(".ttf") || url.endsWith(".svg") || url.endsWith(".png") || url.endsWith(".appcache")) return;
|
|
@@ -128127,14 +128785,26 @@ var require_proxy = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128127
128785
|
}
|
|
128128
128786
|
}
|
|
128129
128787
|
if (typeof proxyReq.getHeader === "function" && proxyReq.getHeader("origin") !== `https://${proxyReq.getHeader("host")}`) {
|
|
128130
|
-
proxyReq.setHeader("origin", `https
|
|
128131
|
-
_options.logger && _options.logger("Alexa-Cookie: Modify headers:
|
|
128788
|
+
proxyReq.setHeader("origin", `https://${proxyReq.getHeader("host") || defaultAmazonHost}`);
|
|
128789
|
+
_options.logger && _options.logger("Alexa-Cookie: Modify headers: Changed Origin");
|
|
128132
128790
|
modified = true;
|
|
128133
128791
|
}
|
|
128134
|
-
|
|
128135
|
-
|
|
128136
|
-
|
|
128137
|
-
|
|
128792
|
+
if (req.body && typeof req.body === "object") {
|
|
128793
|
+
let bodyChanged = false;
|
|
128794
|
+
for (const key of Object.keys(req.body)) {
|
|
128795
|
+
const value = req.body[key];
|
|
128796
|
+
if (typeof value !== "string") continue;
|
|
128797
|
+
const fixed = replaceHostsBack(value);
|
|
128798
|
+
if (fixed !== value) {
|
|
128799
|
+
req.body[key] = fixed;
|
|
128800
|
+
bodyChanged = true;
|
|
128801
|
+
}
|
|
128802
|
+
}
|
|
128803
|
+
if (bodyChanged) _options.logger && _options.logger("Alexa-Cookie: Fixed embedded proxy URL(s) in outgoing POST body");
|
|
128804
|
+
const bodyData = querystring$2.stringify(req.body);
|
|
128805
|
+
proxyReq.setHeader("Content-Length", Buffer.byteLength(bodyData));
|
|
128806
|
+
proxyReq.write(bodyData);
|
|
128807
|
+
}
|
|
128138
128808
|
}
|
|
128139
128809
|
_options.proxyLogLevel === "debug" && _options.logger && _options.logger(`Alexa-Cookie: Proxy-Request: (modified:${modified})${customStringify(proxyReq, null, 2)}`);
|
|
128140
128810
|
}
|
|
@@ -128152,17 +128822,22 @@ var require_proxy = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128152
128822
|
proxyCookies = addCookies(proxyCookies, proxyRes.headers);
|
|
128153
128823
|
}
|
|
128154
128824
|
_options.logger && _options.logger(`Alexa-Cookie: Cookies handled: ${JSON.stringify(proxyCookies)}`);
|
|
128155
|
-
|
|
128825
|
+
const outgoing = proxyRes.socket && proxyRes.socket.parser && proxyRes.socket.parser.outgoing;
|
|
128826
|
+
const successUrl = [
|
|
128827
|
+
proxyRes.headers.location,
|
|
128828
|
+
outgoing && outgoing.method === "GET" && outgoing.path,
|
|
128829
|
+
outgoing && outgoing.getHeader && outgoing.getHeader("location")
|
|
128830
|
+
].find(isProxySuccessUrl);
|
|
128831
|
+
if (successUrl) {
|
|
128156
128832
|
_options.logger && _options.logger("Alexa-Cookie: Proxy detected SUCCESS!!");
|
|
128157
|
-
const
|
|
128158
|
-
const queryParams = querystring$2.parse(proxyRes.headers.location.substr(paramStart + 1));
|
|
128833
|
+
const queryParams = parseQueryParams(successUrl);
|
|
128159
128834
|
proxyRes.statusCode = 302;
|
|
128160
128835
|
proxyRes.headers.location = `http://${_options.proxyOwnIp}:${_options.proxyPort}/cookie-success`;
|
|
128161
128836
|
delete proxyRes.headers.referer;
|
|
128162
128837
|
_options.logger && _options.logger(`Alexa-Cookie: Proxy catched cookie: ${proxyCookies}`);
|
|
128163
128838
|
_options.logger && _options.logger(`Alexa-Cookie: Proxy catched parameters: ${JSON.stringify(queryParams)}`);
|
|
128164
128839
|
callbackCookie && callbackCookie(null, {
|
|
128165
|
-
"loginCookie": proxyCookies,
|
|
128840
|
+
"loginCookie": sanitizeAmazonCookie(proxyCookies),
|
|
128166
128841
|
"authorization_code": queryParams["openid.oa2.authorization_code"],
|
|
128167
128842
|
"frc": initialCookies.frc,
|
|
128168
128843
|
"map-md": initialCookies["map-md"],
|
|
@@ -128174,7 +128849,7 @@ var require_proxy = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128174
128849
|
if (proxyRes.headers.location) {
|
|
128175
128850
|
_options.logger && _options.logger(`Redirect: Original Location ----> ${proxyRes.headers.location}`);
|
|
128176
128851
|
proxyRes.headers.location = replaceHosts(proxyRes.headers.location);
|
|
128177
|
-
if (reqestHost && proxyRes.headers.location.startsWith("/")) proxyRes.headers.location = `http://${_options.proxyOwnIp}:${_options.proxyPort}/${reqestHost}${proxyRes.headers.location}`;
|
|
128852
|
+
if (reqestHost && amazonProxyHosts.includes(reqestHost) && proxyRes.headers.location.startsWith("/")) proxyRes.headers.location = `http://${_options.proxyOwnIp}:${_options.proxyPort}/${reqestHost}${proxyRes.headers.location}`;
|
|
128178
128853
|
_options.logger && _options.logger(`Redirect: Final Location ----> ${proxyRes.headers.location}`);
|
|
128179
128854
|
return;
|
|
128180
128855
|
}
|
|
@@ -128192,8 +128867,21 @@ var require_proxy = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128192
128867
|
return body;
|
|
128193
128868
|
});
|
|
128194
128869
|
}
|
|
128870
|
+
function bufferUrlencodedBody(req, res, next) {
|
|
128871
|
+
const contentType = req.headers["content-type"] || "";
|
|
128872
|
+
if (req.method !== "POST" || contentType.indexOf("application/x-www-form-urlencoded") === -1) return next();
|
|
128873
|
+
let raw = "";
|
|
128874
|
+
req.on("data", (chunk) => {
|
|
128875
|
+
raw += chunk;
|
|
128876
|
+
});
|
|
128877
|
+
req.on("end", () => {
|
|
128878
|
+
req.body = querystring$2.parse(raw);
|
|
128879
|
+
next();
|
|
128880
|
+
});
|
|
128881
|
+
}
|
|
128195
128882
|
const myProxy = proxy("!/cookie-success", optionsAlexa);
|
|
128196
128883
|
const app = express();
|
|
128884
|
+
app.use(bufferUrlencodedBody);
|
|
128197
128885
|
app.use(myProxy);
|
|
128198
128886
|
app.get("/cookie-success", function(req, res) {
|
|
128199
128887
|
res.send(_options.proxyCloseWindowHTML);
|
|
@@ -128203,7 +128891,8 @@ var require_proxy = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128203
128891
|
_options.proxyPort = void 0;
|
|
128204
128892
|
}
|
|
128205
128893
|
const server = app.listen(_options.proxyPort, _options.proxyListenBind, function() {
|
|
128206
|
-
_options.
|
|
128894
|
+
_options.proxyPort = this.address().port;
|
|
128895
|
+
_options.logger && _options.logger(`Alexa-Cookie: Proxy-Server listening on port ${_options.proxyPort}`);
|
|
128207
128896
|
callbackListening && callbackListening(server);
|
|
128208
128897
|
callbackListening = null;
|
|
128209
128898
|
}).on("error", (err) => {
|
|
@@ -128249,6 +128938,13 @@ var require_alexa_cookie = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128249
128938
|
let proxyServer;
|
|
128250
128939
|
let _options;
|
|
128251
128940
|
let Cookie = "";
|
|
128941
|
+
const isAmazonCookieName = (name) => /^(session-id|session-id-time|session-token|ubid-.+|lc-.+|x-.+|at-.+|sess-at-.+|frc|map-md|csrf|sid|csm-hit|i18n-prefs|sp-cdn|skin)$/.test(name);
|
|
128942
|
+
const sanitizeAmazonCookie = (cookie) => {
|
|
128943
|
+
const cookies = cookieTools.parse(cookie || "");
|
|
128944
|
+
let sanitizedCookie = "";
|
|
128945
|
+
for (const name of Object.keys(cookies)) if (isAmazonCookieName(name)) sanitizedCookie += `${name}=${cookies[name]}; `;
|
|
128946
|
+
return sanitizedCookie.replace(/[; ]*$/, "");
|
|
128947
|
+
};
|
|
128252
128948
|
const addCookies = (Cookie, headers) => {
|
|
128253
128949
|
if (!headers || !headers["set-cookie"]) return Cookie;
|
|
128254
128950
|
const cookies = cookieTools.parse(Cookie || "");
|
|
@@ -128336,7 +129032,7 @@ var require_alexa_cookie = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128336
129032
|
if (!_options.baseAmazonPageHandle && _options.baseAmazonPageHandle !== "") {
|
|
128337
129033
|
const amazonDomain = _options.baseAmazonPage.substr(_options.baseAmazonPage.lastIndexOf(".") + 1);
|
|
128338
129034
|
if (amazonDomain === "jp") _options.baseAmazonPageHandle = `_${amazonDomain}`;
|
|
128339
|
-
else if (amazonDomain !== "com") _options.baseAmazonPageHandle =
|
|
129035
|
+
else if (amazonDomain !== "com") _options.baseAmazonPageHandle = `_${amazonDomain}`;
|
|
128340
129036
|
else _options.baseAmazonPageHandle = "";
|
|
128341
129037
|
}
|
|
128342
129038
|
if (!_options.userAgent) if (os$1.platform() === "win32") _options.userAgent = defaultUserAgent;
|
|
@@ -128363,7 +129059,7 @@ var require_alexa_cookie = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128363
129059
|
if (_options.formerRegistrationData) _options.proxyOnly = true;
|
|
128364
129060
|
};
|
|
128365
129061
|
const getCSRFFromCookies = (cookie, _options, callback) => {
|
|
128366
|
-
const csrfUrls = csrfOptions;
|
|
129062
|
+
const csrfUrls = [...csrfOptions];
|
|
128367
129063
|
function csrfTry() {
|
|
128368
129064
|
const path = csrfUrls.shift();
|
|
128369
129065
|
const options = {
|
|
@@ -128526,6 +129222,7 @@ var require_alexa_cookie = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128526
129222
|
const handleTokenRegistration = (_options, loginData, callback) => {
|
|
128527
129223
|
_options.logger && _options.logger(`Handle token registration Start: ${JSON.stringify(loginData)}`);
|
|
128528
129224
|
loginData.deviceAppName = _options.deviceAppName;
|
|
129225
|
+
loginData.loginCookie = sanitizeAmazonCookie(loginData.loginCookie);
|
|
128529
129226
|
let deviceSerial;
|
|
128530
129227
|
if (!_options.formerRegistrationData || !_options.formerRegistrationData.deviceSerial) {
|
|
128531
129228
|
const deviceSerialBuffer = Buffer.alloc(16);
|
|
@@ -128613,6 +129310,7 @@ var require_alexa_cookie = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128613
129310
|
Cookie = addCookies(Cookie, response.headers);
|
|
128614
129311
|
loginData.refreshToken = body.response.success.tokens.bearer.refresh_token;
|
|
128615
129312
|
const accessToken = body.response.success.tokens.bearer.access_token;
|
|
129313
|
+
loginData.accessToken = accessToken;
|
|
128616
129314
|
loginData.tokenDate = Date.now();
|
|
128617
129315
|
loginData.macDms = body.response.success.tokens.mac_dms;
|
|
128618
129316
|
if (body.response.success.tokens.website_cookies && Array.isArray(body.response.success.tokens.website_cookies)) {
|
|
@@ -128639,29 +129337,43 @@ var require_alexa_cookie = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128639
129337
|
_options.logger && _options.logger("Alexa-Cookie: Get User data");
|
|
128640
129338
|
_options.logger && _options.logger(JSON.stringify(options));
|
|
128641
129339
|
request(options, (error, response, body) => {
|
|
128642
|
-
if (!error) {
|
|
129340
|
+
if (!error) if (!response || response.statusCode < 200 || response.statusCode >= 300 || !body) {
|
|
129341
|
+
_options.logger && _options.logger(`Get User data Response: status=${response && response.statusCode}, body=${JSON.stringify(body)}`);
|
|
129342
|
+
if (!_options.amazonPage) {
|
|
129343
|
+
callback && callback(/* @__PURE__ */ new Error(`Could not get user data from Amazon: HTTP ${response && response.statusCode}`), null);
|
|
129344
|
+
return;
|
|
129345
|
+
}
|
|
129346
|
+
loginData.amazonPage = _options.amazonPage;
|
|
129347
|
+
} else {
|
|
128643
129348
|
try {
|
|
128644
129349
|
if (typeof body !== "object") body = JSON.parse(body);
|
|
128645
129350
|
} catch (err) {
|
|
128646
129351
|
_options.logger && _options.logger(`Get User data Response: ${JSON.stringify(body)}`);
|
|
128647
|
-
|
|
128648
|
-
|
|
129352
|
+
if (!_options.amazonPage) {
|
|
129353
|
+
callback && callback(err, null);
|
|
129354
|
+
return;
|
|
129355
|
+
}
|
|
129356
|
+
loginData.amazonPage = _options.amazonPage;
|
|
128649
129357
|
}
|
|
128650
129358
|
_options.logger && _options.logger(`Get User data Response: ${JSON.stringify(body)}`);
|
|
128651
129359
|
Cookie = addCookies(Cookie, response.headers);
|
|
128652
|
-
if (body.marketPlaceDomainName) {
|
|
129360
|
+
if (body && body.marketPlaceDomainName) {
|
|
128653
129361
|
const pos = body.marketPlaceDomainName.indexOf(".");
|
|
128654
129362
|
if (pos !== -1) _options.amazonPage = body.marketPlaceDomainName.substr(pos + 1);
|
|
128655
129363
|
}
|
|
128656
129364
|
loginData.amazonPage = _options.amazonPage;
|
|
128657
|
-
}
|
|
129365
|
+
}
|
|
129366
|
+
else if (error && (!_options || !_options.amazonPage)) {
|
|
128658
129367
|
callback && callback(error, null);
|
|
128659
129368
|
return;
|
|
128660
129369
|
} else if (error && (!_options.formerRegistrationData || !_options.formerRegistrationData.amazonPage) && _options.amazonPage) _options.logger && _options.logger(`Continue with externally set amazonPage: ${_options.amazonPage}`);
|
|
128661
129370
|
else if (error) _options.logger && _options.logger("Ignore error while getting user data and amazonPage because previously set amazonPage is available");
|
|
128662
129371
|
loginData.loginCookie = Cookie;
|
|
128663
129372
|
getLocalCookies(loginData.amazonPage, loginData.refreshToken, (err, localCookie) => {
|
|
128664
|
-
if (err)
|
|
129373
|
+
if (err) {
|
|
129374
|
+
callback && callback(err, null);
|
|
129375
|
+
return;
|
|
129376
|
+
}
|
|
128665
129377
|
loginData.localCookie = localCookie;
|
|
128666
129378
|
getCSRFFromCookies(loginData.localCookie, _options, (err, resData) => {
|
|
128667
129379
|
if (err) {
|
|
@@ -128670,7 +129382,6 @@ var require_alexa_cookie = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128670
129382
|
}
|
|
128671
129383
|
loginData.localCookie = resData.cookie;
|
|
128672
129384
|
loginData.csrf = resData.csrf;
|
|
128673
|
-
delete loginData.accessToken;
|
|
128674
129385
|
delete loginData.authorization_code;
|
|
128675
129386
|
delete loginData.verifier;
|
|
128676
129387
|
loginData.dataVersion = 2;
|
|
@@ -128773,6 +129484,39 @@ var require_alexa_cookie = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128773
129484
|
callback && callback(null, localCookie);
|
|
128774
129485
|
});
|
|
128775
129486
|
};
|
|
129487
|
+
const finishCookieRefresh = (loginData, callback) => {
|
|
129488
|
+
_options.logger && _options.logger("Alexa-Cookie: Skip App registration during refresh and update local cookies");
|
|
129489
|
+
const updateLocalCookies = () => {
|
|
129490
|
+
const amazonPage = loginData.amazonPage || _options.amazonPage;
|
|
129491
|
+
getLocalCookies(amazonPage, loginData.refreshToken, (err, localCookie) => {
|
|
129492
|
+
if (err) {
|
|
129493
|
+
callback && callback(err, null);
|
|
129494
|
+
return;
|
|
129495
|
+
}
|
|
129496
|
+
loginData.localCookie = localCookie;
|
|
129497
|
+
getCSRFFromCookies(loginData.localCookie, _options, (err, resData) => {
|
|
129498
|
+
if (err) {
|
|
129499
|
+
callback && callback(/* @__PURE__ */ new Error(`Error getting csrf for ${amazonPage}`), null);
|
|
129500
|
+
return;
|
|
129501
|
+
}
|
|
129502
|
+
loginData.localCookie = resData.cookie;
|
|
129503
|
+
loginData.csrf = resData.csrf;
|
|
129504
|
+
loginData.amazonPage = amazonPage;
|
|
129505
|
+
loginData.tokenDate = Date.now();
|
|
129506
|
+
delete loginData.authorization_code;
|
|
129507
|
+
delete loginData.verifier;
|
|
129508
|
+
loginData.dataVersion = 2;
|
|
129509
|
+
_options.logger && _options.logger("Alexa-Cookie: Refresh finished with updated cookies and csrf");
|
|
129510
|
+
callback && callback(null, loginData);
|
|
129511
|
+
});
|
|
129512
|
+
});
|
|
129513
|
+
};
|
|
129514
|
+
if (loginData.accessToken) {
|
|
129515
|
+
registerTokenCapabilities(loginData.accessToken, updateLocalCookies);
|
|
129516
|
+
return;
|
|
129517
|
+
}
|
|
129518
|
+
updateLocalCookies();
|
|
129519
|
+
};
|
|
128776
129520
|
this.refreshAlexaCookie = (__options, callback) => {
|
|
128777
129521
|
if (!__options || !__options.formerRegistrationData || !__options.formerRegistrationData.loginCookie || !__options.formerRegistrationData.refreshToken) {
|
|
128778
129522
|
callback && callback(/* @__PURE__ */ new Error("No former registration data provided for Cookie Refresh"), null);
|
|
@@ -128839,13 +129583,16 @@ var require_alexa_cookie = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
128839
129583
|
_options.formerRegistrationData.loginCookie = addCookies(Cookie, response.headers);
|
|
128840
129584
|
_options.formerRegistrationData.accessToken = body.access_token;
|
|
128841
129585
|
getLocalCookies(_options.baseAmazonPage, _options.formerRegistrationData.refreshToken, (err, comCookie) => {
|
|
128842
|
-
if (err)
|
|
129586
|
+
if (err) {
|
|
129587
|
+
callback && callback(err, null);
|
|
129588
|
+
return;
|
|
129589
|
+
}
|
|
128843
129590
|
const initCookies = cookieTools.parse(_options.formerRegistrationData.loginCookie);
|
|
128844
129591
|
let newCookie = `frc=${initCookies.frc}; `;
|
|
128845
129592
|
newCookie += `map-md=${initCookies["map-md"]}; `;
|
|
128846
129593
|
newCookie += comCookie;
|
|
128847
|
-
_options.formerRegistrationData.loginCookie = newCookie;
|
|
128848
|
-
|
|
129594
|
+
_options.formerRegistrationData.loginCookie = sanitizeAmazonCookie(newCookie);
|
|
129595
|
+
finishCookieRefresh(_options.formerRegistrationData, callback);
|
|
128849
129596
|
});
|
|
128850
129597
|
});
|
|
128851
129598
|
};
|
|
@@ -129440,10 +130187,20 @@ var import_alexa_remote = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin
|
|
|
129440
130187
|
listItemId: payload.listItemId
|
|
129441
130188
|
});
|
|
129442
130189
|
return;
|
|
130190
|
+
case "NotifyNowPlayingUpdated":
|
|
130191
|
+
const nowPlaying = payload?.update?.update?.nowPlayingData ?? null;
|
|
130192
|
+
this.emit("ws-now-playing-updated", {
|
|
130193
|
+
customerId: payload?.customerId ?? null,
|
|
130194
|
+
taskSessionId: payload?.update?.taskSessionId ?? null,
|
|
130195
|
+
cause: payload?.update?.update?.cause ?? null,
|
|
130196
|
+
mediaId: nowPlaying?.mediaId ?? null,
|
|
130197
|
+
playerState: nowPlaying?.playerState ?? null,
|
|
130198
|
+
nowPlayingData: nowPlaying
|
|
130199
|
+
});
|
|
130200
|
+
return;
|
|
129443
130201
|
case "PUSH_MICROPHONE_STATE":
|
|
129444
130202
|
case "PUSH_DELETE_DOPPLER_ACTIVITIES":
|
|
129445
130203
|
case "PUSH_DEVICE_SETUP_STATE_CHANGE":
|
|
129446
|
-
case "NotifyNowPlayingUpdated":
|
|
129447
130204
|
case "NotifyMediaSessionsUpdated": return;
|
|
129448
130205
|
}
|
|
129449
130206
|
this.emit("ws-unknown-command", command, payload);
|
|
@@ -131490,7 +132247,7 @@ var import_alexa_remote = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin
|
|
|
131490
132247
|
*/
|
|
131491
132248
|
var ALEXA_API_USER_AGENT_POSTFIX = `AlexaRemote/${{
|
|
131492
132249
|
name: "alexa-remote2",
|
|
131493
|
-
version: "8.
|
|
132250
|
+
version: "8.1.1",
|
|
131494
132251
|
description: "Remote Control for amazon echo devices",
|
|
131495
132252
|
author: {
|
|
131496
132253
|
"name": "Apollon77",
|
|
@@ -131519,16 +132276,16 @@ var ALEXA_API_USER_AGENT_POSTFIX = `AlexaRemote/${{
|
|
|
131519
132276
|
"layla.amazon.de"
|
|
131520
132277
|
],
|
|
131521
132278
|
dependencies: {
|
|
131522
|
-
"alexa-cookie2": "^5.0.
|
|
132279
|
+
"alexa-cookie2": "^5.0.6",
|
|
131523
132280
|
"https": "^1.0.0",
|
|
131524
132281
|
"querystring": "^0.2.1",
|
|
131525
|
-
"ws": "^8.
|
|
132282
|
+
"ws": "^8.21.0",
|
|
131526
132283
|
"extend": "^3.0.2",
|
|
131527
|
-
"uuid": "^11.1.
|
|
132284
|
+
"uuid": "^11.1.1"
|
|
131528
132285
|
},
|
|
131529
132286
|
devDependencies: {
|
|
131530
|
-
"@alcalzone/release-script": "^5.
|
|
131531
|
-
"@alcalzone/release-script-plugin-license": "^
|
|
132287
|
+
"@alcalzone/release-script": "^5.2.1",
|
|
132288
|
+
"@alcalzone/release-script-plugin-license": "^5.2.0",
|
|
131532
132289
|
"eslint": "^8.57.1"
|
|
131533
132290
|
},
|
|
131534
132291
|
scripts: {
|
|
@@ -131627,6 +132384,7 @@ var AlexaProxyLoginSession = class {
|
|
|
131627
132384
|
error: errMsg(err)
|
|
131628
132385
|
} });
|
|
131629
132386
|
}
|
|
132387
|
+
await stopProxy(remote, this.#logger, this.#opts.sessionId);
|
|
131630
132388
|
}
|
|
131631
132389
|
/** Mark cancelled + dispose. */
|
|
131632
132390
|
async cancel() {
|
|
@@ -131680,6 +132438,24 @@ var AlexaProxyLoginSession = class {
|
|
|
131680
132438
|
this.dispose();
|
|
131681
132439
|
}
|
|
131682
132440
|
};
|
|
132441
|
+
/** Close the login proxy so its port is free for the next session (idempotent). */
|
|
132442
|
+
function stopProxy(remote, logger, sessionId) {
|
|
132443
|
+
return new Promise((resolve) => {
|
|
132444
|
+
try {
|
|
132445
|
+
if (typeof remote.stopProxyServer !== "function") {
|
|
132446
|
+
resolve();
|
|
132447
|
+
return;
|
|
132448
|
+
}
|
|
132449
|
+
remote.stopProxyServer(() => resolve());
|
|
132450
|
+
} catch (err) {
|
|
132451
|
+
logger.warn("alexa proxy-login: stopProxyServer failed", { meta: {
|
|
132452
|
+
sessionId,
|
|
132453
|
+
error: errMsg(err)
|
|
132454
|
+
} });
|
|
132455
|
+
resolve();
|
|
132456
|
+
}
|
|
132457
|
+
});
|
|
132458
|
+
}
|
|
131683
132459
|
/**
|
|
131684
132460
|
* Lines emitted by alexa-cookie2 that contain raw credential material
|
|
131685
132461
|
* (cookie values, CSRF tokens, bearer tokens). Any log line matching this
|
|
@@ -131707,15 +132483,62 @@ function isStringOrObject(value) {
|
|
|
131707
132483
|
return typeof value === "string" || typeof value === "object" && value !== null;
|
|
131708
132484
|
}
|
|
131709
132485
|
//#endregion
|
|
132486
|
+
//#region src/alexa-proxy-host.ts
|
|
132487
|
+
/** Typed refusal: names WHY no proxy host could be chosen. */
|
|
132488
|
+
var AlexaProxyHostError = class extends Error {
|
|
132489
|
+
reason;
|
|
132490
|
+
constructor(reason, message, options) {
|
|
132491
|
+
super(message, options);
|
|
132492
|
+
this.name = "AlexaProxyHostError";
|
|
132493
|
+
this.reason = reason;
|
|
132494
|
+
}
|
|
132495
|
+
};
|
|
132496
|
+
var PRIVATE_IPV4 = /^(10\.|192\.168\.|172\.(1[6-9]|2\d|3[01])\.|169\.254\.)/;
|
|
132497
|
+
var IPV4_LITERAL = /^\d{1,3}(\.\d{1,3}){3}$/;
|
|
132498
|
+
/** A host a browser on the hub's network reaches directly: private IPv4, `.local`, or a bare name. */
|
|
132499
|
+
function isLanHost(host) {
|
|
132500
|
+
if (host.length === 0) return false;
|
|
132501
|
+
if (IPV4_LITERAL.test(host)) return PRIVATE_IPV4.test(host);
|
|
132502
|
+
if (host.includes(":")) return false;
|
|
132503
|
+
return host.endsWith(".local") || !host.includes(".");
|
|
132504
|
+
}
|
|
132505
|
+
function lanHostOf(address) {
|
|
132506
|
+
try {
|
|
132507
|
+
const host = new URL(address).hostname;
|
|
132508
|
+
return isLanHost(host) && host !== "localhost" ? host : null;
|
|
132509
|
+
} catch {
|
|
132510
|
+
return null;
|
|
132511
|
+
}
|
|
132512
|
+
}
|
|
132513
|
+
async function resolveProxyHost(input) {
|
|
132514
|
+
const override = input.override.trim();
|
|
132515
|
+
if (override.length > 0) return override;
|
|
132516
|
+
let addresses;
|
|
132517
|
+
try {
|
|
132518
|
+
addresses = await input.readAppConnections();
|
|
132519
|
+
} catch (err) {
|
|
132520
|
+
input.logger.warn("alexa proxy-login: hub addresses unavailable from local-network", { meta: { error: errMsg(err) } });
|
|
132521
|
+
throw new AlexaProxyHostError("palette-unavailable", "alexa proxy-login: the hub address list is unavailable — set proxyHost in settings", { cause: err });
|
|
132522
|
+
}
|
|
132523
|
+
for (const address of addresses) {
|
|
132524
|
+
const host = lanHostOf(address);
|
|
132525
|
+
if (host !== null) return host;
|
|
132526
|
+
}
|
|
132527
|
+
input.logger.warn("alexa proxy-login: no LAN address among the hub appConnections", { meta: { addresses: [...addresses] } });
|
|
132528
|
+
throw new AlexaProxyHostError("no-lan-address", "alexa proxy-login: the hub has no LAN address the browser can open directly — set proxyHost in settings");
|
|
132529
|
+
}
|
|
132530
|
+
//#endregion
|
|
131710
132531
|
//#region src/alexa-proxy-login-manager.ts
|
|
131711
132532
|
var AlexaProxyLoginManager = class {
|
|
131712
132533
|
#logger;
|
|
131713
132534
|
#getProxyConfig;
|
|
132535
|
+
#getAppConnectionAddresses;
|
|
131714
132536
|
#session = null;
|
|
131715
132537
|
#captured = /* @__PURE__ */ new Map();
|
|
131716
132538
|
constructor(deps) {
|
|
131717
132539
|
this.#logger = deps.logger;
|
|
131718
132540
|
this.#getProxyConfig = deps.getProxyConfig;
|
|
132541
|
+
this.#getAppConnectionAddresses = deps.getAppConnectionAddresses;
|
|
131719
132542
|
}
|
|
131720
132543
|
/**
|
|
131721
132544
|
* Start a fresh proxy-login. Cancels any in-flight session first (single
|
|
@@ -131724,8 +132547,11 @@ var AlexaProxyLoginManager = class {
|
|
|
131724
132547
|
async start(amazonDomain) {
|
|
131725
132548
|
await this.cancelActive();
|
|
131726
132549
|
const { proxyHost, proxyPort } = this.#getProxyConfig();
|
|
131727
|
-
const host =
|
|
131728
|
-
|
|
132550
|
+
const host = await resolveProxyHost({
|
|
132551
|
+
override: proxyHost,
|
|
132552
|
+
readAppConnections: this.#getAppConnectionAddresses,
|
|
132553
|
+
logger: this.#logger
|
|
132554
|
+
});
|
|
131729
132555
|
const sessionId = (0, node_crypto.randomBytes)(9).toString("base64url");
|
|
131730
132556
|
const session = new AlexaProxyLoginSession({
|
|
131731
132557
|
sessionId,
|
|
@@ -131793,19 +132619,6 @@ var AlexaProxyLoginManager = class {
|
|
|
131793
132619
|
}
|
|
131794
132620
|
};
|
|
131795
132621
|
/**
|
|
131796
|
-
* Best-effort primary non-loopback IPv4 of the host. Used when the operator
|
|
131797
|
-
* leaves `proxyHost` blank. Returns '' when none found (then the operator must
|
|
131798
|
-
* set it explicitly — common on multi-homed/containerised hosts).
|
|
131799
|
-
*/
|
|
131800
|
-
function detectPrimaryIpv4() {
|
|
131801
|
-
const ifaces = (0, node_os.networkInterfaces)();
|
|
131802
|
-
for (const addrs of Object.values(ifaces)) {
|
|
131803
|
-
if (addrs === void 0) continue;
|
|
131804
|
-
for (const addr of addrs) if (addr.family === "IPv4" && !addr.internal && addr.address.length > 0) return addr.address;
|
|
131805
|
-
}
|
|
131806
|
-
return "";
|
|
131807
|
-
}
|
|
131808
|
-
/**
|
|
131809
132622
|
* Serialize the captured `cookieData` blob into the single STRING the broker
|
|
131810
132623
|
* connection stores in its `cookie` field. `AlexaRemoteClient` already parses a
|
|
131811
132624
|
* JSON-object cookie string back into the richer object form on init, so we
|
|
@@ -135502,7 +136315,8 @@ var AlexaImportAddon = class extends BaseDeviceProvider {
|
|
|
135502
136315
|
proxyHost: cfg.proxyHost,
|
|
135503
136316
|
proxyPort: cfg.proxyPort
|
|
135504
136317
|
};
|
|
135505
|
-
}
|
|
136318
|
+
},
|
|
136319
|
+
getAppConnectionAddresses: async () => (await this.ctx.api.localNetwork.getAddresses.query()).roles.appConnections.resolved
|
|
135506
136320
|
});
|
|
135507
136321
|
this.ctx.logger.info("Alexa: import addon initialised", { meta: { brokerCount: this.activeBrokers.length } });
|
|
135508
136322
|
await this.reconcileIntegrationsToBrokers();
|