react-native-update 10.59.2 → 10.60.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.
Files changed (125) hide show
  1. package/README-CN.md +7 -7
  2. package/README.md +7 -6
  3. package/android/build.gradle +25 -33
  4. package/android/jni/Android.mk +16 -24
  5. package/android/lib/arm64-v8a/librnpushy.so +0 -0
  6. package/android/lib/armeabi-v7a/librnpushy.so +0 -0
  7. package/android/lib/x86/librnpushy.so +0 -0
  8. package/android/lib/x86_64/librnpushy.so +0 -0
  9. package/android/proguard.pro +9 -7
  10. package/android/src/main/java/cn/reactnative/modules/update/ApkInstaller.java +2 -7
  11. package/android/src/main/java/cn/reactnative/modules/update/ArchiveLimits.java +23 -6
  12. package/android/src/main/java/cn/reactnative/modules/update/BundledResourceCopier.java +50 -51
  13. package/android/src/main/java/cn/reactnative/modules/update/CleanupKeepNames.java +12 -13
  14. package/android/src/main/java/cn/reactnative/modules/update/CopyGroupResult.java +3 -0
  15. package/android/src/main/java/cn/reactnative/modules/update/CrashHold.java +22 -30
  16. package/android/src/main/java/cn/reactnative/modules/update/DownloadTask.java +181 -332
  17. package/android/src/main/java/cn/reactnative/modules/update/DownloadTaskParams.java +3 -1
  18. package/android/src/main/java/cn/reactnative/modules/update/ErrorCodes.java +27 -0
  19. package/android/src/main/java/cn/reactnative/modules/update/FileOperationException.java +1 -1
  20. package/android/src/main/java/cn/reactnative/modules/update/FlowBridge.java +32 -8
  21. package/android/src/main/java/cn/reactnative/modules/update/HttpClients.java +63 -0
  22. package/android/src/main/java/cn/reactnative/modules/update/HttpUtils.java +0 -11
  23. package/android/src/main/java/cn/reactnative/modules/update/InstallRecord.java +66 -116
  24. package/android/src/main/java/cn/reactnative/modules/update/NativeCore.java +9 -1
  25. package/android/src/main/java/cn/reactnative/modules/update/PatchFailedException.java +1 -1
  26. package/android/src/main/java/cn/reactnative/modules/update/PushyRuntime.java +32 -60
  27. package/android/src/main/java/cn/reactnative/modules/update/ReactReloadManager.java +8 -23
  28. package/android/src/main/java/cn/reactnative/modules/update/SafeZipFile.java +42 -80
  29. package/android/src/main/java/cn/reactnative/modules/update/StateSerialRunner.java +22 -39
  30. package/android/src/main/java/cn/reactnative/modules/update/SyncCoordinator.java +176 -299
  31. package/android/src/main/java/cn/reactnative/modules/update/Threads.java +35 -0
  32. package/android/src/main/java/cn/reactnative/modules/update/UpdateContext.java +242 -174
  33. package/android/src/main/java/cn/reactnative/modules/update/UpdateEventEmitter.java +1 -1
  34. package/android/src/main/java/cn/reactnative/modules/update/UpdateFileUtils.java +75 -17
  35. package/android/src/main/java/cn/reactnative/modules/update/{UpdateModuleImpl.java → UpdateModule.java} +113 -95
  36. package/android/src/main/java/cn/reactnative/modules/update/UpdatePackage.java +16 -19
  37. package/android/src/oldarch/cn/reactnative/modules/update/NativePushySpec.java +69 -0
  38. package/cpp/android_jni/archive_limits_jni.cpp +83 -0
  39. package/cpp/android_jni/install_record_jni.cpp +89 -0
  40. package/cpp/android_jni/jni_log.h +31 -0
  41. package/cpp/android_jni/jni_natives.h +40 -0
  42. package/cpp/android_jni/jni_registration.cpp +133 -0
  43. package/cpp/android_jni/jni_util.h +160 -0
  44. package/cpp/android_jni/update_core_android.cpp +450 -0
  45. package/cpp/android_jni/update_flow_jni.cpp +133 -0
  46. package/{android/jni → cpp/hpatch}/hpatch.c +5 -5
  47. package/{android/jni → cpp/hpatch}/hpatch.h +4 -1
  48. package/cpp/patch_core/archive_limits.cpp +194 -0
  49. package/cpp/patch_core/archive_limits.h +99 -10
  50. package/cpp/patch_core/archive_patch_core.cpp +96 -12
  51. package/cpp/patch_core/archive_patch_core.h +49 -0
  52. package/cpp/patch_core/digest.h +5 -4
  53. package/cpp/patch_core/error_codes.h +5 -3
  54. package/cpp/patch_core/install_record.cpp +430 -0
  55. package/cpp/patch_core/install_record.h +163 -9
  56. package/cpp/patch_core/patch_core.cpp +62 -16
  57. package/cpp/patch_core/patch_core.h +27 -7
  58. package/cpp/patch_core/patch_manifest.cpp +201 -0
  59. package/cpp/patch_core/patch_manifest.h +74 -0
  60. package/cpp/patch_core/state_ops.h +3 -3
  61. package/cpp/update_flow_core/flow_json.cpp +82 -8
  62. package/cpp/update_flow_core/flow_json.h +21 -0
  63. package/cpp/update_flow_core/native_config.cpp +456 -0
  64. package/cpp/update_flow_core/native_config.h +84 -0
  65. package/cpp/update_flow_core/native_round.cpp +326 -0
  66. package/cpp/update_flow_core/native_round.h +90 -0
  67. package/cpp/update_flow_core/update_flow_core.h +2 -2
  68. package/harmony/hvigor-plugin.ts +11 -19
  69. package/harmony/pushy/src/main/cpp/CMakeLists.txt +17 -26
  70. package/harmony/pushy/src/main/cpp/PushyPackage.h +2 -2
  71. package/harmony/pushy/src/main/cpp/PushyTurboModule.cpp +55 -94
  72. package/harmony/pushy/src/main/cpp/pushy.cpp +694 -517
  73. package/harmony/pushy/src/main/ets/ArchiveLimits.ts +48 -72
  74. package/harmony/pushy/src/main/ets/DownloadTask.ts +164 -404
  75. package/harmony/pushy/src/main/ets/DownloadTaskParams.ts +1 -3
  76. package/harmony/pushy/src/main/ets/ErrorCodes.ts +1 -14
  77. package/harmony/pushy/src/main/ets/EventHub.ts +1 -1
  78. package/harmony/pushy/src/main/ets/InstallRecord.ts +52 -151
  79. package/harmony/pushy/src/main/ets/Logger.ts +20 -34
  80. package/harmony/pushy/src/main/ets/NativePatchCore.ts +116 -42
  81. package/harmony/pushy/src/main/ets/PushyConfiguration.ts +8 -85
  82. package/harmony/pushy/src/main/ets/PushyTurboModule.ts +11 -25
  83. package/harmony/pushy/src/main/ets/SaveFile.ts +99 -18
  84. package/harmony/pushy/src/main/ets/SyncCoordinator.ts +136 -335
  85. package/harmony/pushy/src/main/ets/Texts.ts +0 -4
  86. package/harmony/pushy/src/main/ets/UpdateContext.ts +106 -119
  87. package/harmony/pushy.har +0 -0
  88. package/ios/RCTPushy/RCTPushy+Launch.mm +185 -0
  89. package/ios/RCTPushy/RCTPushy.h +12 -0
  90. package/ios/RCTPushy/RCTPushy.mm +87 -2634
  91. package/ios/RCTPushy/RCTPushyCommon.h +34 -0
  92. package/ios/RCTPushy/RCTPushyConfiguration.h +0 -8
  93. package/ios/RCTPushy/RCTPushyConfiguration.mm +40 -121
  94. package/ios/RCTPushy/RCTPushyDownloader.mm +40 -37
  95. package/ios/RCTPushy/RCTPushyInstallRecord.mm +61 -0
  96. package/ios/RCTPushy/RCTPushyInstaller.mm +689 -0
  97. package/ios/RCTPushy/RCTPushyInternal.h +144 -0
  98. package/ios/RCTPushy/RCTPushyOrchestrator.mm +1001 -0
  99. package/ios/RCTPushy/RCTPushyState.mm +314 -0
  100. package/package.json +25 -23
  101. package/react-native-update.podspec +73 -82
  102. package/src/client.ts +361 -451
  103. package/src/context.ts +1 -1
  104. package/src/core.ts +35 -8
  105. package/src/endpoint.ts +0 -2
  106. package/src/error.ts +13 -32
  107. package/src/i18n.ts +18 -83
  108. package/src/locales/en.ts +0 -4
  109. package/src/locales/zh.ts +0 -4
  110. package/src/provider.tsx +60 -53
  111. package/src/telemetry.ts +0 -13
  112. package/src/type.ts +0 -15
  113. package/src/updateFlowCore.ts +116 -10
  114. package/src/utils.ts +49 -42
  115. package/android/src/main/java/cn/reactnative/modules/update/ArchivePatchPlanResult.java +0 -6
  116. package/android/src/main/java/cn/reactnative/modules/update/PushyConfiguration.java +0 -104
  117. package/android/src/main/java/cn/reactnative/modules/update/UiThreadRunner.java +0 -37
  118. package/android/src/newarch/cn/reactnative/modules/update/UpdateModule.java +0 -121
  119. package/android/src/oldarch/cn/reactnative/modules/update/UpdateModule.java +0 -125
  120. package/cpp/patch_core/jni_natives.h +0 -27
  121. package/cpp/patch_core/jni_registration.cpp +0 -103
  122. package/cpp/patch_core/jni_util.h +0 -60
  123. package/cpp/patch_core/patch_core_android.cpp +0 -97
  124. package/cpp/patch_core/update_core_android.cpp +0 -485
  125. package/cpp/update_flow_core/update_flow_jni.cpp +0 -150
