@sirena-lwm2m/coap 0.8.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 +17 -0
- package/README.md +78 -0
- package/dist/api/exchange-context.d.ts +34 -0
- package/dist/api/exchange-context.d.ts.map +1 -0
- package/dist/api/exchange-context.js +2 -0
- package/dist/api/exchange-context.js.map +1 -0
- package/dist/api/headers.d.ts +10 -0
- package/dist/api/headers.d.ts.map +1 -0
- package/dist/api/headers.js +69 -0
- package/dist/api/headers.js.map +1 -0
- package/dist/api/index.d.ts +5 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/index.js +4 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/request.d.ts +11 -0
- package/dist/api/request.d.ts.map +1 -0
- package/dist/api/request.js +49 -0
- package/dist/api/request.js.map +1 -0
- package/dist/api/response.d.ts +11 -0
- package/dist/api/response.d.ts.map +1 -0
- package/dist/api/response.js +19 -0
- package/dist/api/response.js.map +1 -0
- package/dist/blockwise/block1-assembler.d.ts +26 -0
- package/dist/blockwise/block1-assembler.d.ts.map +1 -0
- package/dist/blockwise/block1-assembler.js +94 -0
- package/dist/blockwise/block1-assembler.js.map +1 -0
- package/dist/blockwise/block2-chunker.d.ts +23 -0
- package/dist/blockwise/block2-chunker.d.ts.map +1 -0
- package/dist/blockwise/block2-chunker.js +99 -0
- package/dist/blockwise/block2-chunker.js.map +1 -0
- package/dist/blockwise/index.d.ts +8 -0
- package/dist/blockwise/index.d.ts.map +1 -0
- package/dist/blockwise/index.js +5 -0
- package/dist/blockwise/index.js.map +1 -0
- package/dist/blockwise/middleware.d.ts +7 -0
- package/dist/blockwise/middleware.d.ts.map +1 -0
- package/dist/blockwise/middleware.js +120 -0
- package/dist/blockwise/middleware.js.map +1 -0
- package/dist/blockwise/option.d.ts +12 -0
- package/dist/blockwise/option.d.ts.map +1 -0
- package/dist/blockwise/option.js +55 -0
- package/dist/blockwise/option.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/message/index.d.ts +21 -0
- package/dist/message/index.d.ts.map +1 -0
- package/dist/message/index.js +79 -0
- package/dist/message/index.js.map +1 -0
- package/dist/observability.d.ts +44 -0
- package/dist/observability.d.ts.map +1 -0
- package/dist/observability.js +71 -0
- package/dist/observability.js.map +1 -0
- package/dist/observe-notification.d.ts +21 -0
- package/dist/observe-notification.d.ts.map +1 -0
- package/dist/observe-notification.js +87 -0
- package/dist/observe-notification.js.map +1 -0
- package/dist/observe.d.ts +10 -0
- package/dist/observe.d.ts.map +1 -0
- package/dist/observe.js +3 -0
- package/dist/observe.js.map +1 -0
- package/dist/option-parser/index.d.ts +30 -0
- package/dist/option-parser/index.d.ts.map +1 -0
- package/dist/option-parser/index.js +125 -0
- package/dist/option-parser/index.js.map +1 -0
- package/dist/router/app.d.ts +8 -0
- package/dist/router/app.d.ts.map +1 -0
- package/dist/router/app.js +25 -0
- package/dist/router/app.js.map +1 -0
- package/dist/router/content-format.d.ts +7 -0
- package/dist/router/content-format.d.ts.map +1 -0
- package/dist/router/content-format.js +23 -0
- package/dist/router/content-format.js.map +1 -0
- package/dist/router/index.d.ts +9 -0
- package/dist/router/index.d.ts.map +1 -0
- package/dist/router/index.js +5 -0
- package/dist/router/index.js.map +1 -0
- package/dist/router/radix.d.ts +16 -0
- package/dist/router/radix.d.ts.map +1 -0
- package/dist/router/radix.js +69 -0
- package/dist/router/radix.js.map +1 -0
- package/dist/router/router.d.ts +38 -0
- package/dist/router/router.d.ts.map +1 -0
- package/dist/router/router.js +111 -0
- package/dist/router/router.js.map +1 -0
- package/dist/router.d.ts +2 -0
- package/dist/router.d.ts.map +1 -0
- package/dist/router.js +2 -0
- package/dist/router.js.map +1 -0
- package/dist/security.d.ts +3 -0
- package/dist/security.d.ts.map +1 -0
- package/dist/security.js +2 -0
- package/dist/security.js.map +1 -0
- package/dist/store/index.d.ts +26 -0
- package/dist/store/index.d.ts.map +1 -0
- package/dist/store/index.js +68 -0
- package/dist/store/index.js.map +1 -0
- package/dist/store/sqlite-store.d.ts +10 -0
- package/dist/store/sqlite-store.d.ts.map +1 -0
- package/dist/store/sqlite-store.js +75 -0
- package/dist/store/sqlite-store.js.map +1 -0
- package/dist/store.d.ts +5 -0
- package/dist/store.d.ts.map +1 -0
- package/dist/store.js +3 -0
- package/dist/store.js.map +1 -0
- package/dist/transport/dtls.d.ts +38 -0
- package/dist/transport/dtls.d.ts.map +1 -0
- package/dist/transport/dtls.js +151 -0
- package/dist/transport/dtls.js.map +1 -0
- package/dist/transport/events.d.ts +34 -0
- package/dist/transport/events.d.ts.map +1 -0
- package/dist/transport/events.js +2 -0
- package/dist/transport/events.js.map +1 -0
- package/dist/transport/index.d.ts +10 -0
- package/dist/transport/index.d.ts.map +1 -0
- package/dist/transport/index.js +5 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/tcp-connection.d.ts +18 -0
- package/dist/transport/tcp-connection.d.ts.map +1 -0
- package/dist/transport/tcp-connection.js +72 -0
- package/dist/transport/tcp-connection.js.map +1 -0
- package/dist/transport/tcp-frame.d.ts +17 -0
- package/dist/transport/tcp-frame.d.ts.map +1 -0
- package/dist/transport/tcp-frame.js +112 -0
- package/dist/transport/tcp-frame.js.map +1 -0
- package/dist/transport/tcp-stream.d.ts +21 -0
- package/dist/transport/tcp-stream.d.ts.map +1 -0
- package/dist/transport/tcp-stream.js +52 -0
- package/dist/transport/tcp-stream.js.map +1 -0
- package/dist/transport/udp.d.ts +97 -0
- package/dist/transport/udp.d.ts.map +1 -0
- package/dist/transport/udp.js +994 -0
- package/dist/transport/udp.js.map +1 -0
- package/dist/transport.d.ts +3 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +2 -0
- package/dist/transport.js.map +1 -0
- package/docs/api-reference.md +536 -0
- package/docs/blockwise.md +117 -0
- package/docs/observability.md +206 -0
- package/docs/observe.md +203 -0
- package/docs/releasing.md +106 -0
- package/docs/router.md +170 -0
- package/docs/store.md +212 -0
- package/docs/tcp-transport.md +89 -0
- package/docs/udp-transport.md +81 -0
- package/examples/slice-1.ts +12 -0
- package/examples/slice-2.ts +96 -0
- package/examples/slice-3-psk.ts +70 -0
- package/examples/slice-3-x509.ts +85 -0
- package/examples/slice-4.ts +45 -0
- package/examples/slice-5-firmware.ts +207 -0
- package/examples/slice-6-temperature.ts +163 -0
- package/examples/slice-7-file-store.ts +92 -0
- package/examples/slice-7-otel.ts +123 -0
- package/package.json +73 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
// Slice 7b — OpenTelemetry metrics example
|
|
2
|
+
//
|
|
3
|
+
// Demonstrates a CoAP server with OTel metrics wired to a console exporter.
|
|
4
|
+
// The metrics module uses lazy import() so there is zero cost when
|
|
5
|
+
// @opentelemetry/api is not installed.
|
|
6
|
+
//
|
|
7
|
+
// To run with real OTel metrics you need the SDK packages:
|
|
8
|
+
// npm install @opentelemetry/api @opentelemetry/sdk-metrics
|
|
9
|
+
//
|
|
10
|
+
// Run without SDK (no-op metrics, zero allocation):
|
|
11
|
+
// node --experimental-strip-types examples/slice-7-otel.ts
|
|
12
|
+
//
|
|
13
|
+
// Run with SDK (console exporter):
|
|
14
|
+
// OTEL_ENABLED=1 node --experimental-strip-types examples/slice-7-otel.ts
|
|
15
|
+
|
|
16
|
+
import dgram from 'node:dgram';
|
|
17
|
+
import { createServer, Response, encodeMessage, decodeMessage, stringToCode } from '@sirena-lwm2m/coap';
|
|
18
|
+
import { bindOtel, tryBindOtel } from '@sirena-lwm2m/coap/observability';
|
|
19
|
+
import type { CoapMetrics } from '@sirena-lwm2m/coap/observability';
|
|
20
|
+
|
|
21
|
+
// ── Metrics setup ─────────────────────────────────────────────────────────────
|
|
22
|
+
//
|
|
23
|
+
// tryBindOtel() lazy-imports @opentelemetry/api at runtime.
|
|
24
|
+
// If the package is absent it silently returns no-op instruments.
|
|
25
|
+
|
|
26
|
+
let metrics: CoapMetrics;
|
|
27
|
+
|
|
28
|
+
if (process.env.OTEL_ENABLED === '1') {
|
|
29
|
+
try {
|
|
30
|
+
// Attempt to wire up a real SDK with a console exporter.
|
|
31
|
+
// This block is only reached when OTEL_ENABLED=1 and the SDK is installed.
|
|
32
|
+
const { MeterProvider, PeriodicExportingMetricReader } = await import('@opentelemetry/sdk-metrics' as never as '@opentelemetry/sdk-metrics');
|
|
33
|
+
const { ConsoleMetricExporter } = await import('@opentelemetry/sdk-metrics' as never as '@opentelemetry/sdk-metrics');
|
|
34
|
+
|
|
35
|
+
const provider = new MeterProvider();
|
|
36
|
+
provider.addMetricReader(
|
|
37
|
+
new PeriodicExportingMetricReader({
|
|
38
|
+
exporter: new ConsoleMetricExporter(),
|
|
39
|
+
exportIntervalMillis: 2000,
|
|
40
|
+
}),
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const meter = provider.getMeter('@sirena-lwm2m/coap');
|
|
44
|
+
metrics = bindOtel(meter as never);
|
|
45
|
+
|
|
46
|
+
console.log('OTel metrics: SDK wired with console exporter (export every 2s)');
|
|
47
|
+
} catch {
|
|
48
|
+
console.warn('OTel SDK not installed — falling back to no-op metrics');
|
|
49
|
+
metrics = await tryBindOtel('@sirena-lwm2m/coap');
|
|
50
|
+
}
|
|
51
|
+
} else {
|
|
52
|
+
// Default path: lazy import falls back to no-ops when @opentelemetry/api absent
|
|
53
|
+
metrics = await tryBindOtel('@sirena-lwm2m/coap');
|
|
54
|
+
console.log('OTel metrics: no-op (set OTEL_ENABLED=1 to enable console exporter)');
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// ── Server ────────────────────────────────────────────────────────────────────
|
|
58
|
+
|
|
59
|
+
const server = createServer({
|
|
60
|
+
listen: ['coap://127.0.0.1:5691'],
|
|
61
|
+
metrics,
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
let requestCount = 0;
|
|
65
|
+
|
|
66
|
+
server.on('request', async (_req, ctx) => {
|
|
67
|
+
requestCount++;
|
|
68
|
+
console.log(`[server] request #${requestCount} from ${ctx.remote}`);
|
|
69
|
+
await ctx.respond(Response.ok(new TextEncoder().encode(`hello #${requestCount}`)));
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
server.on('exchange-error', (err) => {
|
|
73
|
+
console.error('[server] exchange-error:', err.message);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
await server.start();
|
|
77
|
+
console.log('Server started:', server.listenerSummary());
|
|
78
|
+
|
|
79
|
+
// ── Client: send same CON twice (dedup demo, verifies dedupHits counter) ──────
|
|
80
|
+
|
|
81
|
+
const sock = dgram.createSocket('udp4');
|
|
82
|
+
await new Promise<void>((resolve) => sock.bind(0, '127.0.0.1', resolve));
|
|
83
|
+
|
|
84
|
+
const TOKEN = new Uint8Array([0xca, 0xfe, 0xba, 0xbe]);
|
|
85
|
+
const MID = 0x4321;
|
|
86
|
+
|
|
87
|
+
const request = encodeMessage({
|
|
88
|
+
version: 1,
|
|
89
|
+
type: 'CON',
|
|
90
|
+
token: TOKEN,
|
|
91
|
+
code: stringToCode('0.01'), // GET
|
|
92
|
+
messageId: MID,
|
|
93
|
+
options: [],
|
|
94
|
+
payload: new Uint8Array(0),
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const responses: string[] = [];
|
|
98
|
+
sock.on('message', (msg) => {
|
|
99
|
+
const decoded = decodeMessage(msg);
|
|
100
|
+
responses.push(new TextDecoder().decode(decoded.payload));
|
|
101
|
+
console.log(`[client] received: ${responses[responses.length - 1]}`);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
// First transmission — should create a new exchange and increment requestRate
|
|
105
|
+
sock.send(request, 5691, '127.0.0.1');
|
|
106
|
+
console.log('[client] sent CON request (first)');
|
|
107
|
+
await new Promise(r => setTimeout(r, 60));
|
|
108
|
+
|
|
109
|
+
// Retransmission of same MID — server should dedup (increments dedupHits)
|
|
110
|
+
sock.send(request, 5691, '127.0.0.1');
|
|
111
|
+
console.log('[client] retransmitted same CON (should be deduped)');
|
|
112
|
+
await new Promise(r => setTimeout(r, 60));
|
|
113
|
+
|
|
114
|
+
console.log(`\nResult: ${requestCount} handler invocation(s) for 2 transmissions`);
|
|
115
|
+
console.log(requestCount === 1
|
|
116
|
+
? '✓ CON retransmission correctly deduped'
|
|
117
|
+
: '✗ Dedup failed — handler was invoked more than once');
|
|
118
|
+
|
|
119
|
+
// ── Cleanup ───────────────────────────────────────────────────────────────────
|
|
120
|
+
|
|
121
|
+
sock.close();
|
|
122
|
+
await server.stop();
|
|
123
|
+
console.log('\nDone.');
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@sirena-lwm2m/coap",
|
|
3
|
+
"version": "0.8.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=24"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "tsc",
|
|
11
|
+
"test": "node --experimental-strip-types --test 'test/*.test.ts' 'test/eclipse-td/**/*.test.ts' 'test/wire/**/*.test.ts'",
|
|
12
|
+
"test:interop": "node --experimental-strip-types --test 'test/interop/**/*.test.ts'",
|
|
13
|
+
"test:mutate": "node --experimental-strip-types scripts/mutation-runner.ts",
|
|
14
|
+
"prepublishOnly": "npm run build"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"docs",
|
|
19
|
+
"examples",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"exports": {
|
|
23
|
+
".": {
|
|
24
|
+
"import": "./dist/index.js",
|
|
25
|
+
"types": "./dist/index.d.ts"
|
|
26
|
+
},
|
|
27
|
+
"./router": {
|
|
28
|
+
"import": "./dist/router.js",
|
|
29
|
+
"types": "./dist/router.d.ts"
|
|
30
|
+
},
|
|
31
|
+
"./store": {
|
|
32
|
+
"import": "./dist/store.js",
|
|
33
|
+
"types": "./dist/store.d.ts"
|
|
34
|
+
},
|
|
35
|
+
"./transport": {
|
|
36
|
+
"import": "./dist/transport.js",
|
|
37
|
+
"types": "./dist/transport.d.ts"
|
|
38
|
+
},
|
|
39
|
+
"./security": {
|
|
40
|
+
"import": "./dist/security.js",
|
|
41
|
+
"types": "./dist/security.d.ts"
|
|
42
|
+
},
|
|
43
|
+
"./observability": {
|
|
44
|
+
"import": "./dist/observability.js",
|
|
45
|
+
"types": "./dist/observability.d.ts"
|
|
46
|
+
},
|
|
47
|
+
"./blockwise": {
|
|
48
|
+
"import": "./dist/blockwise/index.js",
|
|
49
|
+
"types": "./dist/blockwise/index.d.ts"
|
|
50
|
+
},
|
|
51
|
+
"./internal/*": null
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"@opentelemetry/api": "*",
|
|
55
|
+
"better-sqlite3": "*"
|
|
56
|
+
},
|
|
57
|
+
"peerDependenciesMeta": {
|
|
58
|
+
"better-sqlite3": {
|
|
59
|
+
"optional": true
|
|
60
|
+
},
|
|
61
|
+
"@opentelemetry/api": {
|
|
62
|
+
"optional": true
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
"devDependencies": {
|
|
66
|
+
"@types/better-sqlite3": "^7.6.13",
|
|
67
|
+
"@types/node": "^25.9.1",
|
|
68
|
+
"better-sqlite3": "^12.10.0",
|
|
69
|
+
"fast-check": "^4.8.0",
|
|
70
|
+
"testcontainers": "^12.0.1",
|
|
71
|
+
"typescript": "^6.0.3"
|
|
72
|
+
}
|
|
73
|
+
}
|