@mega-yfue/eufy-sdk 0.4.0-beta.4 → 0.4.0-beta.6

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.
@@ -99,28 +99,35 @@ export declare class SecureMqtt extends EventEmitter implements RealtimeTranspor
99
99
  private open;
100
100
  /**
101
101
  * Subscribe every inbound leg this device's line uses (see `topics.ts` — one `/res` for most lines,
102
- * four topics for `eufy_life`).
102
+ * four topics for `eufy_life` and the clean line).
103
103
  *
104
- * The grants are INSPECTED, not assumed: AWS IoT answers a policy-denied filter with a
105
- * SUBACK_FAILURE (`0x80`) grant rather than failing the SUBSCRIBE, so subscribing with a credential
106
- * whose scope doesn't cover the topic looks identical to success and then delivers nothing. A denied
107
- * topic is reported via `error` naming the credential scope; only an all-denied device throws, so a
108
- * line that grants its state channel but refuses (say) the OTA leg still works.
104
+ * The grants are INSPECTED, not assumed: AWS IoT refuses a policy-denied filter with a
105
+ * {@link SUBACK_FAILURE} grant rather than failing the connection. A denied topic is reported via
106
+ * `error` naming the credential scope; only an all-denied device throws, so a line that grants its
107
+ * state channel but refuses (say) a business leg still works.
109
108
  */
110
109
  subscribeDevice(device: EufyDevice): Promise<void>;
111
110
  /**
112
111
  * Subscribe to explicit topic filters, returning the topics that were granted. A scope-denied filter
113
- * comes back with SUBACK_FAILURE rather than an error (AWS IoT quirk), so it is dropped from the result
114
- * instead of throwing — callers that need every leg check the returned list. Used by lines whose topic
115
- * vocabulary isn't the eufy `subscribeTopics` shape (e.g. Anker Solix `dt/{app}/{pn}/{sn}`).
112
+ * is dropped from the result instead of throwing — callers that need every leg check the returned
113
+ * list. Used by lines whose topic vocabulary isn't the eufy `subscribeTopics` shape (e.g. Anker Solix
114
+ * `dt/{app}/{pn}/{sn}`).
116
115
  */
117
116
  subscribe(topics: string[]): Promise<string[]>;
118
117
  /**
119
- * Split SUBACK grants into granted vs scope-denied topics. AWS IoT marks a policy-denied filter with a
120
- * SUBACK_FAILURE (`0x80`) grant rather than failing the SUBSCRIBE, so the two subscribe paths share
121
- * this split and layer their own policy (drop vs report) on top.
118
+ * Subscribe each filter in a SUBSCRIBE of its own and split the outcome into granted vs refused.
119
+ *
120
+ * One request per filter because the MQTT engine treats a SUBACK as all-or-nothing: one refused grant
121
+ * rejects the whole request, and it forgets EVERY filter of that request for resubscription after a
122
+ * reconnect — so a batch holding one denied leg would lose the granted legs on the next drop. Alone,
123
+ * a refused filter costs only itself. A rejection that carries no SUBACK is a transport failure and
124
+ * is thrown.
125
+ *
126
+ * The cost is one SUBSCRIBE and one SUBACK per filter instead of one per device — four for a
127
+ * four-leg line. They are sent concurrently, so the wall-clock cost is one round trip. Folding them
128
+ * back into one request brings back the lost resubscription.
122
129
  */
123
- private partitionGrants;
130
+ private subscribeEach;
124
131
  /**
125
132
  * Publish a raw payload to an MQTT topic (the command leg — `cmd/{app}/{pn}/{sn}/req`). The `body`
126
133
  * is a pre-built envelope the caller supplies (the command router builds it). QoS 1 by default (the
@@ -95,6 +95,8 @@ export declare class P2PSession extends EventEmitter {
95
95
  private connected;
96
96
  private connecting;
97
97
  private closed;
98
+ /** Whether a short receive buffer has been reported, so a reconnect does not repeat the same warning. */
99
+ private receiveBufferReported;
98
100
  private connectAddress?;
99
101
  private seqNumber;
100
102
  /**
@@ -274,6 +276,14 @@ export declare class P2PSession extends EventEmitter {
274
276
  */
275
277
  private decryptLevel2;
276
278
  get isConnected(): boolean;
279
+ /**
280
+ * Ask the OS for {@link RECEIVE_BUFFER_BYTES} on a bound socket, and warn once per session when it grants
281
+ * less or refuses.
282
+ *
283
+ * The request is made here rather than through `createSocket`'s `recvBufferSize`: Node applies that option
284
+ * inside the bind callback, where a refusal is thrown out of reach of this session and ends the process.
285
+ */
286
+ private requestReceiveBuffer;
277
287
  /** Open the socket and start the lookup → hole-punch handshake. */
278
288
  connect(): Promise<void>;
279
289
  /** Cached across every `P2PSession` in this process — the local outbound IPv4 doesn't vary by
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mega-yfue/eufy-sdk",
3
- "version": "0.4.0-beta.4",
3
+ "version": "0.4.0-beta.6",
4
4
  "description": "One typed TypeScript client for the Anker eufy v6 cloud — capability-driven devices, realtime events over P2P/MQTT/push, and live media",
5
5
  "license": "Apache-2.0",
6
6
  "author": "mega-yfue",