@@ -0,0 +1,326 @@
1
+ #include "native_round.h"
2
+
3
+ #include <cmath>
4
+ #include <utility>
5
+
6
+ #include "../patch_core/hbc_transform_wire.h"
7
+ #include "../patch_core/obscured_text.h"
8
+ #include "native_config.h"
9
+ #include "update_flow_core.h"
10
+
11
+ namespace flowcore {
12
+
13
+ using flowjson::Value;
14
+
15
+ namespace {
16
+
17
+ // Stored encoded (see obscured_text.h).
18
+ const std::string& QueryPath() {
19
+ static const std::string value = pushy::text::Reveal("7514fcd4ad805d55263e08fc99");
20
+ return value;
21
+ }
22
+ const std::string& InfoForceBoot() {
23
+ static const std::string value =
24
+ pushy::text::Reveal("3c18e6d2aba9674a360d19ead5a695");
25
+ return value;
26
+ }
27
+
28
+ // The lists NextQueryStep walks, in order; the state's "list" names the
29
+ // current one ("" once the query is over).
30
+ const char kEndpoints[] = "endpoints";
31
+ const char kQueryUrls[] = "queryUrls";
32
+ const char kRemote[] = "remote";
33
+
34
+ bool HasPrefixIgnoringAsciiCase(const std::string& text, const char* prefix) {
35
+ size_t i = 0;
36
+ for (; prefix[i] != '\0'; i++) {
37
+ if (i >= text.size()) {
38
+ return false;
39
+ }
40
+ char c = text[i];
41
+ if (c >= 'A' && c <= 'Z') {
42
+ c = static_cast<char>(c - 'A' + 'a');
43
+ }
44
+ if (c != prefix[i]) {
45
+ return false;
46
+ }
47
+ }
48
+ return true;
49
+ }
50
+
51
+ bool IsHttpsUrl(const std::string& url) {
52
+ return HasPrefixIgnoringAsciiCase(url, "https://");
53
+ }
54
+
55
+ bool IsCleartextUrl(const std::string& url) {
56
+ return HasPrefixIgnoringAsciiCase(url, "http://");
57
+ }
58
+
59
+ std::string StripTrailingSlashes(std::string url) {
60
+ while (!url.empty() && url.back() == '/') {
61
+ url.pop_back();
62
+ }
63
+ return url;
64
+ }
65
+
66
+ Value StringOr(const Value& value, const char* fallback) {
67
+ return value.IsString() ? value : Value::String(fallback);
68
+ }
69
+
70
+ // A non-negative integral state counter; anything else reads as 0.
71
+ size_t Counter(const Value& value) {
72
+ const double number = value.AsNumber();
73
+ if (!value.IsNumber() || !std::isfinite(number) || number < 0) {
74
+ return 0;
75
+ }
76
+ return number >= 1e15 ? static_cast<size_t>(1e15)
77
+ : static_cast<size_t>(number);
78
+ }
79
+
80
+ // { packageVersion, currentVersion, uuid, rolledBackVersion } — what
81
+ // HandleResponse keys its decision on.
82
+ Value Identity(const Value& config, const Value& env) {
83
+ const Value& configured = config.Get("packageVersion");
84
+ Value identity = Value::Object();
85
+ identity.Set("packageVersion",
86
+ configured.IsString() && !configured.AsString().empty()
87
+ ? configured
88
+ : env.Get("packageVersion"));
89
+ identity.Set("currentVersion", env.Get("currentVersion"));
90
+ identity.Set("uuid", StringOr(env.Get("uuid"), ""));
91
+ identity.Set("rolledBackVersion", env.Get("rolledBackVersion"));
92
+ return identity;
93
+ }
94
+
95
+ std::string RequestBody(const Value& config, const Value& env) {
96
+ const Value identity = Identity(config, env);
97
+ Value cInfo = Value::Object();
98
+ cInfo.Set("rnu", StringOr(config.Get("rnu"), ""));
99
+ cInfo.Set("rn", StringOr(config.Get("rn"), ""));
100
+ cInfo.Set("os", env.Get("os"));
101
+ cInfo.Set("uuid", identity.Get("uuid"));
102
+ Value input = Value::Object();
103
+ input.Set("packageVersion", identity.Get("packageVersion"));
104
+ input.Set("currentVersion", env.Get("currentVersion"));
105
+ input.Set("buildTime", env.Get("buildTime"));
106
+ input.Set("cInfo", std::move(cInfo));
107
+ input.Set("supportedDiffVersion",
108
+ Value::Number(pushy::hbc::kSupportedDiffVersion));
109
+ input.Set("bundleHash", env.Get("bundleHash"));
110
+ return flowjson::Stringify(BuildRequestBody(input));
111
+ }
112
+
113
+ bool Contains(const Value& list, const std::string& text) {
114
+ for (const Value& entry : list.elements()) {
115
+ if (entry.AsString() == text) {
116
+ return true;
117
+ }
118
+ }
119
+ return false;
120
+ }
121
+
122
+ Value PlanAttempts(const Value& attempts, bool hasOrigin, bool httpsOnly) {
123
+ Value planned = Value::Array();
124
+ for (const Value& attempt : attempts.elements()) {
125
+ // diff patches the running version; with none running it cannot apply.
126
+ if (attempt.Get("type").AsString() == "diff" && !hasOrigin) {
127
+ continue;
128
+ }
129
+ Value urls = Value::Array();
130
+ for (const Value& url : attempt.Get("urls").elements()) {
131
+ if (url.IsString() && !url.AsString().empty() &&
132
+ !(httpsOnly && IsCleartextUrl(url.AsString()))) {
133
+ urls.Push(url);
134
+ }
135
+ }
136
+ if (urls.Size() > 0) {
137
+ Value kept = Value::Object();
138
+ kept.Set("type", attempt.Get("type"));
139
+ kept.Set("urls", std::move(urls));
140
+ planned.Push(std::move(kept));
141
+ }
142
+ }
143
+ return planned;
144
+ }
145
+
146
+ Value VersionInfo(const Value& info) {
147
+ Value hashInfo = Value::Object();
148
+ for (const char* key : {"name", "description", "metaInfo"}) {
149
+ if (info.Get(key).IsString()) {
150
+ hashInfo.Set(key, info.Get(key));
151
+ }
152
+ }
153
+ // A forceBoot activation is the brick-rescue path: JS reports it once
154
+ // this version survives to markSuccess. Only the server's directive counts
155
+ // — a silent-strategy activation is ordinary delivery.
156
+ if (info.Get("config").Get("forceBoot").Truthy()) {
157
+ hashInfo.Set(InfoForceBoot(), Value::Bool(true));
158
+ }
159
+ return hashInfo;
160
+ }
161
+
162
+ } // namespace
163
+
164
+ bool IsHttpsOnly(const Value& endpoints) {
165
+ if (endpoints.elements().empty()) {
166
+ return false;
167
+ }
168
+ for (const Value& endpoint : endpoints.elements()) {
169
+ if (!endpoint.IsString() || !IsHttpsUrl(endpoint.AsString())) {
170
+ return false;
171
+ }
172
+ }
173
+ return true;
174
+ }
175
+
176
+ Value PrepareRound(const std::string& configJson, const Value& env,
177
+ double randomSample) {
178
+ RunnableConfig gate = ParseRunnableConfig(configJson);
179
+ if (!gate.runnable() || !env.IsObject()) {
180
+ return Value::Undefined();
181
+ }
182
+ const Value& config = gate.config;
183
+ const Value& queryUrls = config.Get(kQueryUrls);
184
+ Value query = Value::Object();
185
+ query.Set("appKey", Value::String(gate.appKey));
186
+ query.Set("httpsOnly", Value::Bool(IsHttpsOnly(config.Get(kEndpoints))));
187
+ query.Set(kEndpoints,
188
+ OrderEndpointCandidates(config.Get(kEndpoints), randomSample));
189
+ query.Set(kQueryUrls, queryUrls.IsArray() ? queryUrls : Value::Array());
190
+ query.Set("list", Value::String(kEndpoints));
191
+ query.Set("next", Value::Number(0));
192
+ query.Set("tried", Value::Array());
193
+ query.Set("spent", Value::Number(0));
194
+
195
+ Value round = Value::Object();
196
+ round.Set("body", Value::String(RequestBody(config, env)));
197
+ round.Set("query", std::move(query));
198
+ return round;
199
+ }
200
+
201
+ Value NextQueryStep(const Value& previous, const Value& responseText) {
202
+ if (!previous.IsObject()) {
203
+ return Value::Undefined();
204
+ }
205
+ Value state = previous;
206
+ if (state.Get("url").IsString()) {
207
+ const bool post = state.Get("post").Truthy();
208
+ state.Remove("url");
209
+ state.Remove("post");
210
+ if (responseText.IsString()) {
211
+ if (post && IsValidResponse(responseText.AsString())) {
212
+ state.Set("found", Value::Bool(true));
213
+ } else if (!post) {
214
+ bool ok = false;
215
+ Value remote = flowjson::Parse(responseText.AsString(), &ok);
216
+ if (ok && remote.IsArray()) {
217
+ state.Set("list", Value::String(kRemote));
218
+ state.Set(kRemote, std::move(remote));
219
+ state.Set("next", Value::Number(0));
220
+ }
221
+ }
222
+ }
223
+ }
224
+ if (state.Get("found").Truthy()) {
225
+ return state;
226
+ }
227
+ const bool httpsOnly = state.Get("httpsOnly").Truthy();
228
+ for (;;) {
229
+ const std::string list = state.Get("list").AsString();
230
+ if (list != kEndpoints && list != kQueryUrls && list != kRemote) {
231
+ state.Set("list", Value::String(""));
232
+ return state;
233
+ }
234
+ const bool isListOfLists = list == kQueryUrls;
235
+ const Value& entries = state.Get(list);
236
+ size_t next = Counter(state.Get("next"));
237
+ std::string target;
238
+ while (target.empty() && next < entries.Size()) {
239
+ const Value& entry = entries.At(next++);
240
+ if (!entry.IsString()) {
241
+ continue;
242
+ }
243
+ if (isListOfLists) {
244
+ target = entry.AsString();
245
+ continue;
246
+ }
247
+ std::string base = StripTrailingSlashes(entry.AsString());
248
+ if (base.empty() || Contains(state.Get("tried"), base)) {
249
+ continue;
250
+ }
251
+ // A remotely injected endpoint must not downgrade an https
252
+ // configuration to plaintext.
253
+ if (list == kRemote && httpsOnly && !IsHttpsUrl(base)) {
254
+ continue;
255
+ }
256
+ target = std::move(base);
257
+ }
258
+ state.Set("next", Value::Number(static_cast<double>(next)));
259
+ if (target.empty()) {
260
+ // The configured endpoints are followed by the list discovery; a
261
+ // fetched remote list (or running out of lists) ends the query.
262
+ state.Set("list", Value::String(list == kEndpoints ? kQueryUrls : ""));
263
+ state.Set("next", Value::Number(0));
264
+ continue;
265
+ }
266
+ const size_t spent = Counter(state.Get("spent"));
267
+ if (spent >= static_cast<size_t>(kMaxQueryRequests)) {
268
+ state.Set("list", Value::String(""));
269
+ return state;
270
+ }
271
+ state.Set("spent", Value::Number(static_cast<double>(spent + 1)));
272
+ if (isListOfLists) {
273
+ state.Set("url", Value::String(target));
274
+ state.Set("post", Value::Bool(false));
275
+ } else {
276
+ Value tried = state.Get("tried").IsArray() ? state.Get("tried")
277
+ : Value::Array();
278
+ tried.Push(Value::String(target));
279
+ state.Set("tried", std::move(tried));
280
+ state.Set("url", Value::String(target + QueryPath() +
281
+ state.Get("appKey").AsString()));
282
+ state.Set("post", Value::Bool(true));
283
+ }
284
+ return state;
285
+ }
286
+ }
287
+
288
+ Value HandleRoundResponse(const std::string& responseText,
289
+ const std::string& configJson, const Value& env,
290
+ const std::string& requestBody,
291
+ double responseAtSeconds) {
292
+ bool ok = false;
293
+ const Value config = flowjson::Parse(configJson, &ok);
294
+ if (!ok || !config.IsObject() || !env.IsObject()) {
295
+ return Value::Undefined();
296
+ }
297
+ const Value& afterDownload = config.Get("afterDownload");
298
+ const Value decision = HandleResponse(
299
+ responseText, Identity(config, env), false,
300
+ afterDownload.IsString() ? afterDownload.AsString() : std::string());
301
+
302
+ Value round = Value::Object();
303
+ round.Set("action", decision.Get("action"));
304
+ if (decision.Get("action").AsString() == "download") {
305
+ round.Set("hash", decision.Get("hash"));
306
+ round.Set("attempts",
307
+ PlanAttempts(decision.Get("attempts"),
308
+ env.Get("currentVersion").Truthy(),
309
+ IsHttpsOnly(config.Get(kEndpoints))));
310
+ round.Set("activate", decision.Get("activate"));
311
+ round.Set("hashInfo", VersionInfo(decision.Get("info")));
312
+ } else {
313
+ round.Set("reason", decision.Get("reason"));
314
+ }
315
+ // Scoped to the exact request and config that produced the response (§10.3);
316
+ // freshness is anchored to the response's arrival.
317
+ Value cache = Value::Object();
318
+ cache.Set("ts", Value::Number(responseAtSeconds));
319
+ cache.Set("body", Value::String(responseText));
320
+ cache.Set("request", Value::String(requestBody));
321
+ cache.Set("config", Value::String(configJson));
322
+ round.Set("cache", Value::String(flowjson::Stringify(cache)));
323
+ return round;
324
+ }
325
+
326
+ } // namespace flowcore
@@ -0,0 +1,90 @@
1
+ #pragma once
2
+
3
+ #include <string>
4
+
5
+ #include "flow_json.h"
6
+
7
+ // The pure steps of the native cold-start round (NATIVE_CHECKUPDATE_DESIGN
8
+ // §10), one implementation for the Android, iOS and Harmony orchestrators:
9
+ // what to send, which endpoint to ask next, and everything a commit needs
10
+ // from the answer. HTTP, timeouts, locks, downloads and persistence stay
11
+ // native. JS has no counterpart (its client builds its own request through
12
+ // src/updateFlowCore.ts buildCheckRequestBody, which BuildRequestBody
13
+ // mirrors); tests/native-round-vectors.json pins this layer.
14
+ //
15
+ // `config` is the persisted config text (already through
16
+ // ParseRunnableConfig). `env` is what the platform knows about this launch,
17
+ // as a JSON object:
18
+ // packageVersion the binary's package version
19
+ // currentVersion the running version exactly as the platform's JS
20
+ // constant reports it (Android null, iOS absent,
21
+ // Harmony "" when none), so the request matches the one
22
+ // JS builds and JS can reuse the response cache
23
+ // uuid missing -> ""
24
+ // rolledBackVersion the launch-path rollback snapshot
25
+ // buildTime passed through
26
+ // os "<platform> <Platform.Version>", as JS cInfo.os
27
+ // bundleHash omitted from the request when empty
28
+ // Keep the core internal to whichever binary links it (see podspec Core).
29
+ #pragma GCC visibility push(hidden)
30
+
31
+ namespace flowcore {
32
+
33
+ // Total HTTP requests one query may issue: endpoint queries and remote list
34
+ // fetches alike.
35
+ constexpr int kMaxQueryRequests = 8;
36
+
37
+ // {"body": "<checkUpdate request text>", "query": <first NextQueryStep
38
+ // state>}. The body is BuildRequestBody over the config and env: a non-empty
39
+ // string config.packageVersion overrides env.packageVersion, cInfo.rnu/rn are
40
+ // the config's strings ("" otherwise), diffV is this core's
41
+ // kSupportedDiffVersion. randomSample ∈ [0, 1) picks the first endpoint
42
+ // (OrderEndpointCandidates). Undefined when the config is not runnable or
43
+ // env is not an object.
44
+ flowjson::Value PrepareRound(const std::string& configJson,
45
+ const flowjson::Value& env, double randomSample);
46
+
47
+ // One step of the sequential endpoint fallback (§5.1). Pass the previous
48
+ // state and the text the request it named returned (Undefined when it failed
49
+ // or none was made). The result is the next state, with
50
+ // "url" (and "post"): issue that request — a POST of the round's body for
51
+ // an endpoint query, a GET for a remote endpoint list — then call again;
52
+ // "found": true: the text just passed in is the valid check response;
53
+ // neither: no endpoint answered; the query is over.
54
+ // Policy: the configured endpoints in sampled order, then the first
55
+ // queryUrls list that fetches and parses as a JSON array, whose entries are
56
+ // queried in turn (one list is enough). Bases are stripped of trailing '/'
57
+ // and asked once each; entries that are not strings are skipped; a remote
58
+ // entry must be https when every configured endpoint is (IsHttpsOnly), so the
59
+ // network cannot downgrade the round. A response counts only when
60
+ // IsValidResponse accepts it. At most kMaxQueryRequests requests. Undefined
61
+ // for a state that is not an object.
62
+ flowjson::Value NextQueryStep(const flowjson::Value& state,
63
+ const flowjson::Value& responseText);
64
+
65
+ // Every configured endpoint is an https URL (ASCII case-insensitive); false
66
+ // for an empty or missing list.
67
+ bool IsHttpsOnly(const flowjson::Value& endpoints);
68
+
69
+ // HandleResponse for the round, plus what each commit needs:
70
+ // {action: "none", reason, cache}
71
+ // {action: "download", hash, attempts, activate, hashInfo, cache}
72
+ // attempts are planned for this device: no diff attempt without a running
73
+ // version (env.currentVersion falsy), no cleartext http:// URL when the
74
+ // config IsHttpsOnly; strategies left without a URL are dropped. hashInfo is
75
+ // the version info to persist next to the download (the JS side's
76
+ // setLocalHashInfo): the info's string name/description/metaInfo, plus
77
+ // forceBootRescue when the server's config.forceBoot is truthy (the same
78
+ // truthiness that activates it). cache is the response-cache text JS reuses
79
+ // ({ts, body, request, config}). afterDownload is the config's string
80
+ // (otherwise ""). Undefined when the config is not a JSON object or env is
81
+ // not an object.
82
+ flowjson::Value HandleRoundResponse(const std::string& responseText,
83
+ const std::string& configJson,
84
+ const flowjson::Value& env,
85
+ const std::string& requestBody,
86
+ double responseAtSeconds);
87
+
88
+ } // namespace flowcore
89
+
90
+ #pragma GCC visibility pop
@@ -81,8 +81,8 @@ bool ShouldActivateAfterDownload(const flowjson::Value& info,
81
81
  const std::string& afterDownload);
