@sigx/lynx-updates 0.6.1
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 +162 -0
- package/android/com/sigx/updates/UpdateDownloader.kt +154 -0
- package/android/com/sigx/updates/UpdateStore.kt +367 -0
- package/android/com/sigx/updates/UpdatesActivityHook.kt +25 -0
- package/android/com/sigx/updates/UpdatesBundleResolver.kt +18 -0
- package/android/com/sigx/updates/UpdatesEventBus.kt +54 -0
- package/android/com/sigx/updates/UpdatesLifecyclePublisher.kt +42 -0
- package/android/com/sigx/updates/UpdatesModule.kt +235 -0
- package/dist/controller.d.ts +31 -0
- package/dist/controller.d.ts.map +1 -0
- package/dist/controller.js +344 -0
- package/dist/controller.js.map +1 -0
- package/dist/events.d.ts +18 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +61 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -0
- package/dist/native.d.ts +41 -0
- package/dist/native.d.ts.map +1 -0
- package/dist/native.js +161 -0
- package/dist/native.js.map +1 -0
- package/dist/provider/static-manifest.d.ts +66 -0
- package/dist/provider/static-manifest.d.ts.map +1 -0
- package/dist/provider/static-manifest.js +173 -0
- package/dist/provider/static-manifest.js.map +1 -0
- package/dist/state.d.ts +23 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +73 -0
- package/dist/state.js.map +1 -0
- package/dist/types.d.ts +203 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/dist/updates.d.ts +45 -0
- package/dist/updates.d.ts.map +1 -0
- package/dist/updates.js +67 -0
- package/dist/updates.js.map +1 -0
- package/dist/use-updates.d.ts +16 -0
- package/dist/use-updates.d.ts.map +1 -0
- package/dist/use-updates.js +29 -0
- package/dist/use-updates.js.map +1 -0
- package/ios/UpdateDownloader.swift +152 -0
- package/ios/UpdateStore.swift +286 -0
- package/ios/UpdatesBundleResolver.swift +15 -0
- package/ios/UpdatesEventBus.swift +59 -0
- package/ios/UpdatesLifecyclePublisher.swift +48 -0
- package/ios/UpdatesModule.swift +178 -0
- package/package.json +59 -0
- package/signalx-module.json +35 -0
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
package com.sigx.updates
|
|
2
|
+
|
|
3
|
+
import android.content.Context
|
|
4
|
+
import android.os.Handler
|
|
5
|
+
import android.os.Looper
|
|
6
|
+
import android.util.Log
|
|
7
|
+
import com.lynx.jsbridge.LynxMethod
|
|
8
|
+
import com.lynx.jsbridge.LynxModule
|
|
9
|
+
import com.lynx.react.bridge.Callback
|
|
10
|
+
import com.lynx.react.bridge.JavaOnlyMap
|
|
11
|
+
import com.lynx.react.bridge.ReadableMap
|
|
12
|
+
import com.lynx.tasm.TemplateData
|
|
13
|
+
import org.json.JSONObject
|
|
14
|
+
import java.io.File
|
|
15
|
+
import java.util.concurrent.Executors
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* JS bridge for OTA updates.
|
|
19
|
+
* JS usage: NativeModules.Updates.downloadUpdate({...}, callback)
|
|
20
|
+
*
|
|
21
|
+
* Downloads run on a single-thread executor (single-flight is also enforced
|
|
22
|
+
* in [UpdateDownloader]); everything else is cheap file/state work.
|
|
23
|
+
*/
|
|
24
|
+
class UpdatesModule(context: Context) : LynxModule(context) {
|
|
25
|
+
|
|
26
|
+
companion object {
|
|
27
|
+
private const val TAG = "SigxUpdates"
|
|
28
|
+
private val executor = Executors.newSingleThreadExecutor { r ->
|
|
29
|
+
Thread(r, "sigx-updates").apply { isDaemon = true }
|
|
30
|
+
}
|
|
31
|
+
private val mainHandler = Handler(Looper.getMainLooper())
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private fun error(message: String, code: String? = null): JavaOnlyMap {
|
|
35
|
+
val map = JavaOnlyMap()
|
|
36
|
+
map.putString("error", message)
|
|
37
|
+
if (code != null) map.putString("code", code)
|
|
38
|
+
return map
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private fun ok(): JavaOnlyMap {
|
|
42
|
+
val map = JavaOnlyMap()
|
|
43
|
+
map.putBoolean("ok", true)
|
|
44
|
+
return map
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
@LynxMethod
|
|
48
|
+
fun getInstalledRuntimeVersion(): String {
|
|
49
|
+
return UpdateStore.installedRuntimeVersion(mContext)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@LynxMethod
|
|
53
|
+
fun getPlatform(): String = "android"
|
|
54
|
+
|
|
55
|
+
@LynxMethod
|
|
56
|
+
fun getCurrentUpdate(callback: Callback?) {
|
|
57
|
+
try {
|
|
58
|
+
val map = JavaOnlyMap()
|
|
59
|
+
val updateId = UpdateStore.launchedUpdateId
|
|
60
|
+
if (updateId != null) {
|
|
61
|
+
map.putString("updateId", updateId)
|
|
62
|
+
map.putBoolean("isEmbedded", false)
|
|
63
|
+
val metaFile = UpdateStore.updateJsonFile(mContext, updateId)
|
|
64
|
+
if (metaFile.exists()) {
|
|
65
|
+
try {
|
|
66
|
+
val meta = JSONObject(metaFile.readText())
|
|
67
|
+
map.putString("version", meta.optString("version"))
|
|
68
|
+
} catch (_: Exception) { /* metadata is best-effort */ }
|
|
69
|
+
}
|
|
70
|
+
} else {
|
|
71
|
+
map.putBoolean("isEmbedded", true)
|
|
72
|
+
}
|
|
73
|
+
map.putString("runtimeVersion", UpdateStore.installedRuntimeVersion(mContext))
|
|
74
|
+
// Store-shipped app version — providers receive it as
|
|
75
|
+
// UpdateCheckContext.embeddedVersion.
|
|
76
|
+
val versionName = runCatching {
|
|
77
|
+
mContext.packageManager.getPackageInfo(mContext.packageName, 0).versionName
|
|
78
|
+
}.getOrNull()
|
|
79
|
+
map.putString("embeddedVersion", versionName ?: "")
|
|
80
|
+
map.putBoolean("isFirstLaunchAfterUpdate", UpdateStore.isFirstLaunchAfterUpdate)
|
|
81
|
+
map.putBoolean("didRollBack", UpdateStore.didRollBack)
|
|
82
|
+
UpdateStore.rolledBackUpdateId?.let { map.putString("rolledBackUpdateId", it) }
|
|
83
|
+
callback?.invoke(map)
|
|
84
|
+
} catch (e: Exception) {
|
|
85
|
+
callback?.invoke(error(e.message ?: "getCurrentUpdate failed"))
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
@LynxMethod
|
|
90
|
+
fun getState(callback: Callback?) {
|
|
91
|
+
try {
|
|
92
|
+
val state = UpdateStore.readState(mContext)
|
|
93
|
+
val map = JavaOnlyMap()
|
|
94
|
+
if (state != null) {
|
|
95
|
+
map.putString("currentUpdateId", state.currentUpdateId ?: "")
|
|
96
|
+
map.putString("previousUpdateId", state.previousUpdateId ?: "")
|
|
97
|
+
map.putString("pendingUpdateId", state.pendingUpdateId ?: "")
|
|
98
|
+
map.putInt("pendingLaunchAttempts", state.pendingLaunchAttempts)
|
|
99
|
+
map.putInt("maxLaunchAttempts", state.maxLaunchAttempts)
|
|
100
|
+
map.putString("lastRollbackUpdateId", state.lastRollbackUpdateId ?: "")
|
|
101
|
+
map.putString("lastRollbackReason", state.lastRollbackReason ?: "")
|
|
102
|
+
}
|
|
103
|
+
map.putString("runningUpdateId", UpdateStore.launchedUpdateId ?: "")
|
|
104
|
+
callback?.invoke(map)
|
|
105
|
+
} catch (e: Exception) {
|
|
106
|
+
callback?.invoke(error(e.message ?: "getState failed"))
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
@LynxMethod
|
|
111
|
+
fun downloadUpdate(params: ReadableMap?, callback: Callback?) {
|
|
112
|
+
val url = params?.getString("url")
|
|
113
|
+
val sha256 = params?.getString("sha256")
|
|
114
|
+
val updateId = params?.getString("updateId")
|
|
115
|
+
val runtimeVersion = params?.getString("runtimeVersion")
|
|
116
|
+
val manifestJson = try { params?.getString("manifestJson") } catch (_: Exception) { null }
|
|
117
|
+
if (url.isNullOrEmpty() || sha256.isNullOrEmpty() || updateId.isNullOrEmpty()) {
|
|
118
|
+
callback?.invoke(error("url, sha256 and updateId are required"))
|
|
119
|
+
return
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Refuse incompatible bundles at the door — defense in depth on top
|
|
123
|
+
// of the JS-side check.
|
|
124
|
+
val installed = UpdateStore.installedRuntimeVersion(mContext)
|
|
125
|
+
if (!runtimeVersion.isNullOrEmpty() && runtimeVersion != installed) {
|
|
126
|
+
callback?.invoke(error(
|
|
127
|
+
"Update requires runtime $runtimeVersion but binary is $installed",
|
|
128
|
+
"E_RUNTIME_MISMATCH",
|
|
129
|
+
))
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
val headers = mutableMapOf<String, String>()
|
|
134
|
+
try {
|
|
135
|
+
val headerMap = params.getMap("headers")
|
|
136
|
+
if (headerMap != null) {
|
|
137
|
+
val it = headerMap.keySetIterator()
|
|
138
|
+
while (it.hasNextKey()) {
|
|
139
|
+
val key = it.nextKey()
|
|
140
|
+
headerMap.getString(key)?.let { v -> headers[key] = v }
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
} catch (_: Exception) { /* headers optional */ }
|
|
144
|
+
|
|
145
|
+
executor.execute {
|
|
146
|
+
val result = UpdateDownloader.download(
|
|
147
|
+
mContext, url, sha256, updateId, headers, manifestJson ?: "{}")
|
|
148
|
+
if (result == null) {
|
|
149
|
+
callback?.invoke(ok())
|
|
150
|
+
} else {
|
|
151
|
+
val code = when {
|
|
152
|
+
result.startsWith("E_DOWNLOAD_IN_PROGRESS") -> "E_DOWNLOAD_IN_PROGRESS"
|
|
153
|
+
result.startsWith("E_HASH_MISMATCH") -> "hash-mismatch"
|
|
154
|
+
else -> null
|
|
155
|
+
}
|
|
156
|
+
callback?.invoke(error(result, code))
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
@LynxMethod
|
|
162
|
+
fun applyOnNextLaunch(updateId: String?, callback: Callback?) {
|
|
163
|
+
if (updateId.isNullOrEmpty()) {
|
|
164
|
+
callback?.invoke(error("updateId is required"))
|
|
165
|
+
return
|
|
166
|
+
}
|
|
167
|
+
val result = UpdateStore.stagePending(mContext, updateId)
|
|
168
|
+
callback?.invoke(if (result == null) ok() else error(result))
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
@LynxMethod
|
|
172
|
+
fun applyNow(updateId: String?, callback: Callback?) {
|
|
173
|
+
if (updateId.isNullOrEmpty()) {
|
|
174
|
+
callback?.invoke(error("updateId is required"))
|
|
175
|
+
return
|
|
176
|
+
}
|
|
177
|
+
val bundle = UpdateStore.bundleFile(mContext, updateId)
|
|
178
|
+
if (!bundle.exists()) {
|
|
179
|
+
callback?.invoke(error("Update $updateId is not on disk"))
|
|
180
|
+
return
|
|
181
|
+
}
|
|
182
|
+
val view = UpdateStore.currentView()
|
|
183
|
+
if (view == null) {
|
|
184
|
+
callback?.invoke(error("No LynxView attached — cannot reload in place", "E_NO_VIEW"))
|
|
185
|
+
return
|
|
186
|
+
}
|
|
187
|
+
// Stage first so a crash mid-reload still gets crash-guarded rollback
|
|
188
|
+
// (the reload bypasses the startup resolver).
|
|
189
|
+
UpdateStore.stagePending(mContext, updateId)
|
|
190
|
+
UpdateStore.recordReloadAttempt(mContext, updateId)
|
|
191
|
+
mainHandler.post {
|
|
192
|
+
try {
|
|
193
|
+
val bytes = File(bundle.absolutePath).readBytes()
|
|
194
|
+
view.reloadAndInit()
|
|
195
|
+
view.renderTemplateWithBaseUrl(bytes, TemplateData.empty(), "file://${bundle.absolutePath}")
|
|
196
|
+
// JS context is replaced — the callback never reaches the old
|
|
197
|
+
// context on success, which is the documented contract.
|
|
198
|
+
} catch (e: Exception) {
|
|
199
|
+
Log.e(TAG, "applyNow reload failed: ${e.message}")
|
|
200
|
+
callback?.invoke(error(e.message ?: "Reload failed", "apply-failed"))
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
@LynxMethod
|
|
206
|
+
fun markReady(callback: Callback?) {
|
|
207
|
+
try {
|
|
208
|
+
UpdateStore.markReady(mContext)
|
|
209
|
+
callback?.invoke(ok())
|
|
210
|
+
} catch (e: Exception) {
|
|
211
|
+
callback?.invoke(error(e.message ?: "markReady failed"))
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
@LynxMethod
|
|
216
|
+
fun setRollbackOptions(params: ReadableMap?, callback: Callback?) {
|
|
217
|
+
try {
|
|
218
|
+
val max = params?.getInt("maxFailedLaunches") ?: 2
|
|
219
|
+
UpdateStore.setMaxLaunchAttempts(mContext, max)
|
|
220
|
+
callback?.invoke(ok())
|
|
221
|
+
} catch (e: Exception) {
|
|
222
|
+
callback?.invoke(error(e.message ?: "setRollbackOptions failed"))
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
@LynxMethod
|
|
227
|
+
fun clearUpdates(callback: Callback?) {
|
|
228
|
+
try {
|
|
229
|
+
UpdateStore.clearAll(mContext)
|
|
230
|
+
callback?.invoke(ok())
|
|
231
|
+
} catch (e: Exception) {
|
|
232
|
+
callback?.invoke(error(e.message ?: "clearUpdates failed"))
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The updates state machine + mode orchestration. Modes are a thin strategy
|
|
3
|
+
* layer over the same primitives the public API exposes:
|
|
4
|
+
*
|
|
5
|
+
* silent → check + download on launch/foreground; stop at 'ready'
|
|
6
|
+
* immediate → silent, then apply() as soon as 'ready'
|
|
7
|
+
* manual → nothing automatic
|
|
8
|
+
*
|
|
9
|
+
* Mandatory updates (manifest.mandatory && honorMandatory) override every
|
|
10
|
+
* mode: state.mandatory blocks the UI, the download is forced (even in
|
|
11
|
+
* manual) and the update auto-applies once ready — the user is blocked
|
|
12
|
+
* anyway, so restarting immediately strictly beats staying blocked.
|
|
13
|
+
*/
|
|
14
|
+
import { type UpdateCheckResult, type UpdateManifest, type UpdatesConfig } from './types.js';
|
|
15
|
+
/** @internal */
|
|
16
|
+
export declare function configure(raw: UpdatesConfig): void;
|
|
17
|
+
/** @internal */
|
|
18
|
+
export declare function checkForUpdate(): Promise<UpdateCheckResult>;
|
|
19
|
+
/** @internal */
|
|
20
|
+
export declare function download(manifest?: UpdateManifest): Promise<void>;
|
|
21
|
+
/** @internal */
|
|
22
|
+
export declare function apply(): Promise<void>;
|
|
23
|
+
/** Check, then (per mode policy) download and maybe apply. @internal */
|
|
24
|
+
export declare function checkAndMaybeDownload(): Promise<void>;
|
|
25
|
+
/** @internal */
|
|
26
|
+
export declare function markReady(): Promise<void>;
|
|
27
|
+
/** @internal */
|
|
28
|
+
export declare function clearUpdates(): Promise<void>;
|
|
29
|
+
/** Test-only: reset module-level config. @internal */
|
|
30
|
+
export declare function __resetForTests(): void;
|
|
31
|
+
//# sourceMappingURL=controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.d.ts","sourceRoot":"","sources":["../src/controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAmBH,OAAO,EAIH,KAAK,iBAAiB,EACtB,KAAK,cAAc,EAEnB,KAAK,aAAa,EACrB,MAAM,YAAY,CAAC;AAkCpB,gBAAgB;AAChB,wBAAgB,SAAS,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CA2DlD;AA2CD,gBAAgB;AAChB,wBAAsB,cAAc,IAAI,OAAO,CAAC,iBAAiB,CAAC,CAkEjE;AAED,gBAAgB;AAChB,wBAAsB,QAAQ,CAAC,QAAQ,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,IAAI,CAAC,CA2DvE;AAED,gBAAgB;AAChB,wBAAsB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAqB3C;AAYD,wEAAwE;AACxE,wBAAsB,qBAAqB,IAAI,OAAO,CAAC,IAAI,CAAC,CAyB3D;AAED,gBAAgB;AAChB,wBAAsB,SAAS,IAAI,OAAO,CAAC,IAAI,CAAC,CAE/C;AAED,gBAAgB;AAChB,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAElD;AAED,sDAAsD;AACtD,wBAAgB,eAAe,IAAI,IAAI,CAStC"}
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The updates state machine + mode orchestration. Modes are a thin strategy
|
|
3
|
+
* layer over the same primitives the public API exposes:
|
|
4
|
+
*
|
|
5
|
+
* silent → check + download on launch/foreground; stop at 'ready'
|
|
6
|
+
* immediate → silent, then apply() as soon as 'ready'
|
|
7
|
+
* manual → nothing automatic
|
|
8
|
+
*
|
|
9
|
+
* Mandatory updates (manifest.mandatory && honorMandatory) override every
|
|
10
|
+
* mode: state.mandatory blocks the UI, the download is forced (even in
|
|
11
|
+
* manual) and the update auto-applies once ready — the user is blocked
|
|
12
|
+
* anyway, so restarting immediately strictly beats staying blocked.
|
|
13
|
+
*/
|
|
14
|
+
import { createLogger } from '@sigx/lynx-core';
|
|
15
|
+
import { addNativeUpdatesListener } from './events.js';
|
|
16
|
+
import { bakedChannel, getCurrentUpdate, getInstalledRuntimeVersion, getPlatform, nativeApplyNow, nativeApplyOnNextLaunch, nativeAvailable, nativeClearUpdates, nativeDownload, nativeMarkReady, nativeSetRollbackOptions, } from './native.js';
|
|
17
|
+
import { StaticManifestProvider } from './provider/static-manifest.js';
|
|
18
|
+
import { emit, store } from './state.js';
|
|
19
|
+
import { UpdatesError, } from './types.js';
|
|
20
|
+
const log = createLogger('updates');
|
|
21
|
+
let config = null;
|
|
22
|
+
let unsubscribeNative = null;
|
|
23
|
+
let warnedUnavailable = false;
|
|
24
|
+
let checkInFlight = null;
|
|
25
|
+
let downloadInFlight = null;
|
|
26
|
+
let downloadInFlightId = null;
|
|
27
|
+
let bootstrapScheduled = false;
|
|
28
|
+
function requireConfig() {
|
|
29
|
+
if (!config) {
|
|
30
|
+
throw new UpdatesError('not-configured', 'Call Updates.configure() before using the Updates API');
|
|
31
|
+
}
|
|
32
|
+
return config;
|
|
33
|
+
}
|
|
34
|
+
function warnUnavailableOnce() {
|
|
35
|
+
if (warnedUnavailable)
|
|
36
|
+
return;
|
|
37
|
+
warnedUnavailable = true;
|
|
38
|
+
log.warn('Updates native module not available — OTA updates are a no-op in this environment');
|
|
39
|
+
}
|
|
40
|
+
/** @internal */
|
|
41
|
+
export function configure(raw) {
|
|
42
|
+
const provider = 'checkForUpdate' in raw.provider
|
|
43
|
+
? raw.provider
|
|
44
|
+
: new StaticManifestProvider(raw.provider);
|
|
45
|
+
config = {
|
|
46
|
+
provider,
|
|
47
|
+
channel: raw.channel ?? bakedChannel(),
|
|
48
|
+
mode: raw.mode ?? 'silent',
|
|
49
|
+
checkOn: raw.checkOn ?? ['launch'],
|
|
50
|
+
honorMandatory: raw.honorMandatory !== false,
|
|
51
|
+
autoMarkReady: raw.autoMarkReady !== false,
|
|
52
|
+
};
|
|
53
|
+
if (!nativeAvailable()) {
|
|
54
|
+
warnUnavailableOnce();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
// Native event channel: download progress + foreground re-checks.
|
|
58
|
+
unsubscribeNative?.();
|
|
59
|
+
unsubscribeNative = addNativeUpdatesListener((event) => {
|
|
60
|
+
if (event.kind === 'progress') {
|
|
61
|
+
// Late events (delivered after the download settled) must not
|
|
62
|
+
// resurrect progress state outside 'downloading'.
|
|
63
|
+
if (store.status !== 'downloading')
|
|
64
|
+
return;
|
|
65
|
+
const progress = { receivedBytes: event.receivedBytes, totalBytes: event.totalBytes };
|
|
66
|
+
store.progress = progress;
|
|
67
|
+
emit({ type: 'downloadProgress', progress });
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (event.kind === 'foreground' && config?.mode !== 'manual' && config?.checkOn.includes('foreground')) {
|
|
71
|
+
// Don't interleave with an installation already in flight — a
|
|
72
|
+
// re-check would flip status to 'checking' mid-download and hide
|
|
73
|
+
// progress UI. The next foreground (or the post-apply launch)
|
|
74
|
+
// picks it up.
|
|
75
|
+
if (downloadInFlight || store.status === 'downloading' || store.status === 'applying') {
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
void checkAndMaybeDownload();
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
if (raw.rollback?.maxFailedLaunches !== undefined) {
|
|
82
|
+
nativeSetRollbackOptions(raw.rollback.maxFailedLaunches).catch((err) => {
|
|
83
|
+
log.warn('setRollbackOptions failed:', err);
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
// Defer everything else off the boot path — never block first paint.
|
|
87
|
+
// Latched: re-configuring updates the config but must not re-run
|
|
88
|
+
// markReady / the launch check (that's the documented idempotence).
|
|
89
|
+
if (!bootstrapScheduled) {
|
|
90
|
+
bootstrapScheduled = true;
|
|
91
|
+
setTimeout(() => {
|
|
92
|
+
void bootstrap();
|
|
93
|
+
}, 0);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
async function bootstrap() {
|
|
97
|
+
const cfg = requireConfig();
|
|
98
|
+
// Surface what we're running + rollback outcome from the resolver.
|
|
99
|
+
try {
|
|
100
|
+
const running = await getCurrentUpdate();
|
|
101
|
+
store.currentlyRunning = running;
|
|
102
|
+
if (running.didRollBack) {
|
|
103
|
+
emit({ type: 'rolledBack', fromUpdateId: running.rolledBackUpdateId ?? 'unknown' });
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
catch (err) {
|
|
107
|
+
log.warn('getCurrentUpdate failed:', err);
|
|
108
|
+
}
|
|
109
|
+
// Health signal — the pending update commits once JS is alive. Apps
|
|
110
|
+
// that gate on their own readiness set autoMarkReady: false and call
|
|
111
|
+
// Updates.markReady() themselves.
|
|
112
|
+
if (cfg.autoMarkReady) {
|
|
113
|
+
try {
|
|
114
|
+
await nativeMarkReady();
|
|
115
|
+
}
|
|
116
|
+
catch (err) {
|
|
117
|
+
log.warn('markReady failed:', err);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (cfg.mode !== 'manual' && cfg.checkOn.includes('launch')) {
|
|
121
|
+
await checkAndMaybeDownload();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
function buildContext(cfg) {
|
|
125
|
+
const running = store.currentlyRunning;
|
|
126
|
+
return {
|
|
127
|
+
platform: getPlatform(),
|
|
128
|
+
runtimeVersion: getInstalledRuntimeVersion(),
|
|
129
|
+
currentUpdateId: running.updateId,
|
|
130
|
+
embeddedVersion: running.embeddedVersion,
|
|
131
|
+
channel: cfg.channel,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/** @internal */
|
|
135
|
+
export async function checkForUpdate() {
|
|
136
|
+
const cfg = requireConfig();
|
|
137
|
+
if (checkInFlight)
|
|
138
|
+
return checkInFlight;
|
|
139
|
+
checkInFlight = (async () => {
|
|
140
|
+
store.status = 'checking';
|
|
141
|
+
store.error = null;
|
|
142
|
+
store.progress = null;
|
|
143
|
+
emit({ type: 'checkStarted' });
|
|
144
|
+
try {
|
|
145
|
+
const ctx = buildContext(cfg);
|
|
146
|
+
let result = await cfg.provider.checkForUpdate(ctx);
|
|
147
|
+
// Core re-validates the provider's answer: a manifest whose
|
|
148
|
+
// runtimeVersion doesn't match this binary is never installable,
|
|
149
|
+
// whatever the provider claims.
|
|
150
|
+
if (result.type === 'update-available' &&
|
|
151
|
+
result.manifest.runtimeVersion !== ctx.runtimeVersion) {
|
|
152
|
+
result = { type: 'incompatible', manifest: result.manifest };
|
|
153
|
+
}
|
|
154
|
+
switch (result.type) {
|
|
155
|
+
case 'up-to-date':
|
|
156
|
+
store.status = 'up-to-date';
|
|
157
|
+
store.manifest = null;
|
|
158
|
+
store.mandatory = false;
|
|
159
|
+
emit({ type: 'upToDate' });
|
|
160
|
+
break;
|
|
161
|
+
case 'incompatible':
|
|
162
|
+
store.status = 'incompatible';
|
|
163
|
+
store.manifest = result.manifest;
|
|
164
|
+
store.mandatory = false;
|
|
165
|
+
emit({ type: 'incompatibleUpdate', manifest: result.manifest });
|
|
166
|
+
break;
|
|
167
|
+
case 'update-available':
|
|
168
|
+
store.status = 'available';
|
|
169
|
+
store.manifest = result.manifest;
|
|
170
|
+
emit({ type: 'updateAvailable', manifest: result.manifest });
|
|
171
|
+
if (result.manifest.mandatory && cfg.honorMandatory) {
|
|
172
|
+
store.mandatory = true;
|
|
173
|
+
// Mandatory overrides every mode (including manual):
|
|
174
|
+
// the UI is blocked, so install immediately. Fire and
|
|
175
|
+
// forget — progress/errors surface via state/events.
|
|
176
|
+
void runMandatoryPipeline(result.manifest);
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
// The blocking flag tracks the CURRENT best update —
|
|
180
|
+
// a previously-seen mandatory update that has since
|
|
181
|
+
// been superseded must not keep the UI blocked.
|
|
182
|
+
store.mandatory = false;
|
|
183
|
+
}
|
|
184
|
+
break;
|
|
185
|
+
}
|
|
186
|
+
return result;
|
|
187
|
+
}
|
|
188
|
+
catch (err) {
|
|
189
|
+
const error = err instanceof UpdatesError
|
|
190
|
+
? err
|
|
191
|
+
: new UpdatesError('check-failed', `${err?.message ?? err}`);
|
|
192
|
+
store.status = 'error';
|
|
193
|
+
store.error = error;
|
|
194
|
+
emit({ type: 'error', error });
|
|
195
|
+
throw error;
|
|
196
|
+
}
|
|
197
|
+
finally {
|
|
198
|
+
checkInFlight = null;
|
|
199
|
+
}
|
|
200
|
+
})();
|
|
201
|
+
return checkInFlight;
|
|
202
|
+
}
|
|
203
|
+
/** @internal */
|
|
204
|
+
export async function download(manifest) {
|
|
205
|
+
const cfg = requireConfig();
|
|
206
|
+
const target = manifest ?? store.manifest;
|
|
207
|
+
if (!target) {
|
|
208
|
+
throw new UpdatesError('download-failed', 'No update to download — call checkForUpdate() first');
|
|
209
|
+
}
|
|
210
|
+
if (downloadInFlight) {
|
|
211
|
+
// Same update → join the in-flight download. A DIFFERENT update must
|
|
212
|
+
// not silently resolve against the wrong bytes.
|
|
213
|
+
if (downloadInFlightId === target.id)
|
|
214
|
+
return downloadInFlight;
|
|
215
|
+
throw new UpdatesError('download-in-progress', `Download of update ${downloadInFlightId} is in progress — cannot start ${target.id}`);
|
|
216
|
+
}
|
|
217
|
+
// Validate BEFORE arming the single-flight latch — a throw past this
|
|
218
|
+
// point would leave downloadInFlight set forever.
|
|
219
|
+
const ctx = buildContext(cfg);
|
|
220
|
+
if (target.runtimeVersion !== ctx.runtimeVersion) {
|
|
221
|
+
throw new UpdatesError('runtime-mismatch', `Update ${target.id} requires runtime ${target.runtimeVersion}; this binary is ${ctx.runtimeVersion} — a store release is needed`);
|
|
222
|
+
}
|
|
223
|
+
downloadInFlightId = target.id;
|
|
224
|
+
downloadInFlight = (async () => {
|
|
225
|
+
store.status = 'downloading';
|
|
226
|
+
store.manifest = target;
|
|
227
|
+
store.progress = { receivedBytes: 0, totalBytes: null };
|
|
228
|
+
store.error = null;
|
|
229
|
+
emit({ type: 'downloadStarted', manifest: target });
|
|
230
|
+
try {
|
|
231
|
+
const spec = cfg.provider.resolveDownload
|
|
232
|
+
? await cfg.provider.resolveDownload(target, ctx)
|
|
233
|
+
: { url: target.bundleUrl, sha256: target.sha256 };
|
|
234
|
+
await nativeDownload(spec, target.id, target.runtimeVersion, JSON.stringify(target));
|
|
235
|
+
// Default activation policy: the staged bundle loads on the next
|
|
236
|
+
// cold launch. apply() upgrades that to an immediate reload.
|
|
237
|
+
await nativeApplyOnNextLaunch(target.id);
|
|
238
|
+
store.status = 'ready';
|
|
239
|
+
store.progress = null;
|
|
240
|
+
emit({ type: 'updateReady', manifest: target });
|
|
241
|
+
}
|
|
242
|
+
catch (err) {
|
|
243
|
+
const error = err instanceof UpdatesError
|
|
244
|
+
? err
|
|
245
|
+
: new UpdatesError('download-failed', `${err?.message ?? err}`);
|
|
246
|
+
store.status = 'error';
|
|
247
|
+
store.progress = null;
|
|
248
|
+
store.error = error;
|
|
249
|
+
emit({ type: 'error', error });
|
|
250
|
+
throw error;
|
|
251
|
+
}
|
|
252
|
+
finally {
|
|
253
|
+
downloadInFlight = null;
|
|
254
|
+
downloadInFlightId = null;
|
|
255
|
+
}
|
|
256
|
+
})();
|
|
257
|
+
return downloadInFlight;
|
|
258
|
+
}
|
|
259
|
+
/** @internal */
|
|
260
|
+
export async function apply() {
|
|
261
|
+
requireConfig();
|
|
262
|
+
const target = store.manifest;
|
|
263
|
+
if (!target || store.status !== 'ready') {
|
|
264
|
+
throw new UpdatesError('apply-failed', 'No downloaded update to apply — download() must complete first');
|
|
265
|
+
}
|
|
266
|
+
store.status = 'applying';
|
|
267
|
+
emit({ type: 'applying' });
|
|
268
|
+
try {
|
|
269
|
+
// On success the JS context is replaced — this only returns on failure.
|
|
270
|
+
await nativeApplyNow(target.id);
|
|
271
|
+
}
|
|
272
|
+
catch (err) {
|
|
273
|
+
const error = err instanceof UpdatesError
|
|
274
|
+
? err
|
|
275
|
+
: new UpdatesError('apply-failed', `${err?.message ?? err}`);
|
|
276
|
+
// The bundle stays staged for next launch, so 'ready' remains true.
|
|
277
|
+
store.status = 'ready';
|
|
278
|
+
store.error = error;
|
|
279
|
+
emit({ type: 'error', error });
|
|
280
|
+
throw error;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
/** Forced install for mandatory updates — runs in every mode. */
|
|
284
|
+
async function runMandatoryPipeline(target) {
|
|
285
|
+
try {
|
|
286
|
+
await download(target);
|
|
287
|
+
await apply();
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
// surfaced via state/events; UpdateGate offers retry
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
/** Check, then (per mode policy) download and maybe apply. @internal */
|
|
294
|
+
export async function checkAndMaybeDownload() {
|
|
295
|
+
const cfg = requireConfig();
|
|
296
|
+
let result;
|
|
297
|
+
try {
|
|
298
|
+
result = await checkForUpdate();
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
return; // surfaced via state/events already
|
|
302
|
+
}
|
|
303
|
+
if (result.type !== 'update-available')
|
|
304
|
+
return;
|
|
305
|
+
// Mandatory updates were already dispatched inside checkForUpdate.
|
|
306
|
+
if (result.manifest.mandatory && cfg.honorMandatory)
|
|
307
|
+
return;
|
|
308
|
+
if (cfg.mode === 'manual')
|
|
309
|
+
return;
|
|
310
|
+
try {
|
|
311
|
+
await download(result.manifest);
|
|
312
|
+
}
|
|
313
|
+
catch {
|
|
314
|
+
return;
|
|
315
|
+
}
|
|
316
|
+
if (cfg.mode === 'immediate') {
|
|
317
|
+
try {
|
|
318
|
+
await apply();
|
|
319
|
+
}
|
|
320
|
+
catch {
|
|
321
|
+
// surfaced via state/events; staged for next launch regardless
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
/** @internal */
|
|
326
|
+
export async function markReady() {
|
|
327
|
+
await nativeMarkReady();
|
|
328
|
+
}
|
|
329
|
+
/** @internal */
|
|
330
|
+
export async function clearUpdates() {
|
|
331
|
+
await nativeClearUpdates();
|
|
332
|
+
}
|
|
333
|
+
/** Test-only: reset module-level config. @internal */
|
|
334
|
+
export function __resetForTests() {
|
|
335
|
+
config = null;
|
|
336
|
+
unsubscribeNative?.();
|
|
337
|
+
unsubscribeNative = null;
|
|
338
|
+
warnedUnavailable = false;
|
|
339
|
+
checkInFlight = null;
|
|
340
|
+
downloadInFlight = null;
|
|
341
|
+
downloadInFlightId = null;
|
|
342
|
+
bootstrapScheduled = false;
|
|
343
|
+
}
|
|
344
|
+
//# sourceMappingURL=controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controller.js","sourceRoot":"","sources":["../src/controller.ts"],"names":[],"mappings":"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"}
|
package/dist/events.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Native → JS event channel for the Updates module (same GlobalEventEmitter
|
|
3
|
+
* pattern as `@sigx/lynx-background`'s `__sigxBackgroundFire`).
|
|
4
|
+
*
|
|
5
|
+
* Wire shape:
|
|
6
|
+
* { kind: 'progress', receivedBytes: number, totalBytes: number | null }
|
|
7
|
+
* { kind: 'foreground' }
|
|
8
|
+
*/
|
|
9
|
+
export type NativeUpdatesEvent = {
|
|
10
|
+
kind: 'progress';
|
|
11
|
+
receivedBytes: number;
|
|
12
|
+
totalBytes: number | null;
|
|
13
|
+
} | {
|
|
14
|
+
kind: 'foreground';
|
|
15
|
+
};
|
|
16
|
+
export declare function addNativeUpdatesListener(cb: (event: NativeUpdatesEvent) => void): () => void;
|
|
17
|
+
export declare const __EVENT_CHANNEL_FOR_TESTS = "__sigxUpdatesEvent";
|
|
18
|
+
//# sourceMappingURL=events.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../src/events.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,MAAM,kBAAkB,GACxB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,aAAa,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,GACtE;IAAE,IAAI,EAAE,YAAY,CAAA;CAAE,CAAC;AAwC7B,wBAAgB,wBAAwB,CACpC,EAAE,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,IAAI,GACxC,MAAM,IAAI,CAiBZ;AAED,eAAO,MAAM,yBAAyB,uBAAgB,CAAC"}
|