ubriot-updates-rn 0.1.0 → 0.1.4
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.
|
@@ -23,6 +23,7 @@ class UbriotUpdateState(
|
|
|
23
23
|
var pending: UbriotUpdateEntry? = null,
|
|
24
24
|
var lastKnownGood: UbriotUpdateEntry? = null,
|
|
25
25
|
var launchCount: Int = 0,
|
|
26
|
+
var revertedFromId: String? = null,
|
|
26
27
|
)
|
|
27
28
|
|
|
28
29
|
class UbriotUpdatesModule(
|
|
@@ -124,6 +125,18 @@ class UbriotUpdatesModule(
|
|
|
124
125
|
}
|
|
125
126
|
}
|
|
126
127
|
|
|
128
|
+
@ReactMethod
|
|
129
|
+
fun clearRevertedFrom(promise: Promise) {
|
|
130
|
+
try {
|
|
131
|
+
val state = readState(filesDir())
|
|
132
|
+
state.revertedFromId = null
|
|
133
|
+
writeState(filesDir(), state)
|
|
134
|
+
promise.resolve(null)
|
|
135
|
+
} catch (error: Throwable) {
|
|
136
|
+
promise.reject("ubriot_updates_clear_reverted_failed", error)
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
127
140
|
@ReactMethod
|
|
128
141
|
fun reload(promise: Promise) {
|
|
129
142
|
try {
|
|
@@ -150,6 +163,7 @@ class UbriotUpdatesModule(
|
|
|
150
163
|
map.putMap("pending", entryToWritableMap(state.pending))
|
|
151
164
|
map.putMap("lastKnownGood", entryToWritableMap(state.lastKnownGood))
|
|
152
165
|
map.putInt("launchCount", state.launchCount)
|
|
166
|
+
map.putString("revertedFromId", state.revertedFromId)
|
|
153
167
|
return map
|
|
154
168
|
}
|
|
155
169
|
|
|
@@ -200,6 +214,7 @@ class UbriotUpdatesModule(
|
|
|
200
214
|
pending = entryFromJson(json.optJSONObject("pending")),
|
|
201
215
|
lastKnownGood = entryFromJson(json.optJSONObject("lastKnownGood")),
|
|
202
216
|
launchCount = json.optInt("launchCount", 0),
|
|
217
|
+
revertedFromId = json.optString("revertedFromId", "").ifEmpty { null },
|
|
203
218
|
)
|
|
204
219
|
} catch (_: Throwable) {
|
|
205
220
|
UbriotUpdateState()
|
|
@@ -218,6 +233,7 @@ class UbriotUpdatesModule(
|
|
|
218
233
|
.put("pending", entryToJson(state.pending))
|
|
219
234
|
.put("lastKnownGood", entryToJson(state.lastKnownGood))
|
|
220
235
|
.put("launchCount", state.launchCount)
|
|
236
|
+
.put("revertedFromId", state.revertedFromId ?: JSONObject.NULL)
|
|
221
237
|
stateFile(filesDir).writeText(json.toString())
|
|
222
238
|
} catch (_: Throwable) {
|
|
223
239
|
}
|
|
@@ -241,6 +257,7 @@ class UbriotUpdatesModule(
|
|
|
241
257
|
writeState(filesDir, state)
|
|
242
258
|
return active.bundlePath
|
|
243
259
|
}
|
|
260
|
+
state.revertedFromId = active.id
|
|
244
261
|
state.active = null
|
|
245
262
|
state.verified = false
|
|
246
263
|
state.launchCount = 0
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ export type ApplyOptions = {
|
|
|
15
15
|
restart?: boolean;
|
|
16
16
|
};
|
|
17
17
|
export type SyncResult = "up-to-date" | "updated";
|
|
18
|
+
export type LaunchOutcome = "launched" | "crashed";
|
|
18
19
|
export declare function configure(next: UbriotUpdatesConfig): void;
|
|
19
20
|
export declare function checkForUpdate(): Promise<UpdateCheckResult>;
|
|
20
21
|
export declare function downloadUpdate(): Promise<DownloadResult>;
|
package/dist/index.js
CHANGED
|
@@ -8,6 +8,7 @@ exports.sync = sync;
|
|
|
8
8
|
exports.markLaunchSuccessful = markLaunchSuccessful;
|
|
9
9
|
const react_native_1 = require("react-native");
|
|
10
10
|
const MANIFEST_PATH = "/ubriot/updates/manifest";
|
|
11
|
+
const LAUNCH_PATH = "/ubriot/updates/launch";
|
|
11
12
|
let config = null;
|
|
12
13
|
let stagedManifest = null;
|
|
13
14
|
function getNativeModule() {
|
|
@@ -32,6 +33,60 @@ function normalizeBase(apiBase) {
|
|
|
32
33
|
async function verifyManifestSignature(_manifest) {
|
|
33
34
|
return true;
|
|
34
35
|
}
|
|
36
|
+
function reportLaunch(outcome, updateId) {
|
|
37
|
+
try {
|
|
38
|
+
if (!config)
|
|
39
|
+
return;
|
|
40
|
+
if (!updateId)
|
|
41
|
+
return;
|
|
42
|
+
const cfg = config;
|
|
43
|
+
const payload = JSON.stringify({
|
|
44
|
+
appId: cfg.appSlug,
|
|
45
|
+
channel: cfg.channel,
|
|
46
|
+
updateId,
|
|
47
|
+
platform: currentPlatform(),
|
|
48
|
+
outcome,
|
|
49
|
+
});
|
|
50
|
+
void fetch(`${cfg.apiBase}${LAUNCH_PATH}`, {
|
|
51
|
+
method: "POST",
|
|
52
|
+
headers: { "content-type": "application/json" },
|
|
53
|
+
body: payload,
|
|
54
|
+
}).catch(() => { });
|
|
55
|
+
}
|
|
56
|
+
catch { }
|
|
57
|
+
}
|
|
58
|
+
function reportRevertIfCrashed() {
|
|
59
|
+
try {
|
|
60
|
+
const native = react_native_1.NativeModules.UbriotUpdates;
|
|
61
|
+
if (!native || typeof native.getState !== "function")
|
|
62
|
+
return;
|
|
63
|
+
native
|
|
64
|
+
.getState()
|
|
65
|
+
.then((state) => {
|
|
66
|
+
var _a, _b, _c, _d, _e, _f;
|
|
67
|
+
try {
|
|
68
|
+
if (!state)
|
|
69
|
+
return;
|
|
70
|
+
const revertedFromId = (_c = (_b = (_a = state.revertedFromId) !== null && _a !== void 0 ? _a : state.failedUpdateId) !== null && _b !== void 0 ? _b : state.lastRevertedId) !== null && _c !== void 0 ? _c : null;
|
|
71
|
+
if (!revertedFromId)
|
|
72
|
+
return;
|
|
73
|
+
const survivingId = (_f = (_d = state.runningId) !== null && _d !== void 0 ? _d : (_e = state.active) === null || _e === void 0 ? void 0 : _e.id) !== null && _f !== void 0 ? _f : null;
|
|
74
|
+
if (revertedFromId === survivingId)
|
|
75
|
+
return;
|
|
76
|
+
reportLaunch("crashed", revertedFromId);
|
|
77
|
+
try {
|
|
78
|
+
if (typeof native.clearRevertedFrom === "function") {
|
|
79
|
+
native.clearRevertedFrom().catch(() => { });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
catch { }
|
|
83
|
+
}
|
|
84
|
+
catch { }
|
|
85
|
+
})
|
|
86
|
+
.catch(() => { });
|
|
87
|
+
}
|
|
88
|
+
catch { }
|
|
89
|
+
}
|
|
35
90
|
function configure(next) {
|
|
36
91
|
config = {
|
|
37
92
|
apiBase: normalizeBase(next.apiBase),
|
|
@@ -39,6 +94,7 @@ function configure(next) {
|
|
|
39
94
|
channel: next.channel,
|
|
40
95
|
runtimeVersion: next.runtimeVersion,
|
|
41
96
|
};
|
|
97
|
+
reportRevertIfCrashed();
|
|
42
98
|
}
|
|
43
99
|
async function checkForUpdate() {
|
|
44
100
|
var _a, _b, _c, _d;
|
|
@@ -150,6 +206,10 @@ function markLaunchSuccessful() {
|
|
|
150
206
|
const native = react_native_1.NativeModules.UbriotUpdates;
|
|
151
207
|
if (native && typeof native.markLaunchSuccessful === "function") {
|
|
152
208
|
native.markLaunchSuccessful().catch(() => { });
|
|
209
|
+
native
|
|
210
|
+
.getState()
|
|
211
|
+
.then((state) => { var _a, _b, _c; return reportLaunch("launched", (_c = (_a = state === null || state === void 0 ? void 0 : state.runningId) !== null && _a !== void 0 ? _a : (_b = state === null || state === void 0 ? void 0 : state.active) === null || _b === void 0 ? void 0 : _b.id) !== null && _c !== void 0 ? _c : null); })
|
|
212
|
+
.catch(() => { });
|
|
153
213
|
}
|
|
154
214
|
}
|
|
155
215
|
catch {
|
package/ios/UbriotUpdates.m
CHANGED
|
@@ -36,6 +36,7 @@ RCT_EXPORT_MODULE();
|
|
|
36
36
|
@"pending": [NSNull null],
|
|
37
37
|
@"lastKnownGood": [NSNull null],
|
|
38
38
|
@"launchCount": @0,
|
|
39
|
+
@"revertedFromId": [NSNull null],
|
|
39
40
|
} mutableCopy];
|
|
40
41
|
}
|
|
41
42
|
|
|
@@ -94,6 +95,7 @@ RCT_EXPORT_MODULE();
|
|
|
94
95
|
[self writeState:state];
|
|
95
96
|
return [NSURL fileURLWithPath:path];
|
|
96
97
|
}
|
|
98
|
+
state[@"revertedFromId"] = activeId ?: [NSNull null];
|
|
97
99
|
state[@"active"] = [NSNull null];
|
|
98
100
|
state[@"verified"] = @NO;
|
|
99
101
|
state[@"launchCount"] = @0;
|
|
@@ -214,6 +216,17 @@ RCT_EXPORT_METHOD(markLaunchSuccessful:(RCTPromiseResolveBlock)resolve rejecter:
|
|
|
214
216
|
}
|
|
215
217
|
}
|
|
216
218
|
|
|
219
|
+
RCT_EXPORT_METHOD(clearRevertedFrom:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
|
|
220
|
+
@try {
|
|
221
|
+
NSMutableDictionary *state = [UbriotUpdates readState];
|
|
222
|
+
state[@"revertedFromId"] = [NSNull null];
|
|
223
|
+
[UbriotUpdates writeState:state];
|
|
224
|
+
resolve(nil);
|
|
225
|
+
} @catch (NSException *exception) {
|
|
226
|
+
reject(@"ubriot_updates_clear_reverted_failed", exception.reason, nil);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
217
230
|
RCT_EXPORT_METHOD(reload:(RCTPromiseResolveBlock)resolve rejecter:(RCTPromiseRejectBlock)reject) {
|
|
218
231
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
219
232
|
@try {
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -34,14 +34,20 @@ type NativeState = {
|
|
|
34
34
|
pending: NativeEntry;
|
|
35
35
|
lastKnownGood: NativeEntry;
|
|
36
36
|
launchCount: number;
|
|
37
|
+
revertedFromId?: string | null;
|
|
38
|
+
failedUpdateId?: string | null;
|
|
39
|
+
lastRevertedId?: string | null;
|
|
37
40
|
};
|
|
38
41
|
|
|
42
|
+
export type LaunchOutcome = "launched" | "crashed";
|
|
43
|
+
|
|
39
44
|
type NativeUbriotUpdates = {
|
|
40
45
|
getState(): Promise<NativeState>;
|
|
41
46
|
downloadBundle(url: string, manifestId: string): Promise<{ ready: boolean; bundlePath: string }>;
|
|
42
47
|
applyPending(): Promise<void>;
|
|
43
48
|
markLaunchSuccessful(): Promise<void>;
|
|
44
49
|
reload(): Promise<void>;
|
|
50
|
+
clearRevertedFrom?(): Promise<void>;
|
|
45
51
|
};
|
|
46
52
|
|
|
47
53
|
type LaunchManifest = {
|
|
@@ -50,6 +56,7 @@ type LaunchManifest = {
|
|
|
50
56
|
};
|
|
51
57
|
|
|
52
58
|
const MANIFEST_PATH = "/ubriot/updates/manifest";
|
|
59
|
+
const LAUNCH_PATH = "/ubriot/updates/launch";
|
|
53
60
|
|
|
54
61
|
let config: UbriotUpdatesConfig | null = null;
|
|
55
62
|
let stagedManifest: LaunchManifest | null = null;
|
|
@@ -81,6 +88,52 @@ async function verifyManifestSignature(_manifest: unknown): Promise<boolean> {
|
|
|
81
88
|
return true;
|
|
82
89
|
}
|
|
83
90
|
|
|
91
|
+
function reportLaunch(outcome: LaunchOutcome, updateId: string | null | undefined): void {
|
|
92
|
+
try {
|
|
93
|
+
if (!config) return;
|
|
94
|
+
if (!updateId) return;
|
|
95
|
+
const cfg = config;
|
|
96
|
+
const payload = JSON.stringify({
|
|
97
|
+
appId: cfg.appSlug,
|
|
98
|
+
channel: cfg.channel,
|
|
99
|
+
updateId,
|
|
100
|
+
platform: currentPlatform(),
|
|
101
|
+
outcome,
|
|
102
|
+
});
|
|
103
|
+
void fetch(`${cfg.apiBase}${LAUNCH_PATH}`, {
|
|
104
|
+
method: "POST",
|
|
105
|
+
headers: { "content-type": "application/json" },
|
|
106
|
+
body: payload,
|
|
107
|
+
}).catch(() => {});
|
|
108
|
+
} catch {}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function reportRevertIfCrashed(): void {
|
|
112
|
+
try {
|
|
113
|
+
const native = NativeModules.UbriotUpdates as NativeUbriotUpdates | undefined;
|
|
114
|
+
if (!native || typeof native.getState !== "function") return;
|
|
115
|
+
native
|
|
116
|
+
.getState()
|
|
117
|
+
.then((state) => {
|
|
118
|
+
try {
|
|
119
|
+
if (!state) return;
|
|
120
|
+
const revertedFromId =
|
|
121
|
+
state.revertedFromId ?? state.failedUpdateId ?? state.lastRevertedId ?? null;
|
|
122
|
+
if (!revertedFromId) return;
|
|
123
|
+
const survivingId = state.runningId ?? state.active?.id ?? null;
|
|
124
|
+
if (revertedFromId === survivingId) return;
|
|
125
|
+
reportLaunch("crashed", revertedFromId);
|
|
126
|
+
try {
|
|
127
|
+
if (typeof native.clearRevertedFrom === "function") {
|
|
128
|
+
native.clearRevertedFrom().catch(() => {});
|
|
129
|
+
}
|
|
130
|
+
} catch {}
|
|
131
|
+
} catch {}
|
|
132
|
+
})
|
|
133
|
+
.catch(() => {});
|
|
134
|
+
} catch {}
|
|
135
|
+
}
|
|
136
|
+
|
|
84
137
|
export function configure(next: UbriotUpdatesConfig): void {
|
|
85
138
|
config = {
|
|
86
139
|
apiBase: normalizeBase(next.apiBase),
|
|
@@ -88,6 +141,7 @@ export function configure(next: UbriotUpdatesConfig): void {
|
|
|
88
141
|
channel: next.channel,
|
|
89
142
|
runtimeVersion: next.runtimeVersion,
|
|
90
143
|
};
|
|
144
|
+
reportRevertIfCrashed();
|
|
91
145
|
}
|
|
92
146
|
|
|
93
147
|
export async function checkForUpdate(): Promise<UpdateCheckResult> {
|
|
@@ -211,6 +265,10 @@ export function markLaunchSuccessful(): void {
|
|
|
211
265
|
const native = NativeModules.UbriotUpdates as NativeUbriotUpdates | undefined;
|
|
212
266
|
if (native && typeof native.markLaunchSuccessful === "function") {
|
|
213
267
|
native.markLaunchSuccessful().catch(() => {});
|
|
268
|
+
native
|
|
269
|
+
.getState()
|
|
270
|
+
.then((state) => reportLaunch("launched", state?.runningId ?? state?.active?.id ?? null))
|
|
271
|
+
.catch(() => {});
|
|
214
272
|
}
|
|
215
273
|
} catch {
|
|
216
274
|
// never allow launch bookkeeping to crash the host app
|