82
82
 
83
83
  // Composes Parse → ResolveResult → DecideDownload: one call from the
84
- // raw checkUpdate response text to a download decision, so the platform
85
- // orchestrators contain no decision logic at all. identity is the union of
84
+ // raw checkUpdate response text to a download decision (the native round
85
+ // reaches it through HandleRoundResponse, native_round.h). identity is the union of
86
86
  // both composed functions' needs: { packageVersion, currentVersion?, uuid,
87
87
  // rolledBackVersion? }. afterDownload is the client's persisted activation
88
88
  // policy; a download decision carries `activate` (ShouldActivateAfterDownload
@@ -156,26 +156,18 @@ export function reactNativeUpdatePlugin() {
156
156
  console.log(`Build time written to ${metaFilePath} (${buildMode})`);
157
157
  };
158
158
 
159
- if (typeof safeNode.registerTask === 'function') {
160
- try {
161
- safeNode.registerTask({
162
- name: TASK_NAME,
163
- run: writeMeta,
164
- dependencies: ['default@PreBuild'],
165
- postDependencies: ['default@ProcessResource'],
166
- });
167
- return;
168
- } catch (e) {
169
- console.warn(
170
- `reactNativeUpdatePlugin: task registration failed (${
171
- e instanceof Error ? e.message : String(e)
172
- }), writing meta.json at apply time`,
173
- );
174
- }
159
+ if (typeof safeNode.registerTask !== 'function') {
160
+ throw new Error(
161
+ 'reactNativeUpdatePlugin: this hvigor cannot register build tasks; ' +
162
+ 'apply the plugin from a module hvigorfile with hvigor 5 or later.',
163
+ );
175
164
  }
176
- // Very old hvigor without task registration: keep the previous
177
- // behaviour (write at apply time), still only for assemble builds.
178
- writeMeta();
165
+ safeNode.registerTask({
166
+ name: TASK_NAME,
167
+ run: writeMeta,
168
+ dependencies: ['default@PreBuild'],
169
+ postDependencies: ['default@ProcessResource'],
170
+ });
179
171
  },
