@mikrojs/firmware 0.20.1 → 0.20.2-next.20260907205905
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/components/mikrojs/mik_main.cpp +6 -11
- package/components/mikrojs/mik_ota_client_module.cpp +14 -5
- package/components/mikrojs/mik_ota_env.cpp +9 -6
- package/components/mikrojs/test/ota_host/.gitignore +2 -0
- package/package.json +4 -4
- package/prebuilds/esp32/bootloader/bootloader.bin +0 -0
- package/prebuilds/esp32/mikrojs.bin +0 -0
- package/prebuilds/esp32c3/bootloader/bootloader.bin +0 -0
- package/prebuilds/esp32c3/mikrojs.bin +0 -0
- package/prebuilds/esp32c5/bootloader/bootloader.bin +0 -0
- package/prebuilds/esp32c5/mikrojs.bin +0 -0
- package/prebuilds/esp32c6/bootloader/bootloader.bin +0 -0
- package/prebuilds/esp32c6/mikrojs.bin +0 -0
- package/prebuilds/esp32s3/bootloader/bootloader.bin +0 -0
- package/prebuilds/esp32s3/mikrojs.bin +0 -0
|
@@ -746,24 +746,19 @@ void MIK_Main(void) {
|
|
|
746
746
|
if (safe_mode) {
|
|
747
747
|
ESP_LOGW(TAG, "Safe mode: skipping entry point %s", app_config.entry_point);
|
|
748
748
|
} else {
|
|
749
|
-
/* Catch
|
|
749
|
+
/* Catch fatals during an OTA trial: MIK_RunEntry hands a synchronous
|
|
750
|
+
* throw to this handler itself, the loop's rejection flush hands it
|
|
751
|
+
* unhandled rejections. Both note the failure and arm the panic
|
|
752
|
+
* restart so reconcile reverts on the next (clean-looking) boot. */
|
|
750
753
|
MIK_SetErrorHandler(mik_rt, ota_trial_error_handler, nullptr);
|
|
751
|
-
|
|
752
|
-
int rc = MIK_RunEntryErr(mik_rt, app_config.entry_point, entry_err, sizeof(entry_err));
|
|
754
|
+
int rc = MIK_RunEntry(mik_rt, app_config.entry_point);
|
|
753
755
|
if (rc == -EINVAL) {
|
|
754
756
|
ESP_LOGW(TAG, "No entry point configured (no \"main\" field in package.json)");
|
|
755
757
|
} else if (rc == -ENOENT) {
|
|
756
758
|
ESP_LOGW(TAG, "Entry point not found: %s", app_config.entry_point);
|
|
757
759
|
} else if (rc == -EFAULT) {
|
|
760
|
+
/* Already reported to the console by the runtime. */
|
|
758
761
|
ESP_LOGE(TAG, "Failed to evaluate %s", app_config.entry_point);
|
|
759
|
-
/* A synchronous top-level throw doesn't reach the rejection handler
|
|
760
|
-
* above. If this is a trial build, flag it and arm the panic restart
|
|
761
|
-
* so reconcile reverts on the next (clean-looking) boot. */
|
|
762
|
-
if (mik__ota_in_trial()) {
|
|
763
|
-
mik__ota_note_trial_failure(entry_err[0] ? entry_err
|
|
764
|
-
: "entry failed to evaluate");
|
|
765
|
-
MIK_Stop(mik_rt);
|
|
766
|
-
}
|
|
767
762
|
}
|
|
768
763
|
}
|
|
769
764
|
}
|
|
@@ -75,6 +75,10 @@ struct MIKOtaClientState {
|
|
|
75
75
|
* only copy left after ota.reconcile() ran. settle() marks it delivered. */
|
|
76
76
|
bool has_last_install = false;
|
|
77
77
|
MIKOtaDiagnostic last_install = {};
|
|
78
|
+
/* Set by report() when the stored decline made it into the body, so settle()
|
|
79
|
+
* clears only a record the registry has seen. A read that failed leaves the
|
|
80
|
+
* record for the next round. */
|
|
81
|
+
bool decline_reported = false;
|
|
78
82
|
};
|
|
79
83
|
|
|
80
84
|
int mik__ota_client_slot = -1;
|
|
@@ -350,7 +354,8 @@ JSValue kv_string_or_undefined(JSContext* ctx, const char* key) {
|
|
|
350
354
|
MIKOtaClientState* state = state_of(ctx);
|
|
351
355
|
if (!state || !state->env || !state->env->kv_get_str) return JS_UNDEFINED;
|
|
352
356
|
char buf[256] = {};
|
|
353
|
-
if (
|
|
357
|
+
if (state->env->kv_get_str(state->env->opaque, key, buf, sizeof(buf)) != MIK_OTA_KV_OK ||
|
|
358
|
+
buf[0] == '\0') {
|
|
354
359
|
return JS_UNDEFINED;
|
|
355
360
|
}
|
|
356
361
|
return JS_NewString(ctx, buf);
|
|
@@ -911,7 +916,8 @@ JSValue ota_report(JSContext* ctx, JSValue, int, JSValue*) {
|
|
|
911
916
|
* decline(). Without it a registry cannot tell a device still working
|
|
912
917
|
* through a download from one that has stopped. */
|
|
913
918
|
MIKOtaDeclineRecord declined;
|
|
914
|
-
|
|
919
|
+
state->decline_reported = mikrojs::MIKOtaStore(env).GetDecline(&declined);
|
|
920
|
+
if (state->decline_reported) {
|
|
915
921
|
JSValue last = JS_NewObject(ctx);
|
|
916
922
|
JS_SetPropertyStr(ctx, last, "checksum", JS_NewString(ctx, declined.checksum));
|
|
917
923
|
JS_SetPropertyStr(ctx, last, "reason", JS_NewString(ctx, declined.reason));
|
|
@@ -960,10 +966,13 @@ JSValue ota_settle(JSContext* ctx, JSValue, int argc, JSValue* argv) {
|
|
|
960
966
|
/* Confirm before the deliveries, as the built-in does: it must settle the
|
|
961
967
|
* document held BEFORE this round, never the one about to be armed. */
|
|
962
968
|
mikrojs::mik__ota_policy_confirm(state->env);
|
|
963
|
-
/* The round completed, so the cached install report
|
|
964
|
-
* record
|
|
969
|
+
/* The round completed, so the cached install report was delivered, and so
|
|
970
|
+
* was the stored decline record if report() carried it. */
|
|
965
971
|
state->has_last_install = false;
|
|
966
|
-
|
|
972
|
+
if (state->decline_reported) {
|
|
973
|
+
mikrojs::MIKOtaStore(state->env).ClearDecline();
|
|
974
|
+
state->decline_reported = false;
|
|
975
|
+
}
|
|
967
976
|
|
|
968
977
|
bool renamed = false;
|
|
969
978
|
if (usable) {
|
|
@@ -105,11 +105,13 @@ bool env_kv_set_blob(void*, const char* key, const uint8_t* data, size_t len) {
|
|
|
105
105
|
return kv_write_blob(key, data, len);
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
MIKOtaKvStatus env_kv_get_str(void*, const char* key, char* out, size_t max_len) {
|
|
109
109
|
uint8_t buf[320];
|
|
110
110
|
size_t len = sizeof(buf);
|
|
111
|
-
|
|
112
|
-
|
|
111
|
+
MIKOtaKvStatus status = kv_read_blob(key, buf, &len);
|
|
112
|
+
if (status != MIK_OTA_KV_OK) return status;
|
|
113
|
+
/* Stored bytes that will not decode are corruption, not absence. */
|
|
114
|
+
return mik__kv_decode_str(buf, len, out, max_len) ? MIK_OTA_KV_OK : MIK_OTA_KV_ERROR;
|
|
113
115
|
}
|
|
114
116
|
|
|
115
117
|
bool env_kv_set_str(void*, const char* key, const char* value) {
|
|
@@ -119,11 +121,12 @@ bool env_kv_set_str(void*, const char* key, const char* value) {
|
|
|
119
121
|
return kv_write_blob(key, buf, needed);
|
|
120
122
|
}
|
|
121
123
|
|
|
122
|
-
|
|
124
|
+
MIKOtaKvStatus env_kv_get_i32(void*, const char* key, int32_t* out) {
|
|
123
125
|
uint8_t buf[16];
|
|
124
126
|
size_t len = sizeof(buf);
|
|
125
|
-
|
|
126
|
-
|
|
127
|
+
MIKOtaKvStatus status = kv_read_blob(key, buf, &len);
|
|
128
|
+
if (status != MIK_OTA_KV_OK) return status;
|
|
129
|
+
return mik__kv_decode_i32(buf, len, out) ? MIK_OTA_KV_OK : MIK_OTA_KV_ERROR;
|
|
127
130
|
}
|
|
128
131
|
|
|
129
132
|
bool env_kv_set_i32(void*, const char* key, int32_t value) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mikrojs/firmware",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.2-next.20260907205905",
|
|
4
4
|
"description": "Mikro.js ESP32 firmware: ESP-IDF component, build tools, and project template",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"esp-idf",
|
|
@@ -46,9 +46,9 @@
|
|
|
46
46
|
"./package.json": "./package.json"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"
|
|
50
|
-
"@mikrojs/
|
|
51
|
-
"
|
|
49
|
+
"@mikrojs/native": "0.20.2-next.20260907205905+8b6f502",
|
|
50
|
+
"@mikrojs/quickjs": "0.20.2-next.20260907205905+8b6f502",
|
|
51
|
+
"esbuild": "^0.28.2"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=24.0.0"
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|