@mikrojs/native 0.6.0-pr-70.gd2fdc0d → 0.6.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/CMakeLists.txt +1 -1
- package/include/mikrojs/mikrojs.h +2 -1
- package/package.json +2 -2
- package/prebuilds/darwin-arm64/mikrojs.napi.node +0 -0
- package/prebuilds/linux-arm64/mikrojs.napi.node +0 -0
- package/prebuilds/linux-x64/mikrojs.napi.node +0 -0
- package/runtime/ble/ble.ts +4 -31
- package/runtime/internal.d.ts +4 -2
- package/runtime/observable/lazy.ts +39 -0
- package/runtime/observable/operators.ts +10 -6
- package/runtime/udp/udp.ts +1 -1
- package/runtime/wifi/types.ts +2 -2
- package/runtime/wifi/wifi.ts +6 -49
- package/src/mik_app_config.cpp +4 -1
package/CMakeLists.txt
CHANGED
|
@@ -81,7 +81,7 @@ endif()
|
|
|
81
81
|
include(cmake/mikrojs_bytecode.cmake)
|
|
82
82
|
mikrojs_generate_bytecode(
|
|
83
83
|
RUNTIME_DIR "${CMAKE_CURRENT_SOURCE_DIR}/runtime"
|
|
84
|
-
MODULES cbor env result schema fs http/helpers http/request i2c kv/nvs kv/rtc kv/shared neopixel observable observable/operators pin pwm reader sleep spi sntp stdio stream sys test uart udp wifi
|
|
84
|
+
MODULES cbor env result schema fs http/helpers http/request i2c kv/nvs kv/rtc kv/shared neopixel observable observable/lazy observable/operators pin pwm reader sleep spi sntp stdio stream sys test uart udp wifi
|
|
85
85
|
MODULE_PREFIX "mikrojs"
|
|
86
86
|
SYMBOL_PREFIX "mikrojs"
|
|
87
87
|
TARGET gen_bytecode
|
|
@@ -30,7 +30,8 @@ typedef struct MIKConfig {
|
|
|
30
30
|
uint32_t mem_reserved;
|
|
31
31
|
uint32_t fs_read_max; /* 0 = keep runtime default (65536) */
|
|
32
32
|
char entry_point[128];
|
|
33
|
-
char wifi_country[3];
|
|
33
|
+
char wifi_country[3]; /* Two-letter country code + NUL, e.g. "NO" */
|
|
34
|
+
char wifi_hostname[64]; /* DHCP hostname; empty = use mikrojs-<device-id> default */
|
|
34
35
|
} MIKConfig;
|
|
35
36
|
|
|
36
37
|
void MIK_DefaultConfig(MIKConfig* config);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikrojs/native",
|
|
3
|
-
"version": "0.6.0
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Mikro.js C++ runtime library and Node.js native addon",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"esp32",
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
"cmake-js": "^8.0.0",
|
|
79
79
|
"node-addon-api": "^8.7.0",
|
|
80
80
|
"node-gyp-build": "^4.8.4",
|
|
81
|
-
"@mikrojs/quickjs": "0.6.0
|
|
81
|
+
"@mikrojs/quickjs": "0.6.0"
|
|
82
82
|
},
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@swc/core": "^1.15.30",
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/runtime/ble/ble.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {lazyEvent} from 'mikrojs/observable/lazy'
|
|
2
2
|
import {err, ok} from 'mikrojs/result'
|
|
3
3
|
import {Ble as NativeBle} from 'native:ble'
|
|
4
4
|
|
|
5
|
-
import type {Subscriber} from '../observable/types.js'
|
|
6
5
|
import type {Result} from '../result/types.js'
|
|
7
6
|
import type {
|
|
8
7
|
AdvertiseHandle,
|
|
@@ -143,32 +142,6 @@ function normalizeServices(services: Service[]) {
|
|
|
143
142
|
|
|
144
143
|
const native = new NativeBle()
|
|
145
144
|
|
|
146
|
-
/* Lazy-attach: native.on runs only after the first JS subscriber and is
|
|
147
|
-
* removed when the last one leaves. Same pattern as wifi.ts; see the note
|
|
148
|
-
* there for the mbedTLS internal-RAM rationale. */
|
|
149
|
-
function lazyEvent<T>(eventName: string): Observable<T> {
|
|
150
|
-
const subscribers: Subscriber<T>[] = []
|
|
151
|
-
function handler(value: unknown): void {
|
|
152
|
-
const snapshot = subscribers.slice()
|
|
153
|
-
for (const s of snapshot) {
|
|
154
|
-
if (!s.closed) s.next(value as T)
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
return new Observable<T>((sub) => {
|
|
158
|
-
subscribers.push(sub)
|
|
159
|
-
if (subscribers.length === 1) {
|
|
160
|
-
native.on(eventName, handler)
|
|
161
|
-
}
|
|
162
|
-
sub.addTeardown(() => {
|
|
163
|
-
const i = subscribers.indexOf(sub)
|
|
164
|
-
if (i >= 0) subscribers.splice(i, 1)
|
|
165
|
-
if (subscribers.length === 0) {
|
|
166
|
-
native.off(eventName, handler)
|
|
167
|
-
}
|
|
168
|
-
})
|
|
169
|
-
})
|
|
170
|
-
}
|
|
171
|
-
|
|
172
145
|
const ble: Ble = {
|
|
173
146
|
get name(): string {
|
|
174
147
|
return native.getName()
|
|
@@ -248,9 +221,9 @@ const peripheral: Peripheral = {
|
|
|
248
221
|
return ok(handle)
|
|
249
222
|
},
|
|
250
223
|
|
|
251
|
-
onConnect: lazyEvent<ConnectionInfo>('connect'),
|
|
252
|
-
onDisconnect: lazyEvent<ConnectionInfo>('disconnect'),
|
|
253
|
-
onMtu: lazyEvent<MtuInfo>('mtu'),
|
|
224
|
+
onConnect: lazyEvent<ConnectionInfo>(native, 'connect'),
|
|
225
|
+
onDisconnect: lazyEvent<ConnectionInfo>(native, 'disconnect'),
|
|
226
|
+
onMtu: lazyEvent<MtuInfo>(native, 'mtu'),
|
|
254
227
|
}
|
|
255
228
|
|
|
256
229
|
export {ble, peripheral}
|
package/runtime/internal.d.ts
CHANGED
|
@@ -11,6 +11,10 @@ declare module 'mikrojs/kv/shared' {
|
|
|
11
11
|
export {KVError, makeCreateValue, type NativeKvFns} from './kv/shared.js'
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
+
declare module 'mikrojs/observable/lazy' {
|
|
15
|
+
export {lazyEvent} from './observable/lazy.js'
|
|
16
|
+
}
|
|
17
|
+
|
|
14
18
|
declare module 'native:cbor' {
|
|
15
19
|
import type {CborError} from '@mikrojs/native/runtime/cbor/types'
|
|
16
20
|
import type {Result} from 'mikrojs/result'
|
|
@@ -411,7 +415,6 @@ declare module 'native:wifi' {
|
|
|
411
415
|
// Network config
|
|
412
416
|
mac(): R<string>
|
|
413
417
|
getHostname(): string | undefined
|
|
414
|
-
setHostname(hostname: string): R<void>
|
|
415
418
|
getIpConfig(): R<{ip: string; netmask: string; gateway: string; dns: string} | undefined>
|
|
416
419
|
setIpConfig(opts: {
|
|
417
420
|
ip?: string
|
|
@@ -450,7 +453,6 @@ declare module 'native:wifi' {
|
|
|
450
453
|
getPowerSave(): string
|
|
451
454
|
setPowerSave(mode: string): R<void>
|
|
452
455
|
getCountry(): string | undefined
|
|
453
|
-
setCountry(cc: string): R<void>
|
|
454
456
|
}
|
|
455
457
|
|
|
456
458
|
export declare const Wifi: {
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {Observable} from 'native:observable'
|
|
2
|
+
|
|
3
|
+
import type {Subscriber} from './types.js'
|
|
4
|
+
|
|
5
|
+
/* Lazy-attach Observable: native.on is only called once a JS subscriber
|
|
6
|
+
* appears, and native.off runs when the last one unsubscribes. Code paths
|
|
7
|
+
* that import the host module (wifi/ble/...) but don't subscribe take the
|
|
8
|
+
* exact same internal-RAM path as before observables existed — important
|
|
9
|
+
* because mbedTLS handshake needs ~16 KB contiguous internal SRAM and each
|
|
10
|
+
* eager closure pinned at module load chips into that headroom. */
|
|
11
|
+
|
|
12
|
+
interface NativeEventSource {
|
|
13
|
+
on(event: string, listener: (...args: unknown[]) => void): void
|
|
14
|
+
off(event: string, listener: (...args: unknown[]) => void): void
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function lazyEvent<T>(source: NativeEventSource, eventName: string): Observable<T> {
|
|
18
|
+
const subscribers: Subscriber<T>[] = []
|
|
19
|
+
function handler(value: unknown): void {
|
|
20
|
+
/* Snapshot so unsubscribes during dispatch don't shift indices. */
|
|
21
|
+
const snapshot = subscribers.slice()
|
|
22
|
+
for (const s of snapshot) {
|
|
23
|
+
if (!s.closed) s.next(value as T)
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return new Observable<T>((sub) => {
|
|
27
|
+
subscribers.push(sub)
|
|
28
|
+
if (subscribers.length === 1) {
|
|
29
|
+
source.on(eventName, handler)
|
|
30
|
+
}
|
|
31
|
+
sub.addTeardown(() => {
|
|
32
|
+
const i = subscribers.indexOf(sub)
|
|
33
|
+
if (i >= 0) subscribers.splice(i, 1)
|
|
34
|
+
if (subscribers.length === 0) {
|
|
35
|
+
source.off(eventName, handler)
|
|
36
|
+
}
|
|
37
|
+
})
|
|
38
|
+
})
|
|
39
|
+
}
|
|
@@ -17,12 +17,16 @@
|
|
|
17
17
|
* See `.claude/plans/observable.md` for the full design.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
import {Observable as NativeObservable} from 'native:observable'
|
|
21
|
+
|
|
22
|
+
import type {Observable as ObservableT} from './types.js'
|
|
23
|
+
|
|
24
|
+
/* `native:observable` resolves only inside the runtime build; outside
|
|
25
|
+
* (twoslash, host typecheck without internal.d.ts) it falls back to `any`,
|
|
26
|
+
* which collapses pipe/operator inference at use sites. Pin the type to the
|
|
27
|
+
* declared class in `./types.ts` so consumers always see the typed shape. */
|
|
28
|
+
const Observable = NativeObservable as unknown as typeof ObservableT
|
|
29
|
+
type Observable<Ok, Err = never> = ObservableT<Ok, Err>
|
|
26
30
|
|
|
27
31
|
/* Catch a thrown error and re-throw it on the next tick. The synchronous
|
|
28
32
|
* caller keeps going; the error eventually surfaces as an uncaught
|
package/runtime/udp/udp.ts
CHANGED
package/runtime/wifi/types.ts
CHANGED
|
@@ -130,7 +130,7 @@ export interface Wifi {
|
|
|
130
130
|
readonly onRssiLow: Observable<number>
|
|
131
131
|
|
|
132
132
|
readonly mac: string
|
|
133
|
-
hostname: string | undefined
|
|
133
|
+
readonly hostname: string | undefined
|
|
134
134
|
ipConfig(): Result<IpConfig | undefined, WifiError>
|
|
135
135
|
ipConfig(opts: StaticIpConfig): Result<void, WifiError>
|
|
136
136
|
ipConfig(opts?: StaticIpConfig): Result<IpConfig | undefined, WifiError> | Result<void, WifiError>
|
|
@@ -141,7 +141,7 @@ export interface Wifi {
|
|
|
141
141
|
rssiThreshold: number
|
|
142
142
|
|
|
143
143
|
powerSave: PowerSaveMode
|
|
144
|
-
country: WifiCountryCode | undefined
|
|
144
|
+
readonly country: WifiCountryCode | undefined
|
|
145
145
|
}
|
|
146
146
|
|
|
147
147
|
export declare const wifi: Wifi
|
package/runtime/wifi/wifi.ts
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {lazyEvent} from 'mikrojs/observable/lazy'
|
|
2
2
|
import {err, ok} from 'mikrojs/result'
|
|
3
3
|
import {Wifi as NativeWifi} from 'native:wifi'
|
|
4
4
|
|
|
5
|
-
import type {Subscriber} from '../observable/types.js'
|
|
6
5
|
import type {Result} from '../result/types.js'
|
|
7
6
|
import type {
|
|
8
7
|
ApStartOptions,
|
|
@@ -38,36 +37,6 @@ const StatusFromCode = new Map<number, WifiStatus>(
|
|
|
38
37
|
|
|
39
38
|
const native = new NativeWifi()
|
|
40
39
|
|
|
41
|
-
/* Lazy-attach Observable: native.on is only called once a JS subscriber
|
|
42
|
-
* appears, and native.off runs when the last one unsubscribes. Code paths
|
|
43
|
-
* that import wifi but don't subscribe (e.g. a fetch-only flow) take the
|
|
44
|
-
* exact same internal-RAM path as before observables existed — important
|
|
45
|
-
* because mbedTLS handshake needs ~16 KB contiguous internal SRAM and
|
|
46
|
-
* each eager closure pinned at module load chips into that headroom. */
|
|
47
|
-
function lazyEvent<T>(eventName: string): Observable<T> {
|
|
48
|
-
const subscribers: Subscriber<T>[] = []
|
|
49
|
-
function handler(value: unknown): void {
|
|
50
|
-
/* Snapshot so unsubscribes during dispatch don't shift indices. */
|
|
51
|
-
const snapshot = subscribers.slice()
|
|
52
|
-
for (const s of snapshot) {
|
|
53
|
-
if (!s.closed) s.next(value as T)
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
return new Observable<T>((sub) => {
|
|
57
|
-
subscribers.push(sub)
|
|
58
|
-
if (subscribers.length === 1) {
|
|
59
|
-
native.on(eventName, handler)
|
|
60
|
-
}
|
|
61
|
-
sub.addTeardown(() => {
|
|
62
|
-
const i = subscribers.indexOf(sub)
|
|
63
|
-
if (i >= 0) subscribers.splice(i, 1)
|
|
64
|
-
if (subscribers.length === 0) {
|
|
65
|
-
native.off(eventName, handler)
|
|
66
|
-
}
|
|
67
|
-
})
|
|
68
|
-
})
|
|
69
|
-
}
|
|
70
|
-
|
|
71
40
|
const ap: WifiAp = {
|
|
72
41
|
start(options: ApStartOptions): Result<void, WifiError> {
|
|
73
42
|
return native.apStart(options as Parameters<typeof native.apStart>[0])
|
|
@@ -102,8 +71,8 @@ const ap: WifiAp = {
|
|
|
102
71
|
native.apSetInactiveTimeout(seconds)
|
|
103
72
|
},
|
|
104
73
|
|
|
105
|
-
onStationConnect: lazyEvent<ApStationInfo>('station-connect'),
|
|
106
|
-
onStationDisconnect: lazyEvent<ApStationInfo>('station-disconnect'),
|
|
74
|
+
onStationConnect: lazyEvent<ApStationInfo>(native, 'station-connect'),
|
|
75
|
+
onStationDisconnect: lazyEvent<ApStationInfo>(native, 'station-disconnect'),
|
|
107
76
|
}
|
|
108
77
|
|
|
109
78
|
const MAX_CONNECT_RETRIES = 5
|
|
@@ -161,9 +130,9 @@ const wifi: Wifi = {
|
|
|
161
130
|
return ok(asyncResult.value as ScanResult[])
|
|
162
131
|
},
|
|
163
132
|
|
|
164
|
-
onConnect: lazyEvent<WifiConnectionInfo>('connect'),
|
|
165
|
-
onDisconnect: lazyEvent<WifiDisconnectReason>('disconnect'),
|
|
166
|
-
onRssiLow: lazyEvent<number>('rssi-low'),
|
|
133
|
+
onConnect: lazyEvent<WifiConnectionInfo>(native, 'connect'),
|
|
134
|
+
onDisconnect: lazyEvent<WifiDisconnectReason>(native, 'disconnect'),
|
|
135
|
+
onRssiLow: lazyEvent<number>(native, 'rssi-low'),
|
|
167
136
|
|
|
168
137
|
get mac(): string {
|
|
169
138
|
const result = native.mac()
|
|
@@ -174,12 +143,6 @@ const wifi: Wifi = {
|
|
|
174
143
|
return native.getHostname()
|
|
175
144
|
},
|
|
176
145
|
|
|
177
|
-
set hostname(value: string | undefined) {
|
|
178
|
-
if (value !== undefined) {
|
|
179
|
-
native.setHostname(value)
|
|
180
|
-
}
|
|
181
|
-
},
|
|
182
|
-
|
|
183
146
|
ipConfig: ((
|
|
184
147
|
opts?: StaticIpConfig,
|
|
185
148
|
): Result<IpConfig | undefined, WifiError> | Result<void, WifiError> => {
|
|
@@ -219,12 +182,6 @@ const wifi: Wifi = {
|
|
|
219
182
|
get country(): WifiCountryCode | undefined {
|
|
220
183
|
return native.getCountry() as WifiCountryCode | undefined
|
|
221
184
|
},
|
|
222
|
-
|
|
223
|
-
set country(cc: WifiCountryCode | undefined) {
|
|
224
|
-
if (cc !== undefined) {
|
|
225
|
-
native.setCountry(cc)
|
|
226
|
-
}
|
|
227
|
-
},
|
|
228
185
|
}
|
|
229
186
|
|
|
230
187
|
export {wifi}
|
package/src/mik_app_config.cpp
CHANGED
|
@@ -19,6 +19,7 @@ void MIK_DefaultConfig(MIKConfig* config) {
|
|
|
19
19
|
config->fs_read_max = 0; /* 0 = runtime default (65536) */
|
|
20
20
|
config->entry_point[0] = '\0';
|
|
21
21
|
config->wifi_country[0] = '\0';
|
|
22
|
+
config->wifi_hostname[0] = '\0';
|
|
22
23
|
}
|
|
23
24
|
|
|
24
25
|
/* Minimal JSON parser for config file — avoids cJSON dependency.
|
|
@@ -343,8 +344,10 @@ int MIK_LoadConfig(const char* base_path, MIKConfig* config) {
|
|
|
343
344
|
if (mik__json_get_number(buf, "fsReadMax", &num_val)) {
|
|
344
345
|
config->fs_read_max = (uint32_t)num_val;
|
|
345
346
|
}
|
|
346
|
-
mik__json_get_string(buf, "
|
|
347
|
+
mik__json_get_string(buf, "wifi.country", config->wifi_country,
|
|
347
348
|
sizeof(config->wifi_country));
|
|
349
|
+
mik__json_get_string(buf, "wifi.hostname", config->wifi_hostname,
|
|
350
|
+
sizeof(config->wifi_hostname));
|
|
348
351
|
|
|
349
352
|
platform->log(MIK_LOG_INFO, TAG,
|
|
350
353
|
"Loaded config: restart=%d delay=%dms stack=%u reserved=%lu",
|