180
172
  };
181
173
  }
@@ -7,38 +7,31 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
7
7
 
8
8
  set(CMAKE_VERBOSE_MAKEFILE on)
9
9
 
10
+ # The shared native sources are compiled in place from the repository root
11
+ # (or the npm package root, which ships cpp/ and the android/jni submodules).
10
12
  set(REPO_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../../../)
11
- set(STAGED_NATIVE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/android-generated)
12
- set(ANDROID_JNI_DIR ${REPO_ROOT}/android/jni)
13
- if(NOT EXISTS ${ANDROID_JNI_DIR}/hpatch.c)
14
- set(ANDROID_JNI_DIR ${STAGED_NATIVE_DIR}/jni)
15
- endif()
16
13
  set(PATCH_CORE_DIR ${REPO_ROOT}/cpp/patch_core)
17
- if(NOT EXISTS ${PATCH_CORE_DIR}/patch_core.cpp)
18
- set(PATCH_CORE_DIR ${STAGED_NATIVE_DIR}/patch_core)
19
- endif()
20
14
  set(UPDATE_FLOW_CORE_DIR ${REPO_ROOT}/cpp/update_flow_core)
21
- if(NOT EXISTS ${UPDATE_FLOW_CORE_DIR}/update_flow_core.cpp)
22
- set(UPDATE_FLOW_CORE_DIR ${STAGED_NATIVE_DIR}/update_flow_core)
23
- endif()
15
+ set(HPATCH_DIR ${REPO_ROOT}/cpp/hpatch)
16
+ set(HDIFFPATCH_DIR ${REPO_ROOT}/android/jni/HDiffPatch)
17
+ set(LZMA_DIR ${REPO_ROOT}/android/jni/lzma)
24
18
 
