@espressif/rainmaker-neo-base-sdk 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/ESPRMNeoBase.js +1 -1
- package/dist/cjs/index.js +11 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/proto/rmaker_local_ctrl.js +273 -0
- package/dist/cjs/proto/rmaker_local_ctrl.js.map +1 -0
- package/dist/cjs/services/ESPTransport/ESPDiscovery/ESPDiscoveryManager.js +5 -4
- package/dist/cjs/services/ESPTransport/ESPDiscovery/ESPDiscoveryManager.js.map +1 -1
- package/dist/cjs/services/ESPTransport/ESPLocalControlTransport.js +183 -116
- package/dist/cjs/services/ESPTransport/ESPLocalControlTransport.js.map +1 -1
- package/dist/cjs/services/ESPTransport/LocalControlSession.js +62 -0
- package/dist/cjs/services/ESPTransport/LocalControlSession.js.map +1 -0
- package/dist/cjs/types/transport.js +24 -0
- package/dist/cjs/types/transport.js.map +1 -1
- package/dist/cjs/utils/constants.js +70 -4
- package/dist/cjs/utils/constants.js.map +1 -1
- package/dist/cjs/utils/eventSubscriptionUtils.js +48 -4
- package/dist/cjs/utils/eventSubscriptionUtils.js.map +1 -1
- package/dist/esm/ESPRMNeoBase.js +1 -1
- package/dist/esm/index.js +2 -2
- package/dist/esm/proto/rmaker_local_ctrl.js +271 -0
- package/dist/esm/proto/rmaker_local_ctrl.js.map +1 -0
- package/dist/esm/services/ESPTransport/ESPDiscovery/ESPDiscoveryManager.js +5 -4
- package/dist/esm/services/ESPTransport/ESPDiscovery/ESPDiscoveryManager.js.map +1 -1
- package/dist/esm/services/ESPTransport/ESPLocalControlTransport.js +184 -117
- package/dist/esm/services/ESPTransport/ESPLocalControlTransport.js.map +1 -1
- package/dist/esm/services/ESPTransport/LocalControlSession.js +59 -0
- package/dist/esm/services/ESPTransport/LocalControlSession.js.map +1 -0
- package/dist/esm/types/transport.js +24 -1
- package/dist/esm/types/transport.js.map +1 -1
- package/dist/esm/utils/constants.js +65 -5
- package/dist/esm/utils/constants.js.map +1 -1
- package/dist/esm/utils/eventSubscriptionUtils.js +49 -5
- package/dist/esm/utils/eventSubscriptionUtils.js.map +1 -1
- package/dist/types/ESPRMNeoBase.d.ts +1 -1
- package/dist/types/proto/rmaker_local_ctrl.d.ts +137 -0
- package/dist/types/services/ESPTransport/ESPDiscovery/ESPDiscoveryManager.d.ts +4 -3
- package/dist/types/services/ESPTransport/ESPLocalControlTransport.d.ts +70 -23
- package/dist/types/services/ESPTransport/LocalControlSession.d.ts +24 -0
- package/dist/types/types/discovery.d.ts +1 -1
- package/dist/types/types/localControl.d.ts +26 -1
- package/dist/types/types/transport.d.ts +24 -2
- package/dist/types/utils/baseUtils.d.ts +1 -1
- package/dist/types/utils/constants.d.ts +65 -5
- package/dist/types/utils/eventSubscriptionUtils.d.ts +19 -3
- package/package.json +1 -1
- package/dist/cjs/proto/constants.js +0 -24
- package/dist/cjs/proto/constants.js.map +0 -1
- package/dist/cjs/proto/esp_local_ctrl.js +0 -787
- package/dist/cjs/proto/esp_local_ctrl.js.map +0 -1
- package/dist/esm/proto/constants.js +0 -24
- package/dist/esm/proto/constants.js.map +0 -1
- package/dist/esm/proto/esp_local_ctrl.js +0 -758
- package/dist/esm/proto/esp_local_ctrl.js.map +0 -1
- package/dist/types/proto/constants.d.ts +0 -15
- package/dist/types/proto/esp_local_ctrl.d.ts +0 -283
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ESPLocalControlTransport.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ESPLocalControlTransport.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { ESPRMNeoBase } from '../../ESPRMNeoBase.js';
|
|
2
|
+
|
|
3
|
+
/*
|
|
4
|
+
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
|
5
|
+
*
|
|
6
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
7
|
+
*/
|
|
8
|
+
/** Attempts made before a local-control handshake is reported as failed. */
|
|
9
|
+
const DEFAULT_CONNECT_RETRIES = 3;
|
|
10
|
+
/**
|
|
11
|
+
* Returns the app-supplied local control adapter.
|
|
12
|
+
*
|
|
13
|
+
* @throws {Error} When no adapter was registered on {@link ESPRMNeoBase}.
|
|
14
|
+
*/
|
|
15
|
+
function getLocalControlAdapter() {
|
|
16
|
+
const adapter = ESPRMNeoBase.getLocalControlAdapter();
|
|
17
|
+
if (!adapter) {
|
|
18
|
+
throw new Error("Local control adapter is not configured");
|
|
19
|
+
}
|
|
20
|
+
return adapter;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Ensures a usable local-control session for `nodeId`, connecting (with
|
|
24
|
+
* retries) when the adapter reports none.
|
|
25
|
+
*
|
|
26
|
+
* The adapter resolves on a successful handshake and rejects otherwise, so a
|
|
27
|
+
* resolved `connect` is treated as connected.
|
|
28
|
+
*
|
|
29
|
+
* @param adapter - Adapter to drive.
|
|
30
|
+
* @param nodeId - Node to connect to.
|
|
31
|
+
* @param metadata - Local transport metadata (`baseUrl`, `securityType`, `pop`,
|
|
32
|
+
* `username`).
|
|
33
|
+
* @param options - Session endpoints for the protocol in use; omitted for the
|
|
34
|
+
* adapter's built-in default paths.
|
|
35
|
+
* @param maxRetries - Connection attempts before failing.
|
|
36
|
+
* @throws {Error} When every connection attempt fails.
|
|
37
|
+
*/
|
|
38
|
+
async function ensureLocalControlSession(adapter, nodeId, metadata, options, maxRetries = DEFAULT_CONNECT_RETRIES) {
|
|
39
|
+
if (await adapter.isConnected(nodeId)) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
let attempt = 0;
|
|
43
|
+
let lastError;
|
|
44
|
+
while (attempt < maxRetries) {
|
|
45
|
+
try {
|
|
46
|
+
await adapter.connect(nodeId, metadata.baseUrl, metadata.securityType ?? 0, metadata.pop, metadata.username, options);
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
lastError = error;
|
|
51
|
+
attempt += 1;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const message = lastError instanceof Error ? lastError.message : String(lastError);
|
|
55
|
+
throw new Error(`Failed to connect after ${maxRetries} attempts: ${message}`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export { ensureLocalControlSession, getLocalControlAdapter };
|
|
59
|
+
//# sourceMappingURL=LocalControlSession.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LocalControlSession.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -17,6 +17,29 @@ var ESPTransportMode;
|
|
|
17
17
|
/** Communication is routed through MQTT (RainMaker Neo cloud: AWS shadow). */
|
|
18
18
|
ESPTransportMode["mqtt"] = "mqtt";
|
|
19
19
|
})(ESPTransportMode || (ESPTransportMode = {}));
|
|
20
|
+
/**
|
|
21
|
+
* Wire protocol spoken by the `local` transport. Both protocols run over a
|
|
22
|
+
* protocomm session on the node's LAN HTTP server; they differ in endpoint
|
|
23
|
+
* names and message encoding.
|
|
24
|
+
*
|
|
25
|
+
* Carried on the local transport config's `metadata.protocol`, set by local
|
|
26
|
+
* discovery from the mDNS service type that produced the hit.
|
|
27
|
+
*/
|
|
28
|
+
var ESPLocalControlProtocol;
|
|
29
|
+
(function (ESPLocalControlProtocol) {
|
|
30
|
+
/**
|
|
31
|
+
* RainMaker Neo protocol (`rmaker_local_ctrl/*` session plus
|
|
32
|
+
* `get_params`/`set_params`/`get_config`), advertised as
|
|
33
|
+
* `_esp_rmaker_ctrl._tcp`. Default for this SDK.
|
|
34
|
+
*/
|
|
35
|
+
ESPLocalControlProtocol["rmakerLocalCtrl"] = "rmaker_local_ctrl";
|
|
36
|
+
})(ESPLocalControlProtocol || (ESPLocalControlProtocol = {}));
|
|
37
|
+
/**
|
|
38
|
+
* Protocol assumed when a local transport config carries no explicit
|
|
39
|
+
* `metadata.protocol` — for example a LAN transport restored from a client-side
|
|
40
|
+
* registry rather than a fresh discovery hit.
|
|
41
|
+
*/
|
|
42
|
+
const DEFAULT_LOCAL_CONTROL_PROTOCOL = ESPLocalControlProtocol.rmakerLocalCtrl;
|
|
20
43
|
/**
|
|
21
44
|
* Default transport priority order used when neither the node nor the SDK base
|
|
22
45
|
* has an explicit order configured: local control first, MQTT (cloud) fallback.
|
|
@@ -26,5 +49,5 @@ const DEFAULT_TRANSPORT_ORDER = [
|
|
|
26
49
|
ESPTransportMode.mqtt,
|
|
27
50
|
];
|
|
28
51
|
|
|
29
|
-
export { DEFAULT_TRANSPORT_ORDER, ESPTransportMode };
|
|
52
|
+
export { DEFAULT_LOCAL_CONTROL_PROTOCOL, DEFAULT_TRANSPORT_ORDER, ESPLocalControlProtocol, ESPTransportMode };
|
|
30
53
|
//# sourceMappingURL=transport.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transport.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transport.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -473,8 +473,6 @@ const ProvisionType = {
|
|
|
473
473
|
* An object containing endpoint paths.
|
|
474
474
|
*/
|
|
475
475
|
const Endpoint = {
|
|
476
|
-
/** The endpoint for local control. */
|
|
477
|
-
LOCAL_CTRL: "esp_local_ctrl/control",
|
|
478
476
|
/** The endpoint for cloud user association. */
|
|
479
477
|
CLOUD_USER_ASSOCIATION: "cloud_user_assoc",
|
|
480
478
|
/** The endpoint for challenge-response and get-node-id protocol with the device. */
|
|
@@ -482,6 +480,64 @@ const Endpoint = {
|
|
|
482
480
|
/** The endpoint for assisted claiming. */
|
|
483
481
|
RM_CLAIM: "rmaker_claim",
|
|
484
482
|
};
|
|
483
|
+
/**
|
|
484
|
+
* Endpoint paths of the `rmaker_local_ctrl` protocol served by RainMaker Neo
|
|
485
|
+
* firmware (see the firmware's local-control endpoint protocol spec).
|
|
486
|
+
*
|
|
487
|
+
* All data endpoints inherit the security of the session established on
|
|
488
|
+
* {@link RMakerLocalCtrlEndpoint.SESSION}.
|
|
489
|
+
*/
|
|
490
|
+
const RMakerLocalCtrlEndpoint = {
|
|
491
|
+
/** Protocomm session-security endpoint (SEC1 with/without PoP, or SEC2). */
|
|
492
|
+
SESSION: "rmaker_local_ctrl/session",
|
|
493
|
+
/** POST any payload; responds with the service info JSON (`sec_ver`, `cap`, …). */
|
|
494
|
+
VERSION: "rmaker_local_ctrl/version",
|
|
495
|
+
/** Reads the params JSON — protobuf `CmdGetData`, fragmented response. */
|
|
496
|
+
GET_PARAMS: "get_params",
|
|
497
|
+
/** Reads the node config JSON — protobuf `CmdGetData`, fragmented response. */
|
|
498
|
+
GET_CONFIG: "get_config",
|
|
499
|
+
/** Writes params — raw JSON request and response (no protobuf). */
|
|
500
|
+
SET_PARAMS: "set_params",
|
|
501
|
+
};
|
|
502
|
+
/**
|
|
503
|
+
* Root key of the JSON served by {@link RMakerLocalCtrlEndpoint.VERSION}, i.e.
|
|
504
|
+
* `{"rmaker_local_ctrl": {"ver": …, "sec_ver": …, "cap": [...]}}`. Passed to the
|
|
505
|
+
* local-control adapter so the native layer probes the right scheme version.
|
|
506
|
+
*/
|
|
507
|
+
const RMAKER_LOCAL_CTRL_VERSION_KEY = "rmaker_local_ctrl";
|
|
508
|
+
/**
|
|
509
|
+
* Maximum fragment size (bytes) the firmware serves per `RespGetData`. Reads
|
|
510
|
+
* loop with `Offset += Payload.length` until `TotalLen` is reached; this value
|
|
511
|
+
* is informational (the device dictates the actual fragment length).
|
|
512
|
+
*/
|
|
513
|
+
const RMAKER_LOCAL_CTRL_FRAGMENT_SIZE = 200;
|
|
514
|
+
/**
|
|
515
|
+
* `status` values in a `set_params` raw-JSON response.
|
|
516
|
+
*/
|
|
517
|
+
const RMakerLocalCtrlSetParamsStatus = {
|
|
518
|
+
SUCCESS: "success",
|
|
519
|
+
FAIL: "fail",
|
|
520
|
+
};
|
|
521
|
+
/**
|
|
522
|
+
* mDNS TXT record keys advertised by the `_esp_rmaker_ctrl._tcp` service.
|
|
523
|
+
*/
|
|
524
|
+
const RMakerLocalCtrlTxtKey = {
|
|
525
|
+
/** Node ID (also the service instance name and hostname). */
|
|
526
|
+
NODE_ID: "node_id",
|
|
527
|
+
/** Comma-separated active capabilities — see {@link RMakerLocalCtrlCapability}. */
|
|
528
|
+
CAP: "cap",
|
|
529
|
+
};
|
|
530
|
+
/**
|
|
531
|
+
* Capability tokens found in the `cap` TXT record. A node advertising only
|
|
532
|
+
* `ch_resp` is reachable for on-network user-node association but *not* for
|
|
533
|
+
* param control, so it must not be registered as a local control transport.
|
|
534
|
+
*/
|
|
535
|
+
const RMakerLocalCtrlCapability = {
|
|
536
|
+
/** Params/config endpoints are registered. */
|
|
537
|
+
LOCAL_CTRL: "local_ctrl",
|
|
538
|
+
/** Challenge-response (on-network user-node association) is registered. */
|
|
539
|
+
CH_RESP: "ch_resp",
|
|
540
|
+
};
|
|
485
541
|
/**
|
|
486
542
|
* Assisted-claiming REST paths, on the deployment's main API and SigV4-signed
|
|
487
543
|
* like every other `/v1/*` route.
|
|
@@ -639,8 +695,12 @@ const ProvErrorCodes = {
|
|
|
639
695
|
* @enum {string}
|
|
640
696
|
*/
|
|
641
697
|
const ServiceType = {
|
|
642
|
-
/**
|
|
643
|
-
|
|
698
|
+
/**
|
|
699
|
+
* Service type advertised by RainMaker Neo firmware. A single instance serves
|
|
700
|
+
* the `rmaker_local_ctrl` endpoints; the `cap` TXT record says which endpoint
|
|
701
|
+
* sets are active. This is the default for local discovery in this SDK.
|
|
702
|
+
*/
|
|
703
|
+
ESP_RMAKER_LOCAL_CTRL_TCP: "_esp_rmaker_ctrl._tcp.",
|
|
644
704
|
};
|
|
645
705
|
/**
|
|
646
706
|
* An object containing protocol types.
|
|
@@ -849,5 +909,5 @@ const SubscriptionChannelIds = {
|
|
|
849
909
|
MQTT: "mqtt",
|
|
850
910
|
};
|
|
851
911
|
|
|
852
|
-
export { APICallValidationErrorCodes, APIEndpoints, APIOperations, APIPathV1, AWSCredentialsErrorMessages, AssumeRoleErrorMessages, AuthErrorCodes, AuthSuccessMessages, AutomationStatusValues, AutomationSuccessMessages, CLAIM_CSR_MAX_CHUNKS, CLAIM_DEVICE_CSR_KEYS, CLAIM_DEVICE_MAC_KEYS, CLAIM_MAC_HEX_LENGTHS, CLAIM_MAC_SEPARATORS, CLAIM_MAX_FRAGMENT_SIZE, ClaimCapabilities, ClaimCapabilityPolicies, ClaimEndpoints, ClaimErrorCodes, ClaimProgressMessages, ConfigErrorCodes, DEFAULT_REST_API_VERSION, ESPProvProgressMessages, ESPRMNeoErrorCodes, ESPRMNeoStorageKeys, ESPServiceParamType, ESPServiceType, Endpoint, ErrorLabels, GroupSuccessMessages, GroupUserAliases, HTTPMethods, IntegrationSuccessMessages, NodeSuccessMessages, NodeWarnMessages, ProtocolType, ProvErrorCodes, ProvisionType, SDK_VERSION, ScheduleErrorMessages, ScheduleSuccessMessages, ServiceType, SharingSuccessMessages, StatusMessage, StorageAdapterErrorCodes, StorageKeys, SubscriptionChannelIds, TokenErrorCodes, TriggerErrorMessages, TriggerSuccessMessages, ValidationErrorCodes };
|
|
912
|
+
export { APICallValidationErrorCodes, APIEndpoints, APIOperations, APIPathV1, AWSCredentialsErrorMessages, AssumeRoleErrorMessages, AuthErrorCodes, AuthSuccessMessages, AutomationStatusValues, AutomationSuccessMessages, CLAIM_CSR_MAX_CHUNKS, CLAIM_DEVICE_CSR_KEYS, CLAIM_DEVICE_MAC_KEYS, CLAIM_MAC_HEX_LENGTHS, CLAIM_MAC_SEPARATORS, CLAIM_MAX_FRAGMENT_SIZE, ClaimCapabilities, ClaimCapabilityPolicies, ClaimEndpoints, ClaimErrorCodes, ClaimProgressMessages, ConfigErrorCodes, DEFAULT_REST_API_VERSION, ESPProvProgressMessages, ESPRMNeoErrorCodes, ESPRMNeoStorageKeys, ESPServiceParamType, ESPServiceType, Endpoint, ErrorLabels, GroupSuccessMessages, GroupUserAliases, HTTPMethods, IntegrationSuccessMessages, NodeSuccessMessages, NodeWarnMessages, ProtocolType, ProvErrorCodes, ProvisionType, RMAKER_LOCAL_CTRL_FRAGMENT_SIZE, RMAKER_LOCAL_CTRL_VERSION_KEY, RMakerLocalCtrlCapability, RMakerLocalCtrlEndpoint, RMakerLocalCtrlSetParamsStatus, RMakerLocalCtrlTxtKey, SDK_VERSION, ScheduleErrorMessages, ScheduleSuccessMessages, ServiceType, SharingSuccessMessages, StatusMessage, StorageAdapterErrorCodes, StorageKeys, SubscriptionChannelIds, TokenErrorCodes, TriggerErrorMessages, TriggerSuccessMessages, ValidationErrorCodes };
|
|
853
913
|
//# sourceMappingURL=constants.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"constants.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,26 +1,70 @@
|
|
|
1
1
|
import { ESPDiscoveryManager } from '../services/ESPTransport/ESPDiscovery/ESPDiscoveryManager.js';
|
|
2
2
|
import { subscribeNodeUpdates } from '../services/NodeUpdatesBus.js';
|
|
3
|
-
import { ESPTransportMode } from '../types/transport.js';
|
|
3
|
+
import { ESPLocalControlProtocol, ESPTransportMode } from '../types/transport.js';
|
|
4
|
+
import { RMakerLocalCtrlCapability, RMakerLocalCtrlTxtKey } from './constants.js';
|
|
4
5
|
|
|
5
6
|
/*
|
|
6
7
|
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
|
7
8
|
*
|
|
8
9
|
* SPDX-License-Identifier: Apache-2.0
|
|
9
10
|
*/
|
|
10
|
-
/**
|
|
11
|
+
/**
|
|
12
|
+
* Splits the mDNS `cap` TXT record (`"local_ctrl,ch_resp"`) into tokens.
|
|
13
|
+
* Returns `undefined` when the record is absent, which older firmware omits.
|
|
14
|
+
*/
|
|
15
|
+
function parseCapabilities(txt) {
|
|
16
|
+
const raw = txt?.[RMakerLocalCtrlTxtKey.CAP];
|
|
17
|
+
if (typeof raw !== "string")
|
|
18
|
+
return undefined;
|
|
19
|
+
const capabilities = raw
|
|
20
|
+
.split(",")
|
|
21
|
+
.map((capability) => capability.trim())
|
|
22
|
+
.filter(Boolean);
|
|
23
|
+
return capabilities.length ? capabilities : undefined;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Maps a default local-discovery hit into the client-facing payload shape.
|
|
27
|
+
*
|
|
28
|
+
* The `_esp_rmaker_ctrl._tcp` instance is also advertised by nodes that
|
|
29
|
+
* only serve challenge-response (on-network user-node association). Those are
|
|
30
|
+
* not reachable for param control, so a hit whose `cap` TXT record excludes
|
|
31
|
+
* `local_ctrl` maps to `undefined` and is dropped rather than registered as a
|
|
32
|
+
* local transport. A hit with no `cap` record is treated as control-capable.
|
|
33
|
+
*
|
|
34
|
+
* @param info - Raw adapter result (`nodeId`, `baseUrl`, and `txt` when the
|
|
35
|
+
* platform resolved TXT records).
|
|
36
|
+
* @returns The payload to deliver, or `undefined` to skip this hit.
|
|
37
|
+
*/
|
|
11
38
|
function toDiscoveredNodeData(info) {
|
|
39
|
+
const capabilities = parseCapabilities(info.txt);
|
|
40
|
+
if (capabilities &&
|
|
41
|
+
!capabilities.includes(RMakerLocalCtrlCapability.LOCAL_CTRL)) {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
12
44
|
return {
|
|
13
45
|
nodeId: info.nodeId,
|
|
14
46
|
transportDetails: {
|
|
15
47
|
type: ESPTransportMode.local,
|
|
16
|
-
metadata: {
|
|
48
|
+
metadata: {
|
|
49
|
+
baseUrl: info.baseUrl,
|
|
50
|
+
protocol: ESPLocalControlProtocol.rmakerLocalCtrl,
|
|
51
|
+
...(capabilities && { capabilities }),
|
|
52
|
+
},
|
|
17
53
|
},
|
|
18
54
|
};
|
|
19
55
|
}
|
|
20
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* Starts LAN discovery; each hit is mapped then passed to `onDiscovered`.
|
|
58
|
+
* Hits that are not control-capable (see {@link toDiscoveredNodeData}) are
|
|
59
|
+
* skipped.
|
|
60
|
+
*/
|
|
21
61
|
function startLocalDiscovery(onDiscovered) {
|
|
22
62
|
const manager = new ESPDiscoveryManager();
|
|
23
|
-
manager.startDiscovery((info) =>
|
|
63
|
+
manager.startDiscovery((info) => {
|
|
64
|
+
const data = toDiscoveredNodeData(info);
|
|
65
|
+
if (data)
|
|
66
|
+
onDiscovered(data);
|
|
67
|
+
});
|
|
24
68
|
return { stop: () => manager.stopDiscovery() };
|
|
25
69
|
}
|
|
26
70
|
/** Forwards process-wide node param updates to `onUpdate`. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eventSubscriptionUtils.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"eventSubscriptionUtils.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -115,7 +115,7 @@ export declare class ESPRMNeoBase {
|
|
|
115
115
|
static getProvisionAdapter(): ESPProvisionAdapterInterface | undefined;
|
|
116
116
|
/**
|
|
117
117
|
* Sets the local control adapter used to talk to nodes over the LAN via
|
|
118
|
-
* the `
|
|
118
|
+
* the `rmaker_local_ctrl` protocol.
|
|
119
119
|
*
|
|
120
120
|
* @param adapter - Adapter implementing {@link ESPLocalControlAdapterInterface}.
|
|
121
121
|
* @throws {Error} If the SDK is not initialized or the adapter is invalid.
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codec for the `rmaker_local_ctrl` endpoint protocol, mirroring the firmware's
|
|
3
|
+
* `local_ctrl.proto` schema.
|
|
4
|
+
*
|
|
5
|
+
* Hand-rolled like {@link ClaimingProtoHelper} rather than generated: the
|
|
6
|
+
* schema is small, and generated `google-protobuf` modules cannot be pulled
|
|
7
|
+
* into a downstream Metro/RN bundle (see the note in `utils/export.ts`).
|
|
8
|
+
*
|
|
9
|
+
* Field numbers are the wire contract with deployed firmware — treat them as
|
|
10
|
+
* frozen:
|
|
11
|
+
* - `RMakerLocalCtrlPayload`: 1 = msg (varint), 10 = cmdGetData, 11 = respGetData
|
|
12
|
+
* - `CmdGetData`: 1 = DataType (varint), 2 = Offset (varint),
|
|
13
|
+
* 3 = Timestamp (varint), 4 = HasTimestamp (varint)
|
|
14
|
+
* - `RespGetData`: 1 = Status (varint), 2 = Buf
|
|
15
|
+
* - `PayloadBuf`: 1 = Offset (varint), 2 = Payload (bytes), 3 = TotalLen (varint)
|
|
16
|
+
*
|
|
17
|
+
* `Timestamp` / `HasTimestamp` are reserved for a future signed-response
|
|
18
|
+
* extension and are ignored by current firmware, so the encoder omits them.
|
|
19
|
+
*
|
|
20
|
+
* Only `get_params` / `get_config` use this schema; `set_params` carries raw
|
|
21
|
+
* JSON on the wire.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Status returned by the device for a data read.
|
|
25
|
+
*/
|
|
26
|
+
export declare enum RMakerLocalCtrlStatus {
|
|
27
|
+
Success = 0,
|
|
28
|
+
Fail = 1,
|
|
29
|
+
InvalidParam = 2,
|
|
30
|
+
NoMemory = 3
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Selects which document a read targets.
|
|
34
|
+
*/
|
|
35
|
+
export declare enum RMakerLocalCtrlDataType {
|
|
36
|
+
/** The node's params JSON, as served by `get_params`. */
|
|
37
|
+
TypeParams = 0,
|
|
38
|
+
/** The node's config JSON, as served by `get_config`. */
|
|
39
|
+
TypeConfig = 1
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Message type discriminator carried on `RMakerLocalCtrlPayload.msg`.
|
|
43
|
+
*/
|
|
44
|
+
export declare enum RMakerLocalCtrlMsgType {
|
|
45
|
+
TypeCmdGetData = 0,
|
|
46
|
+
TypeRespGetData = 1
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* One fragment of a larger document.
|
|
50
|
+
*/
|
|
51
|
+
export interface PayloadBuf {
|
|
52
|
+
/** Byte offset of this fragment within the document. */
|
|
53
|
+
offset: number;
|
|
54
|
+
/** Fragment bytes (up to 200 per response). */
|
|
55
|
+
payload: Uint8Array;
|
|
56
|
+
/** Full document length in bytes. */
|
|
57
|
+
totalLen: number;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Device response to a data read.
|
|
61
|
+
*/
|
|
62
|
+
export interface RespGetData {
|
|
63
|
+
/** Read status. */
|
|
64
|
+
status: RMakerLocalCtrlStatus;
|
|
65
|
+
/** Fragment carried by this response. */
|
|
66
|
+
buf?: PayloadBuf;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Envelope exchanged on the `get_params` / `get_config` endpoints.
|
|
70
|
+
*/
|
|
71
|
+
export interface RMakerLocalCtrlPayload {
|
|
72
|
+
/** Message type. */
|
|
73
|
+
msg: RMakerLocalCtrlMsgType;
|
|
74
|
+
/** Response payload (device → app). */
|
|
75
|
+
respGetData?: RespGetData;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Encoder/decoder for `rmaker_local_ctrl` frames.
|
|
79
|
+
*/
|
|
80
|
+
export declare class RMakerLocalCtrlProtoHelper {
|
|
81
|
+
/**
|
|
82
|
+
* Builds a `CmdGetData` request for one fragment.
|
|
83
|
+
*
|
|
84
|
+
* An `offset` of 0 makes the device (re)generate and cache the document;
|
|
85
|
+
* subsequent offsets are served from that cache.
|
|
86
|
+
*
|
|
87
|
+
* @param dataType - Document to read.
|
|
88
|
+
* @param offset - Byte offset to read from.
|
|
89
|
+
* @returns The serialized request.
|
|
90
|
+
*/
|
|
91
|
+
static createGetDataRequest(dataType: RMakerLocalCtrlDataType, offset: number): Uint8Array;
|
|
92
|
+
/**
|
|
93
|
+
* Parses a `RespGetData` frame from the device.
|
|
94
|
+
*
|
|
95
|
+
* @param data - Raw response bytes.
|
|
96
|
+
* @returns The parsed payload. Absent fields keep their proto3 defaults.
|
|
97
|
+
*/
|
|
98
|
+
static parseGetDataResponse(data: Uint8Array): RMakerLocalCtrlPayload;
|
|
99
|
+
/**
|
|
100
|
+
* Whether the device reported a successful read.
|
|
101
|
+
*
|
|
102
|
+
* @param response - Parsed response.
|
|
103
|
+
*/
|
|
104
|
+
static isSuccess(response: RMakerLocalCtrlPayload): boolean;
|
|
105
|
+
/**
|
|
106
|
+
* Returns the device's status as its enum name, for diagnostics.
|
|
107
|
+
*
|
|
108
|
+
* @param response - Parsed response.
|
|
109
|
+
* @returns The status name, or `"Unknown"` when absent.
|
|
110
|
+
*/
|
|
111
|
+
static getStatus(response: RMakerLocalCtrlPayload): string;
|
|
112
|
+
/**
|
|
113
|
+
* Offset the device answered with, which must match the requested offset.
|
|
114
|
+
*
|
|
115
|
+
* @param response - Parsed response.
|
|
116
|
+
*/
|
|
117
|
+
static getOffset(response: RMakerLocalCtrlPayload): number;
|
|
118
|
+
/**
|
|
119
|
+
* Full document length reported by the device.
|
|
120
|
+
*
|
|
121
|
+
* @param response - Parsed response.
|
|
122
|
+
*/
|
|
123
|
+
static getTotalLen(response: RMakerLocalCtrlPayload): number;
|
|
124
|
+
/**
|
|
125
|
+
* Fragment bytes carried by the response.
|
|
126
|
+
*
|
|
127
|
+
* @param response - Parsed response.
|
|
128
|
+
*/
|
|
129
|
+
static getPayload(response: RMakerLocalCtrlPayload): Uint8Array;
|
|
130
|
+
private static concat;
|
|
131
|
+
private static encodeVarint;
|
|
132
|
+
private static readVarint;
|
|
133
|
+
/** Advances past a field this codec does not read. */
|
|
134
|
+
private static skipField;
|
|
135
|
+
private static parseRespGetData;
|
|
136
|
+
private static parsePayloadBuf;
|
|
137
|
+
}
|
|
@@ -4,9 +4,10 @@ import { DiscoveryParamsInterface, ESPDiscoveryCallback } from "../../../types/d
|
|
|
4
4
|
* adapter (see {@link ESPRMNeoBase.setLocalDiscoveryAdapter}).
|
|
5
5
|
*
|
|
6
6
|
* - With no discovery config, the default local protocol is used
|
|
7
|
-
* (mDNS service `
|
|
8
|
-
*
|
|
9
|
-
*
|
|
7
|
+
* (mDNS service `_esp_rmaker_ctrl._tcp.` in the `local` domain — the
|
|
8
|
+
* service advertised by RainMaker Neo firmware).
|
|
9
|
+
* - A custom {@link DiscoveryParamsInterface} can be supplied to browse any
|
|
10
|
+
* other service type.
|
|
10
11
|
*/
|
|
11
12
|
declare class ESPDiscoveryManager {
|
|
12
13
|
/** Discovery parameters (service type / domain) passed to the adapter. */
|
|
@@ -2,37 +2,84 @@ import type { ESPRMNeoNode } from "../../ESPRMNeoNode";
|
|
|
2
2
|
import { ESPAPIResponse } from "../../types/output";
|
|
3
3
|
import { ESPTransportConfig, ESPTransportInterface } from "../../types/transport";
|
|
4
4
|
/**
|
|
5
|
-
*
|
|
6
|
-
* the app-supplied {@link ESPRMNeoBase.ESPLocalControlAdapter}
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* The built-in `local` transport, speaking the `rmaker_local_ctrl` endpoint
|
|
6
|
+
* protocol over the app-supplied {@link ESPRMNeoBase.ESPLocalControlAdapter}:
|
|
7
|
+
*
|
|
8
|
+
* - `set_params` carries the same raw JSON body as a cloud set-params call and
|
|
9
|
+
* answers `{"status":"success"}` / `{"status":"fail","description":…}`.
|
|
10
|
+
* - `get_params` / `get_config` exchange protobuf `CmdGetData`/`RespGetData` and
|
|
11
|
+
* are fragmented — the client pulls fixed-size chunks by offset until
|
|
12
|
+
* `TotalLen` is covered.
|
|
13
|
+
*
|
|
14
|
+
* Connection metadata (`baseUrl`, `securityType`, `pop`, and `username` for
|
|
15
|
+
* sec2) is supplied via the transport config by {@link
|
|
16
|
+
* delegatedTransportHandler}; security 0 is not offered by this protocol.
|
|
10
17
|
*/
|
|
11
18
|
declare class ESPLocalControlTransport implements ESPTransportInterface {
|
|
12
|
-
private payload;
|
|
13
19
|
metadata: Record<string, any>;
|
|
14
|
-
propertyInfo: Record<string, any>;
|
|
15
20
|
constructor(transportConfig: ESPTransportConfig);
|
|
16
21
|
private get adapter();
|
|
22
|
+
private ensureConnected;
|
|
17
23
|
/**
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
24
|
+
* Applies params over `set_params`.
|
|
25
|
+
*
|
|
26
|
+
* @param payload - `{ node_id, payload }`, where `payload` is the
|
|
27
|
+
* `{ <deviceOrServiceName>: { <paramName>: value } }` map to write.
|
|
28
|
+
* @throws {Error} When the device reports a non-success status.
|
|
21
29
|
*/
|
|
22
|
-
private connectWithRetry;
|
|
23
|
-
private ensureConnected;
|
|
24
30
|
setParam(payload: Record<string, any>, _nodeRef?: ESPRMNeoNode): Promise<ESPAPIResponse>;
|
|
31
|
+
/**
|
|
32
|
+
* Reads the node's full params document over `get_params`.
|
|
33
|
+
*
|
|
34
|
+
* @param payload - `{ node_id }` identifying the node to read.
|
|
35
|
+
* @returns The params JSON, keyed by device/service name.
|
|
36
|
+
*/
|
|
25
37
|
getParams(payload: Record<string, any>, _nodeRef?: ESPRMNeoNode): Promise<Record<string, any>>;
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
/**
|
|
39
|
+
* Reads the node's config document over `get_config`. Not part of
|
|
40
|
+
* {@link ESPTransportInterface} — the node config normally comes from the
|
|
41
|
+
* cloud; this serves LAN-only flows.
|
|
42
|
+
*
|
|
43
|
+
* @param nodeId - Node to read from.
|
|
44
|
+
* @returns The node config JSON.
|
|
45
|
+
*/
|
|
46
|
+
getConfig(nodeId: string): Promise<Record<string, any>>;
|
|
47
|
+
/**
|
|
48
|
+
* Validates a `set_params` raw-JSON response.
|
|
49
|
+
*
|
|
50
|
+
* @throws {Error} When the body is unparseable or reports a failure.
|
|
51
|
+
*/
|
|
52
|
+
private assertSetParamsAccepted;
|
|
53
|
+
/**
|
|
54
|
+
* Pulls a fragmented document and parses it as JSON, serialized against every
|
|
55
|
+
* other fragmented read of the same node.
|
|
56
|
+
*
|
|
57
|
+
* The device holds **one global transfer cache**, not one per session: an
|
|
58
|
+
* offset-0 request regenerates it and it is freed after the last fragment. So
|
|
59
|
+
* a `getParams()` racing a `getConfig()` on the same node would clobber the
|
|
60
|
+
* other — the second offset-0 regenerates the cache mid-transfer, and the
|
|
61
|
+
* first read's next fragment comes back `Fail` (or, worse, carries bytes from
|
|
62
|
+
* the wrong document). The queue makes that interleaving impossible rather
|
|
63
|
+
* than detecting it after the fact.
|
|
64
|
+
*
|
|
65
|
+
* @param nodeId - Node to read from.
|
|
66
|
+
* @param dataType - Which document to read (params or config).
|
|
67
|
+
* @param endpoint - Endpoint serving that document.
|
|
68
|
+
* @throws {Error} When the device reports a failure, the response is
|
|
69
|
+
* malformed, or a fragment makes no forward progress.
|
|
70
|
+
*/
|
|
71
|
+
private readJsonDocument;
|
|
72
|
+
/** The client-pull loop itself; always reached via {@link readJsonDocument}. */
|
|
73
|
+
private pullJsonDocument;
|
|
74
|
+
private buildGetDataRequest;
|
|
75
|
+
/**
|
|
76
|
+
* Parses one `RespGetData` and checks it answers the requested offset.
|
|
77
|
+
*
|
|
78
|
+
* @param response - Base64 protobuf response from the adapter.
|
|
79
|
+
* @param requestedOffset - Offset asked for, used to detect a desynced pull.
|
|
80
|
+
*/
|
|
81
|
+
private processGetDataResponse;
|
|
82
|
+
/** Joins the pulled fragments and parses the result as JSON. */
|
|
83
|
+
private parseJsonFragments;
|
|
37
84
|
}
|
|
38
85
|
export { ESPLocalControlTransport };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { ESPLocalControlAdapterInterface, ESPLocalControlSessionOptions } from "../../types/localControl";
|
|
2
|
+
/**
|
|
3
|
+
* Returns the app-supplied local control adapter.
|
|
4
|
+
*
|
|
5
|
+
* @throws {Error} When no adapter was registered on {@link ESPRMNeoBase}.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getLocalControlAdapter(): ESPLocalControlAdapterInterface;
|
|
8
|
+
/**
|
|
9
|
+
* Ensures a usable local-control session for `nodeId`, connecting (with
|
|
10
|
+
* retries) when the adapter reports none.
|
|
11
|
+
*
|
|
12
|
+
* The adapter resolves on a successful handshake and rejects otherwise, so a
|
|
13
|
+
* resolved `connect` is treated as connected.
|
|
14
|
+
*
|
|
15
|
+
* @param adapter - Adapter to drive.
|
|
16
|
+
* @param nodeId - Node to connect to.
|
|
17
|
+
* @param metadata - Local transport metadata (`baseUrl`, `securityType`, `pop`,
|
|
18
|
+
* `username`).
|
|
19
|
+
* @param options - Session endpoints for the protocol in use; omitted for the
|
|
20
|
+
* adapter's built-in default paths.
|
|
21
|
+
* @param maxRetries - Connection attempts before failing.
|
|
22
|
+
* @throws {Error} When every connection attempt fails.
|
|
23
|
+
*/
|
|
24
|
+
export declare function ensureLocalControlSession(adapter: ESPLocalControlAdapterInterface, nodeId: string, metadata: Record<string, any>, options?: ESPLocalControlSessionOptions, maxRetries?: number): Promise<void>;
|
|
@@ -23,7 +23,7 @@ declare enum ESPRMNeoEventType {
|
|
|
23
23
|
* (e.g. mDNS service type and domain).
|
|
24
24
|
*/
|
|
25
25
|
interface DiscoveryParamsInterface {
|
|
26
|
-
/** Service type to browse for, e.g. `
|
|
26
|
+
/** Service type to browse for, e.g. `_esp_rmaker_ctrl._tcp.` */
|
|
27
27
|
serviceType: string;
|
|
28
28
|
/** Discovery domain, e.g. `local`. */
|
|
29
29
|
domain: string;
|
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-connection session details passed to {@link
|
|
3
|
+
* ESPLocalControlAdapterInterface.connect}. The protocomm handshake endpoint
|
|
4
|
+
* differs per local-control protocol, so the transport tells the native layer
|
|
5
|
+
* which paths to use instead of the adapter hardcoding them.
|
|
6
|
+
*
|
|
7
|
+
* Adapters built against an earlier SDK simply ignore the extra argument and
|
|
8
|
+
* keep using their built-in default paths.
|
|
9
|
+
*/
|
|
10
|
+
export interface ESPLocalControlSessionOptions {
|
|
11
|
+
/** Protocol tag, one of {@link ESPLocalControlProtocol}. */
|
|
12
|
+
protocol: string;
|
|
13
|
+
/** Protocomm session-security endpoint, e.g. `rmaker_local_ctrl/session`. */
|
|
14
|
+
sessionPath: string;
|
|
15
|
+
/** Version/service-info endpoint, e.g. `rmaker_local_ctrl/version`. */
|
|
16
|
+
versionPath: string;
|
|
17
|
+
/**
|
|
18
|
+
* Root key to read in the version response when probing the security scheme
|
|
19
|
+
* version, e.g. `rmaker_local_ctrl` for `{"rmaker_local_ctrl": {…}}`.
|
|
20
|
+
*/
|
|
21
|
+
versionKey: string;
|
|
22
|
+
}
|
|
1
23
|
/**
|
|
2
24
|
* Local control adapter interface for node communication over LAN.
|
|
3
25
|
*/
|
|
@@ -8,8 +30,11 @@ export interface ESPLocalControlAdapterInterface {
|
|
|
8
30
|
isConnected(nodeId: string): Promise<boolean>;
|
|
9
31
|
/**
|
|
10
32
|
* Connects to the node with local control parameters.
|
|
33
|
+
*
|
|
34
|
+
* @param options - Session endpoints for the protocol in use. Omitted only by
|
|
35
|
+
* callers that want the adapter's built-in default paths.
|
|
11
36
|
*/
|
|
12
|
-
connect(nodeId: string, baseUrl: string, securtiyType: number, pop?: string, username?: string): Promise<Record<string, unknown>>;
|
|
37
|
+
connect(nodeId: string, baseUrl: string, securtiyType: number, pop?: string, username?: string, options?: ESPLocalControlSessionOptions): Promise<Record<string, unknown>>;
|
|
13
38
|
/**
|
|
14
39
|
* Sends data to the specified path on the node.
|
|
15
40
|
*/
|