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