25
19
  # Always compile from source. A prebuilt-import branch used to live here, but
26
20
  # it had no symbol verification: a stale libs/<abi>/librnpushy.so missing a
27
21
  # newly added export (e.g. getSupportedDiffVersion) would silently ship and
28
22
  # crash getConstants at runtime.
29
- set(HDIFFPATCH_DIR ${ANDROID_JNI_DIR}/HDiffPatch)
30
- set(LZMA_DIR ${ANDROID_JNI_DIR}/lzma)
23
+ #
24
+ # The platform-neutral cores are picked up by directory (non-recursive, so
25
+ # tests/ stays out; the Android JNI glue lives in cpp/android_jni), so a new
26
+ # core source needs no edit here. CONFIGURE_DEPENDS re-globs on every build.
27
+ file(GLOB CORE_SOURCES CONFIGURE_DEPENDS
28
+ ${PATCH_CORE_DIR}/*.cpp
29
+ ${UPDATE_FLOW_CORE_DIR}/*.cpp
30
+ ${HPATCH_DIR}/*.c
31
+ )
31
32
  set(HDP_SOURCES
32
33
  ${CMAKE_CURRENT_SOURCE_DIR}/pushy.cpp
33
- ${PATCH_CORE_DIR}/archive_patch_core.cpp
34
- ${PATCH_CORE_DIR}/digest.cpp
35
- ${PATCH_CORE_DIR}/hbc_transform.cpp
36
- ${PATCH_CORE_DIR}/hbc_transform_wire.cpp
37
- ${PATCH_CORE_DIR}/patch_core.cpp
38
- ${PATCH_CORE_DIR}/state_core.cpp
39
- ${UPDATE_FLOW_CORE_DIR}/flow_json.cpp
40
- ${UPDATE_FLOW_CORE_DIR}/update_flow_core.cpp
41
- ${ANDROID_JNI_DIR}/hpatch.c
34
+ ${CORE_SOURCES}
42
35
  ${HDIFFPATCH_DIR}/libHDiffPatch/HPatch/patch.c
43
36
  ${HDIFFPATCH_DIR}/file_for_patch.c
44
37
  ${LZMA_DIR}/C/LzmaDec.c
@@ -49,14 +42,12 @@ add_library(rnpushy SHARED
49
42
  ${HDP_SOURCES}
50
43
  )
51
44
 
45
+ # pushy.cpp includes the cores by name; the cores themselves (and hpatch's
46
+ # HDiffPatch/lzma includes) resolve file-relative.
52
47
  target_include_directories(rnpushy PRIVATE
53
48
  ${CMAKE_CURRENT_SOURCE_DIR}
54
49
  ${PATCH_CORE_DIR}
55
50
  ${UPDATE_FLOW_CORE_DIR}
56
- ${ANDROID_JNI_DIR}
57
- ${HDIFFPATCH_DIR}
58
- ${HDIFFPATCH_DIR}/libHDiffPatch/HPatch
59
- ${LZMA_DIR}/C
60
51
  )
61
52
 
62
53
  target_link_libraries(rnpushy PUBLIC
@@ -22,8 +22,8 @@
22
22
  * SOFTWARE.
23
23
  */
24
24
 
25
- #ifndef GEO_LOCATION_PACKAGE_H
26
- #define GEO_LOCATION_PACKAGE_H
25
+ #ifndef PUSHY_PACKAGE_H
26
+ #define PUSHY_PACKAGE_H
27
27
 
28
28
  #include "RNOH/Package.h"
29
29
  #include "PushyTurboModule.h"