@totemsdk/edge-coap 0.1.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/LICENSE +21 -0
- package/README.md +84 -0
- package/dist/gateway.d.ts +22 -0
- package/dist/gateway.js +105 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +7 -0
- package/dist/sensor-bridge.d.ts +26 -0
- package/dist/sensor-bridge.js +46 -0
- package/dist/transport.d.ts +47 -0
- package/dist/transport.js +9 -0
- package/package.json +43 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Totem SDK Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# @totemsdk/edge-coap
|
|
2
|
+
|
|
3
|
+
Edge runtime adapter for CoAP — constrained devices, RFC 7252, UDP transport.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @totemsdk/edge-coap
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Design
|
|
12
|
+
|
|
13
|
+
This package does **not** import `dgram`, `coap`, or any UDP library. All network behaviour is injected via `CoapTransportPort`. The package handles CoAP framing (CON/NON/ACK/RST, options, tokens) and request/response matching.
|
|
14
|
+
|
|
15
|
+
## Quick start
|
|
16
|
+
|
|
17
|
+
```ts
|
|
18
|
+
import { createEdgeRuntime, createEdgeDevice, createCapabilitySet } from '@totemsdk/edge';
|
|
19
|
+
import { createCoapGateway, createCoapSensorBridge } from '@totemsdk/edge-coap';
|
|
20
|
+
import type { CoapTransportPort } from '@totemsdk/edge-coap';
|
|
21
|
+
|
|
22
|
+
// 1. Implement CoapTransportPort
|
|
23
|
+
const transport: CoapTransportPort = {
|
|
24
|
+
async bind(port) { /* bind UDP socket */ },
|
|
25
|
+
async close() { /* close socket */ },
|
|
26
|
+
async send(host, port, message) { /* send UDP datagram */ },
|
|
27
|
+
onMessage(handler) { /* register inbound handler */ return () => {}; },
|
|
28
|
+
onError(handler) { /* register error handler */ return () => {}; },
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// 2. Wire into Edge runtime
|
|
32
|
+
const runtime = createEdgeRuntime({
|
|
33
|
+
deviceId: 'coap-gateway-01',
|
|
34
|
+
capabilities: createCapabilitySet(['transport:coap', 'proof:create']),
|
|
35
|
+
ports: { /* proof port */ },
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// 3. Create gateway
|
|
39
|
+
const gateway = createCoapGateway({ runtime, transport, localPort: 5683 });
|
|
40
|
+
await gateway.start();
|
|
41
|
+
|
|
42
|
+
// 4. GET a resource
|
|
43
|
+
const result = await gateway.get(['sensors', 'temperature'], '192.168.1.100', 5683);
|
|
44
|
+
console.log(result.data?.payload);
|
|
45
|
+
|
|
46
|
+
// 5. POST to a resource
|
|
47
|
+
await gateway.post(['actuators', 'valve'], new TextEncoder().encode('open'), '192.168.1.101', 5683);
|
|
48
|
+
|
|
49
|
+
// 6. Or use the sensor bridge for automated polling
|
|
50
|
+
const bridge = createCoapSensorBridge({
|
|
51
|
+
runtime,
|
|
52
|
+
transport,
|
|
53
|
+
gateway,
|
|
54
|
+
bindings: [
|
|
55
|
+
{ sensorId: 'temp-1', path: ['sensors', 'temperature'], host: '192.168.1.100', port: 5683, intervalMs: 5000 },
|
|
56
|
+
],
|
|
57
|
+
});
|
|
58
|
+
await bridge.start();
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Transport port
|
|
62
|
+
|
|
63
|
+
| Method | Description |
|
|
64
|
+
|--------|-------------|
|
|
65
|
+
| `bind(port)` | Bind UDP socket to local port |
|
|
66
|
+
| `close()` | Close the socket |
|
|
67
|
+
| `send(host, port, message)` | Send CoAP message bytes to remote endpoint |
|
|
68
|
+
| `onMessage(handler)` | Register handler for inbound messages with remote address |
|
|
69
|
+
| `onError(handler)` | Register handler for socket errors |
|
|
70
|
+
|
|
71
|
+
## Supported methods
|
|
72
|
+
|
|
73
|
+
| Method | Gateway method |
|
|
74
|
+
|--------|---------------|
|
|
75
|
+
| GET | `get(path, host, port)` |
|
|
76
|
+
| POST | `post(path, payload, host, port)` |
|
|
77
|
+
|
|
78
|
+
## Capabilities
|
|
79
|
+
|
|
80
|
+
- `transport:coap` — required for CoAP transport
|
|
81
|
+
|
|
82
|
+
## License
|
|
83
|
+
|
|
84
|
+
MIT
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CoAP Edge Gateway — wires a CoapTransportPort into an EdgeRuntime.
|
|
3
|
+
*/
|
|
4
|
+
import type { EdgeRuntime, EdgeOperationResult } from '@totemsdk/edge';
|
|
5
|
+
import type { CoapTransportPort } from './transport.js';
|
|
6
|
+
export interface CoapGatewayConfig {
|
|
7
|
+
runtime: EdgeRuntime;
|
|
8
|
+
transport: CoapTransportPort;
|
|
9
|
+
localPort: number;
|
|
10
|
+
}
|
|
11
|
+
export interface CoapGateway {
|
|
12
|
+
start(): Promise<void>;
|
|
13
|
+
stop(): Promise<void>;
|
|
14
|
+
readonly status: 'stopped' | 'running' | 'error';
|
|
15
|
+
get(path: string[], host: string, port: number): Promise<EdgeOperationResult<{
|
|
16
|
+
payload: Uint8Array;
|
|
17
|
+
}>>;
|
|
18
|
+
post(path: string[], payload: Uint8Array, host: string, port: number): Promise<EdgeOperationResult<{
|
|
19
|
+
payload: Uint8Array;
|
|
20
|
+
}>>;
|
|
21
|
+
}
|
|
22
|
+
export declare function createCoapGateway(config: CoapGatewayConfig): CoapGateway;
|
package/dist/gateway.js
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CoAP Edge Gateway — wires a CoapTransportPort into an EdgeRuntime.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createCoapGateway = createCoapGateway;
|
|
7
|
+
function createCoapGateway(config) {
|
|
8
|
+
let status = 'stopped';
|
|
9
|
+
let unsubMsg;
|
|
10
|
+
let unsubErr;
|
|
11
|
+
const pending = new Map();
|
|
12
|
+
let nextId = 0;
|
|
13
|
+
return {
|
|
14
|
+
get status() { return status; },
|
|
15
|
+
async start() {
|
|
16
|
+
if (status === 'running')
|
|
17
|
+
return;
|
|
18
|
+
await config.transport.bind(config.localPort);
|
|
19
|
+
unsubMsg = config.transport.onMessage((raw, remote) => {
|
|
20
|
+
try {
|
|
21
|
+
const msg = decodeCoap(raw, remote);
|
|
22
|
+
if (msg.type === 'ACK' && msg.token.length > 0) {
|
|
23
|
+
const tokenId = new DataView(msg.token.buffer, msg.token.byteOffset, 4).getUint32(0, false);
|
|
24
|
+
const p = pending.get(tokenId);
|
|
25
|
+
if (p) {
|
|
26
|
+
clearTimeout(p.timer);
|
|
27
|
+
pending.delete(tokenId);
|
|
28
|
+
p.resolve(msg.payload);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch { /* drop */ }
|
|
33
|
+
});
|
|
34
|
+
unsubErr = config.transport.onError(() => { status = 'error'; });
|
|
35
|
+
status = 'running';
|
|
36
|
+
},
|
|
37
|
+
async stop() {
|
|
38
|
+
unsubMsg?.();
|
|
39
|
+
unsubErr?.();
|
|
40
|
+
for (const [, p] of pending) {
|
|
41
|
+
clearTimeout(p.timer);
|
|
42
|
+
p.reject(new Error('Gateway stopped'));
|
|
43
|
+
}
|
|
44
|
+
pending.clear();
|
|
45
|
+
await config.transport.close();
|
|
46
|
+
status = 'stopped';
|
|
47
|
+
},
|
|
48
|
+
async get(path, host, port) {
|
|
49
|
+
return coapRequest(config.transport, 'GET', path, new Uint8Array(0), host, port, pending, nextId++);
|
|
50
|
+
},
|
|
51
|
+
async post(path, payload, host, port) {
|
|
52
|
+
return coapRequest(config.transport, 'POST', path, payload, host, port, pending, nextId++);
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
async function coapRequest(transport, method, path, payload, host, port, pending, messageId, timeoutMs = 10000) {
|
|
57
|
+
const token = new Uint8Array(4);
|
|
58
|
+
new DataView(token.buffer).setUint32(0, messageId, false);
|
|
59
|
+
const frame = encodeCoap({ type: 'CON', method, messageId, token, path, payload, remote: { host, port }, receivedAt: Date.now() });
|
|
60
|
+
await transport.send(host, port, frame);
|
|
61
|
+
return new Promise((resolve) => {
|
|
62
|
+
const timer = setTimeout(() => { pending.delete(messageId); resolve({ ok: false, error: 'CoAP request timed out' }); }, timeoutMs);
|
|
63
|
+
pending.set(messageId, { resolve: (v) => resolve({ ok: true, data: { payload: v } }), reject: (e) => resolve({ ok: false, error: e.message }), timer });
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
function encodeCoap(msg) {
|
|
67
|
+
const pathBytes = msg.path.map(p => [11, ...new TextEncoder().encode(p)]).flat();
|
|
68
|
+
const tokenLen = Math.min(msg.token.length, 8);
|
|
69
|
+
const header = new Uint8Array(4 + tokenLen);
|
|
70
|
+
header[0] = 0x40 | (msg.type === 'CON' ? 0 : msg.type === 'NON' ? 0x10 : msg.type === 'ACK' ? 0x20 : 0x30);
|
|
71
|
+
header[0] |= tokenLen;
|
|
72
|
+
header[1] = msg.method === 'GET' ? 1 : msg.method === 'POST' ? 2 : msg.method === 'PUT' ? 3 : 4;
|
|
73
|
+
new DataView(header.buffer).setUint16(2, msg.messageId, false);
|
|
74
|
+
header.set(msg.token.slice(0, tokenLen), 4);
|
|
75
|
+
const options = new Uint8Array(pathBytes.length + 1);
|
|
76
|
+
options.set(new Uint8Array(pathBytes), 0);
|
|
77
|
+
options[pathBytes.length] = 0xFF;
|
|
78
|
+
const result = new Uint8Array(header.length + options.length + msg.payload.length);
|
|
79
|
+
result.set(header);
|
|
80
|
+
result.set(options, header.length);
|
|
81
|
+
result.set(msg.payload, header.length + options.length);
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
function decodeCoap(raw, remote) {
|
|
85
|
+
const tokenLen = raw[0] & 0x0F;
|
|
86
|
+
const typeCode = (raw[0] >> 4) & 0x03;
|
|
87
|
+
const type = typeCode === 0 ? 'CON' : typeCode === 1 ? 'NON' : typeCode === 2 ? 'ACK' : 'RST';
|
|
88
|
+
const code = raw[1];
|
|
89
|
+
const messageId = new DataView(raw.buffer, raw.byteOffset + 2, 2).getUint16(0, false);
|
|
90
|
+
const token = raw.slice(4, 4 + tokenLen);
|
|
91
|
+
let offset = 4 + tokenLen;
|
|
92
|
+
const path = [];
|
|
93
|
+
while (offset < raw.length && raw[offset] !== 0xFF) {
|
|
94
|
+
const delta = (raw[offset] >> 4) & 0x0F;
|
|
95
|
+
const len = raw[offset] & 0x0F;
|
|
96
|
+
offset++;
|
|
97
|
+
if (delta === 11)
|
|
98
|
+
path.push(new TextDecoder().decode(raw.slice(offset, offset + len)));
|
|
99
|
+
offset += len;
|
|
100
|
+
}
|
|
101
|
+
if (offset < raw.length && raw[offset] === 0xFF)
|
|
102
|
+
offset++;
|
|
103
|
+
const payload = raw.slice(offset);
|
|
104
|
+
return { type, messageId, token, path, payload, remote, receivedAt: Date.now() };
|
|
105
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export type { CoapTransportPort, CoapMessage, CoapMessageType, CoapMethod } from './transport.js';
|
|
2
|
+
export { createCoapGateway } from './gateway.js';
|
|
3
|
+
export type { CoapGatewayConfig, CoapGateway } from './gateway.js';
|
|
4
|
+
export { createCoapSensorBridge } from './sensor-bridge.js';
|
|
5
|
+
export type { CoapSensorBinding, CoapSensorBridgeConfig, CoapSensorBridge } from './sensor-bridge.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.createCoapSensorBridge = exports.createCoapGateway = void 0;
|
|
4
|
+
var gateway_js_1 = require("./gateway.js");
|
|
5
|
+
Object.defineProperty(exports, "createCoapGateway", { enumerable: true, get: function () { return gateway_js_1.createCoapGateway; } });
|
|
6
|
+
var sensor_bridge_js_1 = require("./sensor-bridge.js");
|
|
7
|
+
Object.defineProperty(exports, "createCoapSensorBridge", { enumerable: true, get: function () { return sensor_bridge_js_1.createCoapSensorBridge; } });
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CoAP Sensor Bridge — maps CoAP resource observations to Edge proof inputs.
|
|
3
|
+
*/
|
|
4
|
+
import type { EdgeRuntime } from '@totemsdk/edge';
|
|
5
|
+
import type { CoapTransportPort } from './transport.js';
|
|
6
|
+
import type { CoapGateway } from './gateway.js';
|
|
7
|
+
export interface CoapSensorBinding {
|
|
8
|
+
sensorId: string;
|
|
9
|
+
path: string[];
|
|
10
|
+
host: string;
|
|
11
|
+
port: number;
|
|
12
|
+
intervalMs: number;
|
|
13
|
+
dataType?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface CoapSensorBridgeConfig {
|
|
16
|
+
runtime: EdgeRuntime;
|
|
17
|
+
transport: CoapTransportPort;
|
|
18
|
+
gateway?: CoapGateway;
|
|
19
|
+
bindings: CoapSensorBinding[];
|
|
20
|
+
}
|
|
21
|
+
export interface CoapSensorBridge {
|
|
22
|
+
start(): Promise<void>;
|
|
23
|
+
stop(): Promise<void>;
|
|
24
|
+
poll(): Promise<void>;
|
|
25
|
+
}
|
|
26
|
+
export declare function createCoapSensorBridge(config: CoapSensorBridgeConfig): CoapSensorBridge;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CoAP Sensor Bridge — maps CoAP resource observations to Edge proof inputs.
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createCoapSensorBridge = createCoapSensorBridge;
|
|
7
|
+
function createCoapSensorBridge(config) {
|
|
8
|
+
const timers = [];
|
|
9
|
+
let running = false;
|
|
10
|
+
async function pollBinding(binding) {
|
|
11
|
+
try {
|
|
12
|
+
const gw = config.gateway;
|
|
13
|
+
if (!gw)
|
|
14
|
+
return;
|
|
15
|
+
const result = await gw.get(binding.path, binding.host, binding.port);
|
|
16
|
+
if (result.ok && config.runtime.ports.proof) {
|
|
17
|
+
await config.runtime.ports.proof.createProof({
|
|
18
|
+
subject: `sensor:${binding.sensorId}`,
|
|
19
|
+
claims: [{
|
|
20
|
+
sensorId: binding.sensorId,
|
|
21
|
+
path: binding.path.join('/'),
|
|
22
|
+
dataType: binding.dataType ?? 'coap-observation',
|
|
23
|
+
payload: result.data?.payload,
|
|
24
|
+
timestamp: Date.now(),
|
|
25
|
+
}],
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
catch { /* non-fatal */ }
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
async start() {
|
|
33
|
+
if (running)
|
|
34
|
+
return;
|
|
35
|
+
for (const b of config.bindings) {
|
|
36
|
+
await pollBinding(b);
|
|
37
|
+
timers.push(setInterval(() => pollBinding(b), b.intervalMs));
|
|
38
|
+
}
|
|
39
|
+
running = true;
|
|
40
|
+
},
|
|
41
|
+
async stop() { for (const t of timers)
|
|
42
|
+
clearInterval(t); timers.length = 0; running = false; },
|
|
43
|
+
async poll() { for (const b of config.bindings)
|
|
44
|
+
await pollBinding(b); },
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CoAP transport port — injected by the caller.
|
|
3
|
+
*
|
|
4
|
+
* CoAP (RFC 7252) runs over UDP. The caller provides the socket.
|
|
5
|
+
* Messages are confirmable (CON), non-confirmable (NON),
|
|
6
|
+
* acknowledgement (ACK), or reset (RST).
|
|
7
|
+
*/
|
|
8
|
+
export interface CoapTransportPort {
|
|
9
|
+
/** Bind to a local port. */
|
|
10
|
+
bind(port: number): Promise<void>;
|
|
11
|
+
/** Close the socket. */
|
|
12
|
+
close(): Promise<void>;
|
|
13
|
+
/** Send a CoAP message to a remote endpoint. */
|
|
14
|
+
send(host: string, port: number, message: Uint8Array): Promise<void>;
|
|
15
|
+
/** Register a handler for inbound CoAP messages. */
|
|
16
|
+
onMessage(handler: (message: Uint8Array, remote: {
|
|
17
|
+
host: string;
|
|
18
|
+
port: number;
|
|
19
|
+
}) => void): () => void;
|
|
20
|
+
/** Register a handler for socket errors. */
|
|
21
|
+
onError(handler: (err: Error) => void): () => void;
|
|
22
|
+
}
|
|
23
|
+
export type CoapMessageType = 'CON' | 'NON' | 'ACK' | 'RST';
|
|
24
|
+
export type CoapMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
|
|
25
|
+
export interface CoapMessage {
|
|
26
|
+
/** Message type. */
|
|
27
|
+
type: CoapMessageType;
|
|
28
|
+
/** Request method (only for CON/NON requests). */
|
|
29
|
+
method?: CoapMethod;
|
|
30
|
+
/** Response code (only for ACK responses). */
|
|
31
|
+
responseCode?: string;
|
|
32
|
+
/** Message ID for deduplication. */
|
|
33
|
+
messageId: number;
|
|
34
|
+
/** Token for request/response matching. */
|
|
35
|
+
token: Uint8Array;
|
|
36
|
+
/** URI path (e.g. ["sensors", "temperature"]). */
|
|
37
|
+
path: string[];
|
|
38
|
+
/** Payload bytes. */
|
|
39
|
+
payload: Uint8Array;
|
|
40
|
+
/** Remote endpoint. */
|
|
41
|
+
remote: {
|
|
42
|
+
host: string;
|
|
43
|
+
port: number;
|
|
44
|
+
};
|
|
45
|
+
/** Timestamp of receipt. */
|
|
46
|
+
receivedAt: number;
|
|
47
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* CoAP transport port — injected by the caller.
|
|
4
|
+
*
|
|
5
|
+
* CoAP (RFC 7252) runs over UDP. The caller provides the socket.
|
|
6
|
+
* Messages are confirmable (CON), non-confirmable (NON),
|
|
7
|
+
* acknowledgement (ACK), or reset (RST).
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@totemsdk/edge-coap",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Edge runtime adapter for CoAP — constrained devices, RFC 7252, UDP transport",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"require": "./dist/index.js",
|
|
11
|
+
"import": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"prepare": "tsc",
|
|
17
|
+
"clean": "rm -rf dist",
|
|
18
|
+
"test": "jest --passWithNoTests"
|
|
19
|
+
},
|
|
20
|
+
"files": ["dist", "README.md", "LICENSE"],
|
|
21
|
+
"dependencies": {
|
|
22
|
+
"@totemsdk/edge": "^0.1.3"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@types/jest": "^30.0.0",
|
|
26
|
+
"@types/node": "^20.0.0",
|
|
27
|
+
"jest": "^30.4.2",
|
|
28
|
+
"ts-jest": "^29.0.0",
|
|
29
|
+
"typescript": "^7.0.2"
|
|
30
|
+
},
|
|
31
|
+
"engines": { "node": ">=18.0.0" },
|
|
32
|
+
"publishConfig": { "access": "public" },
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"author": "Totem SDK",
|
|
35
|
+
"homepage": "https://totem.ing",
|
|
36
|
+
"repository": {
|
|
37
|
+
"type": "git",
|
|
38
|
+
"url": "git+https://github.com/totem-sdk/totem-sdk.git",
|
|
39
|
+
"directory": "packages/totem-sdk/packages/edge-coap"
|
|
40
|
+
},
|
|
41
|
+
"keywords": ["totem", "totemsdk", "minima", "blockchain", "edge", "coap", "transport"],
|
|
42
|
+
"bugs": { "url": "https://github.com/totem-sdk/totem-sdk/issues" }
|
|
43
|
+
}
|