@hot-updater/react-native 1.0.0-rc.1 → 1.0.0-rc.15
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/android/proguard-rules.pro +17 -2
- package/android/src/main/java/com/hotupdater/BuiltInAssetResolver.kt +286 -0
- package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +651 -637
- package/android/src/main/java/com/hotupdater/BundleMetadata.kt +10 -0
- package/android/src/main/java/com/hotupdater/HotUpdaterException.kt +0 -13
- package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +10 -14
- package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryManager.kt +37 -54
- package/android/src/main/java/com/hotupdater/HotUpdaterRecoveryState.kt +64 -0
- package/android/src/main/java/com/hotupdater/OkHttpDownloadService.kt +19 -0
- package/android/src/main/java/com/hotupdater/TarArchiveInputStream.kt +214 -375
- package/android/src/main/java/com/hotupdater/TarBrArchiveExtractor.kt +119 -0
- package/android/src/newarch/HotUpdater.kt +7 -9
- package/android/src/newarch/HotUpdaterModule.kt +40 -20
- package/android/src/oldarch/HotUpdater.kt +7 -9
- package/android/src/oldarch/HotUpdaterModule.kt +40 -20
- package/android/src/test/java/com/hotupdater/BundleFileStorageServiceTest.kt +1126 -74
- package/android/src/test/java/com/hotupdater/HotUpdaterImplTest.kt +4 -5
- package/android/src/test/java/com/hotupdater/HotUpdaterRecoveryStateTest.kt +97 -0
- package/android/src/test/java/com/hotupdater/PendingCrashRecoveryTest.kt +44 -0
- package/android/src/test/java/com/hotupdater/TarBrArchiveExtractorTest.kt +206 -0
- package/ios/HotUpdater/Internal/BrotliFileDecompressor.swift +167 -0
- package/ios/HotUpdater/Internal/BuiltInAssetResolver.swift +196 -0
- package/ios/HotUpdater/Internal/BundleFileStorageService.swift +773 -1016
- package/ios/HotUpdater/Internal/BundleMetadata.swift +5 -0
- package/ios/HotUpdater/Internal/FileUtilities.swift +64 -0
- package/ios/HotUpdater/Internal/HotUpdater-Bridging-Header.h +0 -1
- package/ios/HotUpdater/Internal/HotUpdater.mm +5 -27
- package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +149 -51
- package/ios/HotUpdater/Internal/NotificationExtension.swift +0 -2
- package/ios/HotUpdater/Internal/TarArchiveExtractor.swift +182 -311
- package/ios/HotUpdater/Internal/URLSessionDownloadService.swift +13 -72
- package/ios/HotUpdater/Recovery/HotUpdaterRecovery.h +16 -0
- package/ios/HotUpdater/Recovery/HotUpdaterRecovery.mm +83 -0
- package/ios/HotUpdater/Recovery/HotUpdaterRecoveryHooks.mm +49 -0
- package/lib/commonjs/checkForUpdate.js +32 -23
- package/lib/commonjs/checkForUpdate.js.map +1 -1
- package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js +97 -28
- package/lib/commonjs/checkForUpdate.releaseCatalog.spec.js.map +1 -1
- package/lib/commonjs/error.js +4 -13
- package/lib/commonjs/error.js.map +1 -1
- package/lib/commonjs/fetchJSON.js +9 -2
- package/lib/commonjs/fetchJSON.js.map +1 -1
- package/lib/commonjs/httpClient.js +46 -29
- package/lib/commonjs/httpClient.js.map +1 -1
- package/lib/commonjs/httpClient.spec.js +57 -5
- package/lib/commonjs/httpClient.spec.js.map +1 -1
- package/lib/commonjs/index.js +31 -14
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.spec.js +56 -11
- package/lib/commonjs/index.spec.js.map +1 -1
- package/lib/commonjs/native.js +15 -14
- package/lib/commonjs/native.js.map +1 -1
- package/lib/commonjs/native.spec.js +128 -22
- package/lib/commonjs/native.spec.js.map +1 -1
- package/lib/commonjs/{notifyAppReadyAnalytics.boundary.spec.js → notifyAppReadyInsights.boundary.spec.js} +28 -21
- package/lib/commonjs/notifyAppReadyInsights.boundary.spec.js.map +1 -0
- package/lib/commonjs/notifyAppReadyInsights.js +188 -0
- package/lib/commonjs/notifyAppReadyInsights.js.map +1 -0
- package/lib/commonjs/{notifyAppReadyAnalytics.spec.js → notifyAppReadyInsights.spec.js} +161 -29
- package/lib/commonjs/notifyAppReadyInsights.spec.js.map +1 -0
- package/lib/commonjs/{notifyAppReadyAnalytics.test-utils.js → notifyAppReadyInsights.test-utils.js} +3 -3
- package/lib/commonjs/notifyAppReadyInsights.test-utils.js.map +1 -0
- package/lib/commonjs/{notifyAppReadyAnalytics.transport.spec.js → notifyAppReadyInsights.transport.spec.js} +14 -7
- package/lib/commonjs/notifyAppReadyInsights.transport.spec.js.map +1 -0
- package/lib/commonjs/sdkVersion.js +1 -1
- package/lib/commonjs/sdkVersion.js.map +1 -1
- package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -1
- package/lib/commonjs/store.js +3 -10
- package/lib/commonjs/store.js.map +1 -1
- package/lib/commonjs/store.notification.spec.js +12 -4
- package/lib/commonjs/store.notification.spec.js.map +1 -1
- package/lib/commonjs/store.spec.js +2 -136
- package/lib/commonjs/store.spec.js.map +1 -1
- package/lib/commonjs/wrap.js +11 -12
- package/lib/commonjs/wrap.js.map +1 -1
- package/lib/commonjs/wrap.spec.js +97 -25
- package/lib/commonjs/wrap.spec.js.map +1 -1
- package/lib/module/checkForUpdate.js +32 -23
- package/lib/module/checkForUpdate.js.map +1 -1
- package/lib/module/checkForUpdate.releaseCatalog.spec.js +97 -28
- package/lib/module/checkForUpdate.releaseCatalog.spec.js.map +1 -1
- package/lib/module/error.js +4 -13
- package/lib/module/error.js.map +1 -1
- package/lib/module/fetchJSON.js +7 -1
- package/lib/module/fetchJSON.js.map +1 -1
- package/lib/module/httpClient.js +48 -31
- package/lib/module/httpClient.js.map +1 -1
- package/lib/module/httpClient.spec.js +57 -5
- package/lib/module/httpClient.spec.js.map +1 -1
- package/lib/module/index.js +32 -15
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.spec.js +56 -11
- package/lib/module/index.spec.js.map +1 -1
- package/lib/module/native.js +13 -12
- package/lib/module/native.js.map +1 -1
- package/lib/module/native.spec.js +128 -22
- package/lib/module/native.spec.js.map +1 -1
- package/lib/module/{notifyAppReadyAnalytics.boundary.spec.js → notifyAppReadyInsights.boundary.spec.js} +23 -16
- package/lib/module/notifyAppReadyInsights.boundary.spec.js.map +1 -0
- package/lib/module/notifyAppReadyInsights.js +181 -0
- package/lib/module/notifyAppReadyInsights.js.map +1 -0
- package/lib/module/{notifyAppReadyAnalytics.spec.js → notifyAppReadyInsights.spec.js} +153 -21
- package/lib/module/notifyAppReadyInsights.spec.js.map +1 -0
- package/lib/module/{notifyAppReadyAnalytics.test-utils.js → notifyAppReadyInsights.test-utils.js} +3 -3
- package/lib/module/notifyAppReadyInsights.test-utils.js.map +1 -0
- package/lib/module/{notifyAppReadyAnalytics.transport.spec.js → notifyAppReadyInsights.transport.spec.js} +11 -4
- package/lib/module/notifyAppReadyInsights.transport.spec.js.map +1 -0
- package/lib/module/sdkVersion.js +1 -1
- package/lib/module/sdkVersion.js.map +1 -1
- package/lib/module/specs/NativeHotUpdater.js.map +1 -1
- package/lib/module/store.js +3 -10
- package/lib/module/store.js.map +1 -1
- package/lib/module/store.notification.spec.js +12 -4
- package/lib/module/store.notification.spec.js.map +1 -1
- package/lib/module/store.spec.js +2 -136
- package/lib/module/store.spec.js.map +1 -1
- package/lib/module/wrap.js +11 -12
- package/lib/module/wrap.js.map +1 -1
- package/lib/module/wrap.spec.js +99 -25
- package/lib/module/wrap.spec.js.map +1 -1
- package/lib/typescript/commonjs/checkForUpdate.d.ts +2 -3
- package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
- package/lib/typescript/commonjs/error.d.ts +4 -13
- package/lib/typescript/commonjs/error.d.ts.map +1 -1
- package/lib/typescript/commonjs/fetchJSON.d.ts +4 -0
- package/lib/typescript/commonjs/fetchJSON.d.ts.map +1 -1
- package/lib/typescript/commonjs/httpClient.d.ts +6 -6
- package/lib/typescript/commonjs/httpClient.d.ts.map +1 -1
- package/lib/typescript/commonjs/index.d.ts +4 -7
- package/lib/typescript/commonjs/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/native.d.ts +5 -9
- package/lib/typescript/commonjs/native.d.ts.map +1 -1
- package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts +25 -0
- package/lib/typescript/commonjs/notifyAppReadyInsights.d.ts.map +1 -0
- package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts +8 -0
- package/lib/typescript/commonjs/notifyAppReadyInsights.test-utils.d.ts.map +1 -0
- package/lib/typescript/commonjs/sdkVersion.d.ts +1 -1
- package/lib/typescript/commonjs/sdkVersion.d.ts.map +1 -1
- package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts +8 -35
- package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -1
- package/lib/typescript/commonjs/store.d.ts +1 -3
- package/lib/typescript/commonjs/store.d.ts.map +1 -1
- package/lib/typescript/commonjs/wrap.types.d.ts +5 -8
- package/lib/typescript/commonjs/wrap.types.d.ts.map +1 -1
- package/lib/typescript/module/checkForUpdate.d.ts +2 -3
- package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
- package/lib/typescript/module/error.d.ts +4 -13
- package/lib/typescript/module/error.d.ts.map +1 -1
- package/lib/typescript/module/fetchJSON.d.ts +4 -0
- package/lib/typescript/module/fetchJSON.d.ts.map +1 -1
- package/lib/typescript/module/httpClient.d.ts +6 -6
- package/lib/typescript/module/httpClient.d.ts.map +1 -1
- package/lib/typescript/module/index.d.ts +4 -7
- package/lib/typescript/module/index.d.ts.map +1 -1
- package/lib/typescript/module/native.d.ts +5 -9
- package/lib/typescript/module/native.d.ts.map +1 -1
- package/lib/typescript/module/notifyAppReadyInsights.d.ts +25 -0
- package/lib/typescript/module/notifyAppReadyInsights.d.ts.map +1 -0
- package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts +8 -0
- package/lib/typescript/module/notifyAppReadyInsights.test-utils.d.ts.map +1 -0
- package/lib/typescript/module/sdkVersion.d.ts +1 -1
- package/lib/typescript/module/sdkVersion.d.ts.map +1 -1
- package/lib/typescript/module/specs/NativeHotUpdater.d.ts +8 -35
- package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -1
- package/lib/typescript/module/store.d.ts +1 -3
- package/lib/typescript/module/store.d.ts.map +1 -1
- package/lib/typescript/module/wrap.types.d.ts +5 -8
- package/lib/typescript/module/wrap.types.d.ts.map +1 -1
- package/package.json +3 -3
- package/src/checkForUpdate.releaseCatalog.spec.ts +137 -61
- package/src/checkForUpdate.ts +35 -29
- package/src/error.ts +4 -14
- package/src/fetchJSON.ts +12 -1
- package/src/httpClient.spec.ts +70 -5
- package/src/httpClient.ts +78 -64
- package/src/index.spec.ts +59 -11
- package/src/index.ts +41 -17
- package/src/native.spec.ts +133 -22
- package/src/native.ts +21 -32
- package/src/{notifyAppReadyAnalytics.boundary.spec.ts → notifyAppReadyInsights.boundary.spec.ts} +25 -17
- package/src/{notifyAppReadyAnalytics.spec.ts → notifyAppReadyInsights.spec.ts} +141 -22
- package/src/{notifyAppReadyAnalytics.test-utils.ts → notifyAppReadyInsights.test-utils.ts} +4 -4
- package/src/{notifyAppReadyAnalytics.transport.spec.ts → notifyAppReadyInsights.transport.spec.ts} +13 -5
- package/src/notifyAppReadyInsights.ts +293 -0
- package/src/sdkVersion.ts +1 -1
- package/src/specs/NativeHotUpdater.ts +8 -36
- package/src/store.notification.spec.ts +13 -3
- package/src/store.spec.ts +0 -157
- package/src/store.ts +2 -23
- package/src/wrap.spec.ts +109 -31
- package/src/wrap.tsx +11 -11
- package/src/wrap.types.ts +5 -8
- package/android/src/main/java/com/hotupdater/DecompressService.kt +0 -89
- package/android/src/main/java/com/hotupdater/DecompressionStrategy.kt +0 -26
- package/android/src/main/java/com/hotupdater/TarBrDecompressionStrategy.kt +0 -117
- package/android/src/main/java/com/hotupdater/TarGzDecompressionStrategy.kt +0 -117
- package/android/src/main/java/com/hotupdater/ZipDecompressionStrategy.kt +0 -192
- package/android/src/test/java/com/hotupdater/TarArchiveInputStreamTest.kt +0 -68
- package/ios/HotUpdater/Internal/ArchiveExtractionUtilities.swift +0 -178
- package/ios/HotUpdater/Internal/DecompressService.swift +0 -112
- package/ios/HotUpdater/Internal/DecompressionStrategy.swift +0 -22
- package/ios/HotUpdater/Internal/StreamingTarArchiveExtractor.swift +0 -370
- package/ios/HotUpdater/Internal/TarBrDecompressionStrategy.swift +0 -39
- package/ios/HotUpdater/Internal/TarGzDecompressionStrategy.swift +0 -59
- package/ios/HotUpdater/Internal/ZipArchiveExtractor.swift +0 -482
- package/ios/HotUpdater/Internal/ZipDecompressionStrategy.swift +0 -56
- package/lib/commonjs/notifyAppReadyAnalytics.boundary.spec.js.map +0 -1
- package/lib/commonjs/notifyAppReadyAnalytics.js +0 -133
- package/lib/commonjs/notifyAppReadyAnalytics.js.map +0 -1
- package/lib/commonjs/notifyAppReadyAnalytics.spec.js.map +0 -1
- package/lib/commonjs/notifyAppReadyAnalytics.test-utils.js.map +0 -1
- package/lib/commonjs/notifyAppReadyAnalytics.transport.spec.js.map +0 -1
- package/lib/module/notifyAppReadyAnalytics.boundary.spec.js.map +0 -1
- package/lib/module/notifyAppReadyAnalytics.js +0 -128
- package/lib/module/notifyAppReadyAnalytics.js.map +0 -1
- package/lib/module/notifyAppReadyAnalytics.spec.js.map +0 -1
- package/lib/module/notifyAppReadyAnalytics.test-utils.js.map +0 -1
- package/lib/module/notifyAppReadyAnalytics.transport.spec.js.map +0 -1
- package/lib/typescript/commonjs/notifyAppReadyAnalytics.d.ts +0 -13
- package/lib/typescript/commonjs/notifyAppReadyAnalytics.d.ts.map +0 -1
- package/lib/typescript/commonjs/notifyAppReadyAnalytics.test-utils.d.ts +0 -8
- package/lib/typescript/commonjs/notifyAppReadyAnalytics.test-utils.d.ts.map +0 -1
- package/lib/typescript/module/notifyAppReadyAnalytics.d.ts +0 -13
- package/lib/typescript/module/notifyAppReadyAnalytics.d.ts.map +0 -1
- package/lib/typescript/module/notifyAppReadyAnalytics.test-utils.d.ts +0 -8
- package/lib/typescript/module/notifyAppReadyAnalytics.test-utils.d.ts.map +0 -1
- package/src/notifyAppReadyAnalytics.ts +0 -194
package/src/native.spec.ts
CHANGED
|
@@ -52,6 +52,13 @@ vi.mock("./specs/NativeHotUpdater", () => ({
|
|
|
52
52
|
describe("notifyAppReady", () => {
|
|
53
53
|
beforeEach(() => {
|
|
54
54
|
vi.resetModules();
|
|
55
|
+
nativeModuleMock.getActiveUpdateState.mockReset();
|
|
56
|
+
nativeModuleMock.getActiveUpdateState.mockReturnValue({
|
|
57
|
+
activeSelection: null,
|
|
58
|
+
stableSelection: null,
|
|
59
|
+
verificationPending: false,
|
|
60
|
+
highestSeenCatalogs: {},
|
|
61
|
+
});
|
|
55
62
|
nativeModuleMock.notifyAppReady.mockReset();
|
|
56
63
|
nativeModuleMock.getBaseURL.mockReset();
|
|
57
64
|
nativeModuleMock.getBundleId.mockReset();
|
|
@@ -122,6 +129,89 @@ describe("notifyAppReady", () => {
|
|
|
122
129
|
});
|
|
123
130
|
});
|
|
124
131
|
|
|
132
|
+
it("tracks same-file promotions without changing artifact or crash identities", async () => {
|
|
133
|
+
const state = {
|
|
134
|
+
activeSelection: {
|
|
135
|
+
kind: "BUNDLE",
|
|
136
|
+
bundleId: "bundle-123",
|
|
137
|
+
releaseId: "release-1",
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
nativeModuleMock.getActiveUpdateState.mockImplementation(() => state);
|
|
141
|
+
nativeModuleMock.getBundleId.mockReturnValue("bundle-123");
|
|
142
|
+
nativeModuleMock.getManifest.mockReturnValue({ assets: {} });
|
|
143
|
+
nativeModuleMock.getCrashHistory.mockReturnValue(["bundle-failed"]);
|
|
144
|
+
const { getUpdateId, getBundleId, getManifest, getCrashHistory } =
|
|
145
|
+
await import("./native");
|
|
146
|
+
|
|
147
|
+
expect(getUpdateId()).toBe("release-1");
|
|
148
|
+
state.activeSelection.releaseId = "release-2";
|
|
149
|
+
expect(getUpdateId()).toBe("release-2");
|
|
150
|
+
expect(getBundleId()).toBe("bundle-123");
|
|
151
|
+
expect(getManifest().bundleId).toBe("bundle-123");
|
|
152
|
+
expect(getCrashHistory()).toEqual(["bundle-failed"]);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it.each([
|
|
156
|
+
[null, "min-bundle-id"],
|
|
157
|
+
["legacy-bundle", "legacy-bundle"],
|
|
158
|
+
])(
|
|
159
|
+
"preserves the fallback ID for native bundle %s",
|
|
160
|
+
async (bundleId, expected) => {
|
|
161
|
+
nativeModuleMock.getBundleId.mockReturnValue(bundleId);
|
|
162
|
+
const { getUpdateId } = await import("./native");
|
|
163
|
+
|
|
164
|
+
expect(getUpdateId()).toBe(expected);
|
|
165
|
+
},
|
|
166
|
+
);
|
|
167
|
+
|
|
168
|
+
it("reports a staged update while the manifest still identifies the running file", async () => {
|
|
169
|
+
const runningSelection = {
|
|
170
|
+
kind: "BUNDLE",
|
|
171
|
+
bundleId: "running-file",
|
|
172
|
+
releaseId: "running-update",
|
|
173
|
+
};
|
|
174
|
+
const state = {
|
|
175
|
+
activeSelection: runningSelection,
|
|
176
|
+
stableSelection: runningSelection,
|
|
177
|
+
};
|
|
178
|
+
nativeModuleMock.getActiveUpdateState.mockImplementation(() => state);
|
|
179
|
+
nativeModuleMock.getBundleId.mockReturnValue("running-file");
|
|
180
|
+
nativeModuleMock.getManifest.mockReturnValue({
|
|
181
|
+
assets: {},
|
|
182
|
+
bundleId: "running-file",
|
|
183
|
+
});
|
|
184
|
+
const { getUpdateId, getBundleId, getManifest } = await import("./native");
|
|
185
|
+
|
|
186
|
+
expect(getUpdateId()).toBe("running-update");
|
|
187
|
+
state.activeSelection = {
|
|
188
|
+
kind: "BUNDLE",
|
|
189
|
+
bundleId: "staged-file",
|
|
190
|
+
releaseId: "staged-update",
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
expect(getUpdateId()).toBe("staged-update");
|
|
194
|
+
expect(getBundleId()).toBe("running-file");
|
|
195
|
+
expect(getManifest().bundleId).toBe("running-file");
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
it("reports an explicit built-in rollback by its update ID", async () => {
|
|
199
|
+
nativeModuleMock.getActiveUpdateState.mockReturnValue(
|
|
200
|
+
JSON.stringify({
|
|
201
|
+
activeSelection: {
|
|
202
|
+
kind: "EMBEDDED",
|
|
203
|
+
releaseId: "rollback-1",
|
|
204
|
+
bundleId: "min-bundle-id",
|
|
205
|
+
},
|
|
206
|
+
}),
|
|
207
|
+
);
|
|
208
|
+
nativeModuleMock.getBundleId.mockReturnValue(null);
|
|
209
|
+
const { getUpdateId, getBundleId } = await import("./native");
|
|
210
|
+
|
|
211
|
+
expect(getUpdateId()).toBe("rollback-1");
|
|
212
|
+
expect(getBundleId()).toBe("min-bundle-id");
|
|
213
|
+
});
|
|
214
|
+
|
|
125
215
|
it("normalizes legacy PROMOTED launch reports to UPDATE_APPLIED", async () => {
|
|
126
216
|
nativeModuleMock.notifyAppReady.mockReturnValue(
|
|
127
217
|
JSON.stringify({
|
|
@@ -157,7 +247,7 @@ describe("notifyAppReady", () => {
|
|
|
157
247
|
toBundleId: "bundle-122",
|
|
158
248
|
});
|
|
159
249
|
expect(readNotifyAppReady()).toEqual({
|
|
160
|
-
|
|
250
|
+
insightsEvent: {
|
|
161
251
|
fromBundleId: "bundle-123",
|
|
162
252
|
toBundleId: "bundle-122",
|
|
163
253
|
type: "RECOVERED",
|
|
@@ -184,13 +274,13 @@ describe("notifyAppReady", () => {
|
|
|
184
274
|
|
|
185
275
|
expect(notifyAppReady()).toEqual({ status: "UNCHANGED" });
|
|
186
276
|
expect(readNotifyAppReady()).toEqual({
|
|
187
|
-
|
|
277
|
+
insightsEvent: null,
|
|
188
278
|
pending: false,
|
|
189
279
|
result: { status: "UNCHANGED" },
|
|
190
280
|
});
|
|
191
281
|
});
|
|
192
282
|
|
|
193
|
-
it("returns UNCHANGED when automatic
|
|
283
|
+
it("returns UNCHANGED when automatic insights metadata is incomplete", async () => {
|
|
194
284
|
nativeModuleMock.notifyAppReady.mockReturnValue({
|
|
195
285
|
status: "UPDATE_APPLIED",
|
|
196
286
|
});
|
|
@@ -199,7 +289,7 @@ describe("notifyAppReady", () => {
|
|
|
199
289
|
|
|
200
290
|
expect(notifyAppReady()).toEqual({ status: "UNCHANGED" });
|
|
201
291
|
expect(readNotifyAppReady()).toEqual({
|
|
202
|
-
|
|
292
|
+
insightsEvent: null,
|
|
203
293
|
pending: false,
|
|
204
294
|
result: { status: "UNCHANGED" },
|
|
205
295
|
});
|
|
@@ -212,7 +302,7 @@ describe("notifyAppReady", () => {
|
|
|
212
302
|
|
|
213
303
|
expect(notifyAppReady()).toEqual({ status: "UNCHANGED" });
|
|
214
304
|
expect(readNotifyAppReady()).toEqual({
|
|
215
|
-
|
|
305
|
+
insightsEvent: null,
|
|
216
306
|
pending: false,
|
|
217
307
|
result: { status: "UNCHANGED" },
|
|
218
308
|
});
|
|
@@ -225,7 +315,7 @@ describe("notifyAppReady", () => {
|
|
|
225
315
|
|
|
226
316
|
expect(notifyAppReady()).toEqual({ status: "UNCHANGED" });
|
|
227
317
|
expect(readNotifyAppReady()).toEqual({
|
|
228
|
-
|
|
318
|
+
insightsEvent: null,
|
|
229
319
|
pending: true,
|
|
230
320
|
result: { status: "UNCHANGED" },
|
|
231
321
|
});
|
|
@@ -448,13 +538,20 @@ describe("notifyAppReady", () => {
|
|
|
448
538
|
expect(getBaseURL()).toBe("file:///bundle-123");
|
|
449
539
|
|
|
450
540
|
await updateBundle({
|
|
541
|
+
assets: {},
|
|
451
542
|
bundleId: "bundle-456",
|
|
452
|
-
|
|
453
|
-
|
|
543
|
+
archiveUrl: "https://example.com/bundle.tar.br",
|
|
544
|
+
manifestFileHash: "manifest-hash",
|
|
545
|
+
manifestUrl: "https://example.com/manifest.json",
|
|
454
546
|
status: "UPDATE",
|
|
455
547
|
});
|
|
456
548
|
|
|
457
549
|
expect(getBundleId()).toBe("bundle-123");
|
|
550
|
+
expect(nativeModuleMock.updateBundle).toHaveBeenCalledWith(
|
|
551
|
+
expect.objectContaining({
|
|
552
|
+
archiveUrl: "https://example.com/bundle.tar.br",
|
|
553
|
+
}),
|
|
554
|
+
);
|
|
458
555
|
expect(getManifest()).toEqual({
|
|
459
556
|
assets: {},
|
|
460
557
|
bundleId: "bundle-123",
|
|
@@ -481,9 +578,10 @@ describe("notifyAppReady", () => {
|
|
|
481
578
|
const { getBundleId, updateBundle } = await import("./native");
|
|
482
579
|
|
|
483
580
|
await updateBundle({
|
|
581
|
+
assets: {},
|
|
484
582
|
bundleId: "00000000-0000-0000-0000-000000000003",
|
|
485
|
-
|
|
486
|
-
|
|
583
|
+
manifestFileHash: "manifest-hash",
|
|
584
|
+
manifestUrl: "https://example.com/manifest.json",
|
|
487
585
|
status: "UPDATE",
|
|
488
586
|
});
|
|
489
587
|
|
|
@@ -496,9 +594,10 @@ describe("notifyAppReady", () => {
|
|
|
496
594
|
|
|
497
595
|
await expect(
|
|
498
596
|
updateBundle({
|
|
597
|
+
assets: {},
|
|
499
598
|
bundleId: "00000000-0000-0000-0000-000000000003",
|
|
500
|
-
|
|
501
|
-
|
|
599
|
+
manifestFileHash: "manifest-hash",
|
|
600
|
+
manifestUrl: "https://example.com/manifest.json",
|
|
502
601
|
status: "UPDATE",
|
|
503
602
|
}),
|
|
504
603
|
).resolves.toBe(true);
|
|
@@ -522,9 +621,10 @@ describe("notifyAppReady", () => {
|
|
|
522
621
|
const { updateBundle } = await import("./native");
|
|
523
622
|
|
|
524
623
|
await updateBundle({
|
|
624
|
+
assets: {},
|
|
525
625
|
bundleId: "00000000-0000-0000-0000-000000000003",
|
|
526
|
-
|
|
527
|
-
|
|
626
|
+
manifestFileHash: "manifest-hash",
|
|
627
|
+
manifestUrl: "https://example.com/manifest.json",
|
|
528
628
|
status: "UPDATE",
|
|
529
629
|
});
|
|
530
630
|
|
|
@@ -534,9 +634,10 @@ describe("notifyAppReady", () => {
|
|
|
534
634
|
|
|
535
635
|
await expect(
|
|
536
636
|
updateBundle({
|
|
637
|
+
assets: {},
|
|
537
638
|
bundleId: "00000000-0000-0000-0000-000000000003",
|
|
538
|
-
|
|
539
|
-
|
|
639
|
+
manifestFileHash: "manifest-hash",
|
|
640
|
+
manifestUrl: "https://example.com/manifest.json",
|
|
540
641
|
status: "UPDATE",
|
|
541
642
|
}),
|
|
542
643
|
).resolves.toBe(true);
|
|
@@ -552,7 +653,7 @@ describe("notifyAppReady", () => {
|
|
|
552
653
|
|
|
553
654
|
await updateBundle({
|
|
554
655
|
bundleId: "bundle-789",
|
|
555
|
-
|
|
656
|
+
assets: {
|
|
556
657
|
"index.ios.bundle": {
|
|
557
658
|
file: {
|
|
558
659
|
compression: "br",
|
|
@@ -568,8 +669,6 @@ describe("notifyAppReady", () => {
|
|
|
568
669
|
},
|
|
569
670
|
},
|
|
570
671
|
},
|
|
571
|
-
fileHash: "sig:archive",
|
|
572
|
-
fileUrl: "https://example.com/bundle.zip",
|
|
573
672
|
manifestFileHash: "sig:manifest",
|
|
574
673
|
manifestUrl: "https://example.com/manifest.json",
|
|
575
674
|
status: "UPDATE",
|
|
@@ -577,7 +676,7 @@ describe("notifyAppReady", () => {
|
|
|
577
676
|
|
|
578
677
|
expect(nativeModuleMock.updateBundle).toHaveBeenCalledWith({
|
|
579
678
|
bundleId: "bundle-789",
|
|
580
|
-
|
|
679
|
+
assets: {
|
|
581
680
|
"index.ios.bundle": {
|
|
582
681
|
file: {
|
|
583
682
|
compression: "br",
|
|
@@ -594,8 +693,6 @@ describe("notifyAppReady", () => {
|
|
|
594
693
|
},
|
|
595
694
|
},
|
|
596
695
|
channel: undefined,
|
|
597
|
-
fileHash: "sig:archive",
|
|
598
|
-
fileUrl: "https://example.com/bundle.zip",
|
|
599
696
|
manifestFileHash: "sig:manifest",
|
|
600
697
|
manifestUrl: "https://example.com/manifest.json",
|
|
601
698
|
});
|
|
@@ -728,6 +825,20 @@ describe("notifyAppReady", () => {
|
|
|
728
825
|
expect(getInstallId()).toBe("install-123");
|
|
729
826
|
});
|
|
730
827
|
|
|
828
|
+
it("normalizes an omitted native fingerprint constant to null", async () => {
|
|
829
|
+
nativeModuleMock.getConstants.mockReturnValue({
|
|
830
|
+
APP_VERSION: null,
|
|
831
|
+
CHANNEL: "production",
|
|
832
|
+
DEFAULT_CHANNEL: "production",
|
|
833
|
+
FINGERPRINT_HASH: undefined as unknown as null,
|
|
834
|
+
MIN_BUNDLE_ID: "min-bundle-id",
|
|
835
|
+
});
|
|
836
|
+
|
|
837
|
+
const { getFingerprintHash } = await import("./native");
|
|
838
|
+
|
|
839
|
+
expect(getFingerprintHash()).toBeNull();
|
|
840
|
+
});
|
|
841
|
+
|
|
731
842
|
it("throws when native SDK does not expose getInstallId", async () => {
|
|
732
843
|
const nativeModule = nativeModuleMock as typeof nativeModuleMock & {
|
|
733
844
|
getInstallId?: typeof nativeModuleMock.getInstallId;
|
package/src/native.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type
|
|
2
|
+
type ArtifactAsset,
|
|
3
3
|
type CatalogHighWater,
|
|
4
4
|
INVALID_COHORT_ERROR_MESSAGE,
|
|
5
5
|
isValidCohort,
|
|
@@ -234,7 +234,7 @@ const getReloadProcess = (): (() => Promise<void>) | null => {
|
|
|
234
234
|
: null;
|
|
235
235
|
};
|
|
236
236
|
|
|
237
|
-
export type HotUpdaterProgressArtifactType = "
|
|
237
|
+
export type HotUpdaterProgressArtifactType = "diff";
|
|
238
238
|
|
|
239
239
|
export type HotUpdaterDiffFileStatus =
|
|
240
240
|
| "pending"
|
|
@@ -286,18 +286,11 @@ export interface HotUpdaterDiffProgressDetails {
|
|
|
286
286
|
files: HotUpdaterDiffFileSnapshot[];
|
|
287
287
|
}
|
|
288
288
|
|
|
289
|
-
export type HotUpdaterProgressEvent =
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
totalBytes?: number;
|
|
295
|
-
}
|
|
296
|
-
| {
|
|
297
|
-
progress: number;
|
|
298
|
-
artifactType: "diff";
|
|
299
|
-
details: HotUpdaterDiffProgressDetails;
|
|
300
|
-
};
|
|
289
|
+
export type HotUpdaterProgressEvent = {
|
|
290
|
+
progress: number;
|
|
291
|
+
artifactType: "diff";
|
|
292
|
+
details: HotUpdaterDiffProgressDetails;
|
|
293
|
+
};
|
|
301
294
|
|
|
302
295
|
export type HotUpdaterEvent = {
|
|
303
296
|
onProgress: HotUpdaterProgressEvent;
|
|
@@ -434,8 +427,6 @@ export const commitReleaseSelection = async (input: {
|
|
|
434
427
|
export async function updateBundle(params: UpdateParams): Promise<boolean> {
|
|
435
428
|
const updateBundleId = params.bundleId;
|
|
436
429
|
const status = params.status;
|
|
437
|
-
const targetFileUrl = params.fileUrl;
|
|
438
|
-
|
|
439
430
|
const currentBundleId = status === "UPDATE" ? getFreshBundleId() : undefined;
|
|
440
431
|
|
|
441
432
|
// If native is still on the same bundle we installed in this session,
|
|
@@ -467,11 +458,10 @@ export async function updateBundle(params: UpdateParams): Promise<boolean> {
|
|
|
467
458
|
const existing = sessionState.getInflightUpdate(updateBundleId);
|
|
468
459
|
if (existing) return existing;
|
|
469
460
|
|
|
470
|
-
const targetFileHash = params.fileHash;
|
|
471
461
|
const targetChannel = params.channel;
|
|
472
462
|
const targetManifestUrl = params.manifestUrl;
|
|
473
463
|
const targetManifestFileHash = params.manifestFileHash;
|
|
474
|
-
const
|
|
464
|
+
const targetAssets = params.assets;
|
|
475
465
|
|
|
476
466
|
const promise = (async () => {
|
|
477
467
|
try {
|
|
@@ -479,12 +469,10 @@ export async function updateBundle(params: UpdateParams): Promise<boolean> {
|
|
|
479
469
|
const ok = await HotUpdaterNative.updateBundle({
|
|
480
470
|
bundleId: updateBundleId,
|
|
481
471
|
channel: targetChannel,
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
manifestFileHash: targetManifestFileHash ?? null,
|
|
487
|
-
manifestUrl: targetManifestUrl ?? null,
|
|
472
|
+
assets: targetAssets as Record<string, ArtifactAsset>,
|
|
473
|
+
manifestFileHash: targetManifestFileHash,
|
|
474
|
+
manifestUrl: targetManifestUrl,
|
|
475
|
+
...(params.archiveUrl ? { archiveUrl: params.archiveUrl } : {}),
|
|
488
476
|
...(selection === undefined ? {} : { selection }),
|
|
489
477
|
});
|
|
490
478
|
if (ok) {
|
|
@@ -599,8 +587,9 @@ export const getMinBundleId = (): string => {
|
|
|
599
587
|
return constants.MIN_BUNDLE_ID;
|
|
600
588
|
};
|
|
601
589
|
|
|
602
|
-
|
|
603
|
-
|
|
590
|
+
/** Returns the selected update ID shown in the console, including staged updates. */
|
|
591
|
+
export const getUpdateId = (): string =>
|
|
592
|
+
getActiveUpdateState().activeSelection?.releaseId ?? getBundleId();
|
|
604
593
|
|
|
605
594
|
/**
|
|
606
595
|
* Fetches the current bundle version id.
|
|
@@ -687,7 +676,7 @@ export const isChannelSwitched = (): boolean => {
|
|
|
687
676
|
*/
|
|
688
677
|
export const getFingerprintHash = (): string | null => {
|
|
689
678
|
const constants = HotUpdaterNative.getConstants();
|
|
690
|
-
return constants.FINGERPRINT_HASH;
|
|
679
|
+
return constants.FINGERPRINT_HASH ?? null;
|
|
691
680
|
};
|
|
692
681
|
|
|
693
682
|
export const getInstallId = (): string => {
|
|
@@ -783,7 +772,7 @@ export type NotifyAppReadyResult =
|
|
|
783
772
|
toReleaseId?: string;
|
|
784
773
|
};
|
|
785
774
|
|
|
786
|
-
export type
|
|
775
|
+
export type NotifyAppReadyInsightsEvent = {
|
|
787
776
|
type: "UPDATE_APPLIED" | "RECOVERED";
|
|
788
777
|
fromBundleId: string;
|
|
789
778
|
toBundleId: string;
|
|
@@ -891,9 +880,9 @@ const getNotifyAppReadyTransition = (
|
|
|
891
880
|
return null;
|
|
892
881
|
};
|
|
893
882
|
|
|
894
|
-
const
|
|
883
|
+
const getNotifyAppReadyInsightsEvent = (
|
|
895
884
|
result: RawNotifyAppReadyResult,
|
|
896
|
-
):
|
|
885
|
+
): NotifyAppReadyInsightsEvent | null => {
|
|
897
886
|
const transition = getNotifyAppReadyTransition(result);
|
|
898
887
|
|
|
899
888
|
if (!transition || !isPersistedUpdateStrategy(result.updateStrategy)) {
|
|
@@ -938,14 +927,14 @@ const normalizeNotifyAppReadyResult = (
|
|
|
938
927
|
|
|
939
928
|
export const readNotifyAppReady = (): {
|
|
940
929
|
result: NotifyAppReadyResult;
|
|
941
|
-
|
|
930
|
+
insightsEvent: NotifyAppReadyInsightsEvent | null;
|
|
942
931
|
pending: boolean;
|
|
943
932
|
} => {
|
|
944
933
|
const rawResult = readRawNotifyAppReadyResult();
|
|
945
934
|
|
|
946
935
|
return {
|
|
947
936
|
result: normalizeNotifyAppReadyResult(rawResult),
|
|
948
|
-
|
|
937
|
+
insightsEvent: getNotifyAppReadyInsightsEvent(rawResult),
|
|
949
938
|
pending: rawResult.status === "PENDING",
|
|
950
939
|
};
|
|
951
940
|
};
|
package/src/{notifyAppReadyAnalytics.boundary.spec.ts → notifyAppReadyInsights.boundary.spec.ts}
RENAMED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
2
2
|
|
|
3
3
|
import type {
|
|
4
|
-
|
|
4
|
+
ActiveUpdateState,
|
|
5
|
+
NotifyAppReadyInsightsEvent,
|
|
5
6
|
NotifyAppReadyResult,
|
|
6
7
|
} from "./native";
|
|
7
8
|
import {
|
|
8
9
|
createNotifyReadResult,
|
|
9
10
|
stubNotifyFrame,
|
|
10
|
-
} from "./
|
|
11
|
+
} from "./notifyAppReadyInsights.test-utils";
|
|
11
12
|
|
|
12
13
|
const platformState = vi.hoisted((): { OS: "ios" | "android" } => ({
|
|
13
14
|
OS: "ios",
|
|
@@ -42,13 +43,14 @@ const mocks = vi.hoisted(() => ({
|
|
|
42
43
|
getAppVersion: vi.fn<() => string | undefined>(() => "1.0.0"),
|
|
43
44
|
getBundleId: vi.fn<() => string | undefined>(() => "bundle-id"),
|
|
44
45
|
getChannel: vi.fn(() => "production"),
|
|
46
|
+
getActiveUpdateState: vi.fn<() => ActiveUpdateState>(),
|
|
45
47
|
getCohort: vi.fn(() => "123"),
|
|
46
48
|
getFingerprintHash: vi.fn(() => "fingerprint-hash"),
|
|
47
49
|
getInstallId: vi.fn<() => string | undefined>(() => "install-id"),
|
|
48
50
|
getPersistedUserIdentity: vi.fn(() => ({})),
|
|
49
51
|
readNotifyAppReady: vi.fn<
|
|
50
52
|
() => {
|
|
51
|
-
|
|
53
|
+
insightsEvent: NotifyAppReadyInsightsEvent | null;
|
|
52
54
|
pending: boolean;
|
|
53
55
|
result: NotifyAppReadyResult;
|
|
54
56
|
}
|
|
@@ -65,6 +67,7 @@ vi.mock("./native", () => ({
|
|
|
65
67
|
getAppVersion: mocks.getAppVersion,
|
|
66
68
|
getBundleId: mocks.getBundleId,
|
|
67
69
|
getChannel: mocks.getChannel,
|
|
70
|
+
getActiveUpdateState: mocks.getActiveUpdateState,
|
|
68
71
|
getCohort: mocks.getCohort,
|
|
69
72
|
getFingerprintHash: mocks.getFingerprintHash,
|
|
70
73
|
getInstallId: mocks.getInstallId,
|
|
@@ -78,20 +81,20 @@ vi.mock("./specs/NativeHotUpdater", () => ({
|
|
|
78
81
|
}));
|
|
79
82
|
|
|
80
83
|
const createClient = () => {
|
|
81
|
-
const
|
|
84
|
+
const sendInsightsEvent = vi.fn().mockResolvedValue(undefined);
|
|
82
85
|
return {
|
|
83
86
|
client: {
|
|
84
87
|
createSession: vi.fn(async () => ({
|
|
85
88
|
fetchReleaseCatalog: vi.fn(),
|
|
86
89
|
resolveArtifact: vi.fn(),
|
|
87
|
-
|
|
90
|
+
sendInsightsEvent,
|
|
88
91
|
})),
|
|
89
92
|
},
|
|
90
|
-
|
|
93
|
+
sendInsightsEvent,
|
|
91
94
|
};
|
|
92
95
|
};
|
|
93
96
|
|
|
94
|
-
describe("automatic notifyAppReady
|
|
97
|
+
describe("automatic notifyAppReady insights boundaries", () => {
|
|
95
98
|
beforeEach(() => {
|
|
96
99
|
vi.resetModules();
|
|
97
100
|
vi.unstubAllGlobals();
|
|
@@ -106,6 +109,11 @@ describe("automatic notifyAppReady analytics boundaries", () => {
|
|
|
106
109
|
mocks.getAppVersion.mockReturnValue("1.0.0");
|
|
107
110
|
mocks.getBundleId.mockReturnValue("bundle-id");
|
|
108
111
|
mocks.getChannel.mockReturnValue("production");
|
|
112
|
+
mocks.getActiveUpdateState.mockReturnValue({
|
|
113
|
+
activeSelection: null,
|
|
114
|
+
stableSelection: null,
|
|
115
|
+
verificationPending: false,
|
|
116
|
+
});
|
|
109
117
|
mocks.getCohort.mockReturnValue("123");
|
|
110
118
|
mocks.getFingerprintHash.mockReturnValue("fingerprint-hash");
|
|
111
119
|
mocks.getInstallId.mockReturnValue("install-id");
|
|
@@ -124,7 +132,7 @@ describe("automatic notifyAppReady analytics boundaries", () => {
|
|
|
124
132
|
const { init } = await import("./wrap");
|
|
125
133
|
|
|
126
134
|
init({
|
|
127
|
-
|
|
135
|
+
insights: true,
|
|
128
136
|
client: {
|
|
129
137
|
createSession: vi.fn(async () => {
|
|
130
138
|
throw new Error("baseURL unavailable");
|
|
@@ -138,7 +146,7 @@ describe("automatic notifyAppReady analytics boundaries", () => {
|
|
|
138
146
|
expect(onError).not.toHaveBeenCalled();
|
|
139
147
|
expect(onNotifyAppReady).toHaveBeenCalledWith({ status: "UNCHANGED" });
|
|
140
148
|
expect(warn).toHaveBeenCalledWith(
|
|
141
|
-
"[HotUpdater] Automatic notifyAppReady
|
|
149
|
+
"[HotUpdater] Automatic notifyAppReady insights failed:",
|
|
142
150
|
expect.objectContaining({
|
|
143
151
|
message: "baseURL unavailable",
|
|
144
152
|
}),
|
|
@@ -163,17 +171,17 @@ describe("automatic notifyAppReady analytics boundaries", () => {
|
|
|
163
171
|
} else {
|
|
164
172
|
mocks.getInstallId.mockReturnValue(value);
|
|
165
173
|
}
|
|
166
|
-
const { client,
|
|
174
|
+
const { client, sendInsightsEvent } = createClient();
|
|
167
175
|
const { init } = await import("./wrap");
|
|
168
176
|
|
|
169
|
-
init({
|
|
177
|
+
init({ insights: true, client, onError, onNotifyAppReady });
|
|
170
178
|
await vi.runOnlyPendingTimersAsync();
|
|
171
179
|
|
|
172
|
-
expect(
|
|
180
|
+
expect(sendInsightsEvent).not.toHaveBeenCalled();
|
|
173
181
|
expect(onError).not.toHaveBeenCalled();
|
|
174
182
|
expect(onNotifyAppReady).toHaveBeenCalledWith({ status: "UNCHANGED" });
|
|
175
183
|
expect(warn).toHaveBeenCalledWith(
|
|
176
|
-
"[HotUpdater] Automatic notifyAppReady
|
|
184
|
+
"[HotUpdater] Automatic notifyAppReady insights failed:",
|
|
177
185
|
expect.any(Error),
|
|
178
186
|
);
|
|
179
187
|
warn.mockRestore();
|
|
@@ -197,17 +205,17 @@ describe("automatic notifyAppReady analytics boundaries", () => {
|
|
|
197
205
|
} else {
|
|
198
206
|
mocks.getBundleId.mockReturnValue(value);
|
|
199
207
|
}
|
|
200
|
-
const { client,
|
|
208
|
+
const { client, sendInsightsEvent } = createClient();
|
|
201
209
|
const { init } = await import("./wrap");
|
|
202
210
|
|
|
203
|
-
init({
|
|
211
|
+
init({ insights: true, client, onError, onNotifyAppReady });
|
|
204
212
|
await vi.runOnlyPendingTimersAsync();
|
|
205
213
|
|
|
206
|
-
expect(
|
|
214
|
+
expect(sendInsightsEvent).not.toHaveBeenCalled();
|
|
207
215
|
expect(onError).not.toHaveBeenCalled();
|
|
208
216
|
expect(onNotifyAppReady).toHaveBeenCalledWith({ status: "UNCHANGED" });
|
|
209
217
|
expect(warn).toHaveBeenCalledWith(
|
|
210
|
-
"[HotUpdater] Automatic notifyAppReady
|
|
218
|
+
"[HotUpdater] Automatic notifyAppReady insights failed:",
|
|
211
219
|
expect.any(Error),
|
|
212
220
|
);
|
|
213
221
|
warn.mockRestore();
|