@hot-updater/react-native 1.0.4 → 1.0.6
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/HotUpdater.podspec +24 -3
- package/Package.swift +100 -0
- package/android/build.gradle +3 -4
- package/android/hot-updater-builtin-assets.gradle +67 -0
- package/android/hot-updater-min-bundle-id.gradle +69 -0
- package/android/src/main/java/com/hotupdater/ArtifactFileResolver.kt +85 -0
- package/android/src/main/java/com/hotupdater/BuiltInAssetResolver.kt +116 -11
- package/android/src/main/java/com/hotupdater/BundleFileStorageService.kt +117 -12
- package/android/src/main/java/com/hotupdater/HotUpdaterImpl.kt +5 -52
- package/android/src/newarch/HotUpdaterModule.kt +46 -2
- package/android/src/oldarch/HotUpdaterModule.kt +46 -2
- package/ios/HotUpdater/Interface/HotUpdaterInterface.h +66 -0
- package/ios/HotUpdater/Interface/HotUpdaterInterface.m +3 -0
- package/ios/HotUpdater/Internal/ArtifactFileResolver.swift +87 -0
- package/ios/HotUpdater/Internal/BundleFileStorageService.swift +88 -13
- package/ios/HotUpdater/Internal/HotUpdater.mm +41 -90
- package/ios/HotUpdater/Internal/HotUpdaterImpl.swift +25 -11
- package/ios/HotUpdater/Internal/HotUpdaterInterface.swift +26 -0
- package/ios/HotUpdater/Internal/HotUpdaterMinBundleId.m +10 -0
- package/ios/HotUpdater/Package.swift +88 -0
- package/ios/Plugins/HotUpdaterMinBundleIdPlugin/HotUpdaterMinBundleIdPlugin.swift +28 -0
- package/ios/scripts/generate-min-bundle-id.zsh +49 -0
- package/lib/commonjs/checkForUpdate.js +8 -0
- package/lib/commonjs/checkForUpdate.js.map +1 -1
- package/lib/commonjs/fetchUpdateResponse.js +5 -2
- package/lib/commonjs/fetchUpdateResponse.js.map +1 -1
- package/lib/commonjs/httpClient.js +64 -5
- package/lib/commonjs/httpClient.js.map +1 -1
- package/lib/commonjs/native.js +9 -0
- package/lib/commonjs/native.js.map +1 -1
- package/lib/commonjs/sdkVersion.js +1 -1
- package/lib/commonjs/specs/NativeHotUpdater.js.map +1 -1
- package/lib/module/checkForUpdate.js +8 -0
- package/lib/module/checkForUpdate.js.map +1 -1
- package/lib/module/fetchUpdateResponse.js +4 -1
- package/lib/module/fetchUpdateResponse.js.map +1 -1
- package/lib/module/httpClient.js +67 -7
- package/lib/module/httpClient.js.map +1 -1
- package/lib/module/native.js +9 -0
- package/lib/module/native.js.map +1 -1
- package/lib/module/sdkVersion.js +1 -1
- package/lib/module/specs/NativeHotUpdater.js.map +1 -1
- package/lib/typescript/commonjs/checkForUpdate.d.ts.map +1 -1
- package/lib/typescript/commonjs/fetchUpdateResponse.d.ts +2 -0
- package/lib/typescript/commonjs/fetchUpdateResponse.d.ts.map +1 -1
- package/lib/typescript/commonjs/httpClient.d.ts +18 -2
- package/lib/typescript/commonjs/httpClient.d.ts.map +1 -1
- package/lib/typescript/commonjs/native.d.ts.map +1 -1
- package/lib/typescript/commonjs/sdkVersion.d.ts +1 -1
- package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts +13 -1
- package/lib/typescript/commonjs/specs/NativeHotUpdater.d.ts.map +1 -1
- package/lib/typescript/module/checkForUpdate.d.ts.map +1 -1
- package/lib/typescript/module/fetchUpdateResponse.d.ts +2 -0
- package/lib/typescript/module/fetchUpdateResponse.d.ts.map +1 -1
- package/lib/typescript/module/httpClient.d.ts +18 -2
- package/lib/typescript/module/httpClient.d.ts.map +1 -1
- package/lib/typescript/module/native.d.ts.map +1 -1
- package/lib/typescript/module/sdkVersion.d.ts +1 -1
- package/lib/typescript/module/specs/NativeHotUpdater.d.ts +13 -1
- package/lib/typescript/module/specs/NativeHotUpdater.d.ts.map +1 -1
- package/package.json +5 -4
- package/react-native.config.js +7 -0
- package/src/checkForUpdate.ts +11 -0
- package/src/fetchUpdateResponse.ts +4 -1
- package/src/httpClient.ts +84 -9
- package/src/native.ts +7 -0
- package/src/sdkVersion.ts +1 -1
- package/src/specs/NativeHotUpdater.ts +13 -1
package/src/checkForUpdate.ts
CHANGED
|
@@ -18,6 +18,7 @@ import type {
|
|
|
18
18
|
UpdateErrorStage,
|
|
19
19
|
} from "./clientPlugin";
|
|
20
20
|
import { HotUpdaterError, StaleReleaseCatalogError } from "./error";
|
|
21
|
+
import { DEFAULT_REQUEST_TIMEOUT_MS } from "./fetchUpdateResponse";
|
|
21
22
|
import type { HotUpdaterHttpClient } from "./httpClient";
|
|
22
23
|
import {
|
|
23
24
|
acceptReleaseCatalog,
|
|
@@ -392,6 +393,16 @@ async function checkForReleaseCatalogUpdate(input: {
|
|
|
392
393
|
manifestFileHash: artifact.manifestFileHash,
|
|
393
394
|
manifestUrl: artifact.manifestUrl,
|
|
394
395
|
...(artifact.archiveUrl ? { archiveUrl: artifact.archiveUrl } : {}),
|
|
396
|
+
...(artifact.filesUrl
|
|
397
|
+
? {
|
|
398
|
+
filesUrl: artifact.filesUrl,
|
|
399
|
+
...(options.requestHeaders
|
|
400
|
+
? { requestHeaders: options.requestHeaders }
|
|
401
|
+
: {}),
|
|
402
|
+
requestTimeout:
|
|
403
|
+
options.requestTimeout ?? DEFAULT_REQUEST_TIMEOUT_MS,
|
|
404
|
+
}
|
|
405
|
+
: {}),
|
|
395
406
|
selection: receipt,
|
|
396
407
|
shouldSkipCurrentBundleIdCheck: true,
|
|
397
408
|
status: desired.status,
|
|
@@ -8,12 +8,15 @@ export interface UpdateRequest {
|
|
|
8
8
|
readonly onResponse?: (response: UpdateHttpResponse) => void;
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
+
/** How long an update request may take when the app sets no `requestTimeout`. */
|
|
12
|
+
export const DEFAULT_REQUEST_TIMEOUT_MS = 5000;
|
|
13
|
+
|
|
11
14
|
/** Read once for parsing and diagnostics, under the same request timeout. */
|
|
12
15
|
export const fetchUpdateResponse = async ({
|
|
13
16
|
url,
|
|
14
17
|
resource,
|
|
15
18
|
requestHeaders,
|
|
16
|
-
requestTimeout =
|
|
19
|
+
requestTimeout = DEFAULT_REQUEST_TIMEOUT_MS,
|
|
17
20
|
onResponse,
|
|
18
21
|
}: UpdateRequest): Promise<{ response: Response; body: string | null }> => {
|
|
19
22
|
const controller = new AbortController();
|
package/src/httpClient.ts
CHANGED
|
@@ -1,15 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
|
+
ARTIFACT_FILES_PROTOCOL_VERSION,
|
|
2
3
|
ARTIFACT_PROTOCOL_VERSION,
|
|
3
4
|
canonicalizeAppVersion,
|
|
4
5
|
encodeChannelKey,
|
|
5
6
|
resolveBaseURL,
|
|
7
|
+
type ArtifactAssetFile,
|
|
6
8
|
type ArtifactInfo,
|
|
9
|
+
type ArtifactInfoV2,
|
|
10
|
+
type ChangedAssetPatch,
|
|
7
11
|
type HotUpdaterBaseURL,
|
|
8
12
|
type ReleaseCatalog,
|
|
9
13
|
type UpdateHttpResponse,
|
|
10
14
|
} from "@hot-updater/protocol";
|
|
11
15
|
|
|
12
|
-
import { fetchJSON } from "./fetchJSON";
|
|
16
|
+
import { fetchJSON, FetchJSONResponseError } from "./fetchJSON";
|
|
13
17
|
import { fetchReleaseCatalogWithCache } from "./releaseCatalogCache";
|
|
14
18
|
import { InvalidUpdateResponseError } from "./updateError";
|
|
15
19
|
|
|
@@ -30,12 +34,32 @@ export interface ArtifactRequest {
|
|
|
30
34
|
readonly requestTimeout?: number;
|
|
31
35
|
}
|
|
32
36
|
|
|
37
|
+
/**
|
|
38
|
+
* How native downloads a Bundle. In artifact protocol v1, `assets` holds a
|
|
39
|
+
* URL for every file. In v2, it holds only the Hermes patch, and native asks
|
|
40
|
+
* `filesUrl` for the URLs of the files it downloads one by one.
|
|
41
|
+
*/
|
|
42
|
+
export interface ResolvedArtifact {
|
|
43
|
+
readonly manifestUrl: string;
|
|
44
|
+
readonly manifestFileHash: string;
|
|
45
|
+
readonly archiveUrl?: string;
|
|
46
|
+
readonly assets: Record<
|
|
47
|
+
string,
|
|
48
|
+
{
|
|
49
|
+
readonly file?: ArtifactAssetFile;
|
|
50
|
+
readonly fileHash?: string;
|
|
51
|
+
readonly patch?: ChangedAssetPatch | null;
|
|
52
|
+
}
|
|
53
|
+
>;
|
|
54
|
+
readonly filesUrl?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
33
57
|
export interface HotUpdaterHttpSession {
|
|
34
58
|
/** Resolves to null when the server says the scope has no catalog, so no update. */
|
|
35
59
|
fetchReleaseCatalog: (
|
|
36
60
|
params: ReleaseCatalogRequest,
|
|
37
61
|
) => Promise<ReleaseCatalog | null>;
|
|
38
|
-
resolveArtifact: (params: ArtifactRequest) => Promise<
|
|
62
|
+
resolveArtifact: (params: ArtifactRequest) => Promise<ResolvedArtifact>;
|
|
39
63
|
}
|
|
40
64
|
|
|
41
65
|
export interface HotUpdaterHttpClient {
|
|
@@ -59,6 +83,7 @@ const requireArtifactUrl = (value: string): string => {
|
|
|
59
83
|
return value;
|
|
60
84
|
};
|
|
61
85
|
|
|
86
|
+
// Legacy: artifact protocol v1: validates a server that predates v2; remove with the fallback.
|
|
62
87
|
const requireArtifactUrls = (info: ArtifactInfo): ArtifactInfo => {
|
|
63
88
|
requireArtifactUrl(info.manifestUrl);
|
|
64
89
|
if (info.archiveUrl) requireArtifactUrl(info.archiveUrl);
|
|
@@ -91,6 +116,25 @@ const requireArtifactProtocolV1 = (info: ArtifactInfo): ArtifactInfo => {
|
|
|
91
116
|
return info;
|
|
92
117
|
};
|
|
93
118
|
|
|
119
|
+
const requireArtifactProtocolV2 = (info: ArtifactInfoV2): ArtifactInfoV2 => {
|
|
120
|
+
if (
|
|
121
|
+
info?.artifactProtocolVersion !== ARTIFACT_FILES_PROTOCOL_VERSION ||
|
|
122
|
+
!info.manifestUrl ||
|
|
123
|
+
!info.manifestFileHash ||
|
|
124
|
+
(info.archiveUrl !== undefined && typeof info.archiveUrl !== "string") ||
|
|
125
|
+
(info.patch !== undefined &&
|
|
126
|
+
(!info.patch?.assetPath || !info.patch.patchUrl))
|
|
127
|
+
) {
|
|
128
|
+
throw new InvalidUpdateResponseError(
|
|
129
|
+
`Server does not support artifact protocol ${ARTIFACT_FILES_PROTOCOL_VERSION}.`,
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
requireArtifactUrl(info.manifestUrl);
|
|
133
|
+
if (info.archiveUrl) requireArtifactUrl(info.archiveUrl);
|
|
134
|
+
if (info.patch) requireArtifactUrl(info.patch.patchUrl);
|
|
135
|
+
return info;
|
|
136
|
+
};
|
|
137
|
+
|
|
94
138
|
const createSession = (
|
|
95
139
|
baseURL: string,
|
|
96
140
|
onResponse?: (response: UpdateHttpResponse) => void,
|
|
@@ -133,16 +177,47 @@ const createSession = (
|
|
|
133
177
|
url,
|
|
134
178
|
});
|
|
135
179
|
},
|
|
136
|
-
resolveArtifact: async (params): Promise<
|
|
137
|
-
const
|
|
180
|
+
resolveArtifact: async (params): Promise<ResolvedArtifact> => {
|
|
181
|
+
const target = encodeURIComponent(params.targetBundleId);
|
|
182
|
+
const route = `${target}/from/${encodeURIComponent(params.currentBundleId)}`;
|
|
183
|
+
const request = {
|
|
138
184
|
...(onResponse ? { onResponse } : {}),
|
|
139
185
|
requestHeaders: params.requestHeaders,
|
|
140
186
|
requestTimeout: params.requestTimeout,
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
187
|
+
};
|
|
188
|
+
let info: ArtifactInfoV2;
|
|
189
|
+
try {
|
|
190
|
+
info = await fetchJSON<ArtifactInfoV2>({
|
|
191
|
+
...request,
|
|
192
|
+
url: `${baseURL}/artifacts/v2/${route}`,
|
|
193
|
+
});
|
|
194
|
+
} catch (error) {
|
|
195
|
+
// Legacy: artifact protocol v1: a server older than v2 has no such route. Remove this
|
|
196
|
+
// fallback once no supported server predates v2.
|
|
197
|
+
if (!(error instanceof FetchJSONResponseError) || error.status !== 404) {
|
|
198
|
+
throw error;
|
|
199
|
+
}
|
|
200
|
+
return requireArtifactUrls(
|
|
201
|
+
requireArtifactProtocolV1(
|
|
202
|
+
await fetchJSON<ArtifactInfo>({
|
|
203
|
+
...request,
|
|
204
|
+
url: `${baseURL}/artifacts/v1/${route}`,
|
|
205
|
+
}),
|
|
206
|
+
),
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
const { archiveUrl, manifestFileHash, manifestUrl, patch } =
|
|
210
|
+
requireArtifactProtocolV2(info);
|
|
211
|
+
const { assetPath, ...assetPatch } = patch ?? { assetPath: undefined };
|
|
212
|
+
return {
|
|
213
|
+
...(archiveUrl ? { archiveUrl } : {}),
|
|
214
|
+
assets: assetPath
|
|
215
|
+
? { [assetPath]: { patch: assetPatch as ChangedAssetPatch } }
|
|
216
|
+
: {},
|
|
217
|
+
filesUrl: `${baseURL}/artifacts/v2/${target}/files`,
|
|
218
|
+
manifestFileHash,
|
|
219
|
+
manifestUrl,
|
|
220
|
+
};
|
|
146
221
|
},
|
|
147
222
|
});
|
|
148
223
|
|
package/src/native.ts
CHANGED
|
@@ -461,6 +461,13 @@ export async function stageBundle(
|
|
|
461
461
|
manifestFileHash: targetManifestFileHash,
|
|
462
462
|
manifestUrl: targetManifestUrl,
|
|
463
463
|
...(params.archiveUrl ? { archiveUrl: params.archiveUrl } : {}),
|
|
464
|
+
...(params.filesUrl ? { filesUrl: params.filesUrl } : {}),
|
|
465
|
+
...(params.filesUrl && params.requestHeaders
|
|
466
|
+
? { requestHeaders: params.requestHeaders }
|
|
467
|
+
: {}),
|
|
468
|
+
...(params.filesUrl && params.requestTimeout
|
|
469
|
+
? { requestTimeout: params.requestTimeout }
|
|
470
|
+
: {}),
|
|
464
471
|
...(selection === undefined ? {} : { selection }),
|
|
465
472
|
});
|
|
466
473
|
sessionState.markBundleInstalled(updateBundleId, targetChannel);
|
package/src/sdkVersion.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const HOT_UPDATER_SDK_VERSION = "1.0.
|
|
1
|
+
export const HOT_UPDATER_SDK_VERSION = "1.0.6";
|
|
@@ -15,8 +15,20 @@ export interface UpdateBundleParams {
|
|
|
15
15
|
manifestFileHash: string;
|
|
16
16
|
/** Optional tar.br URL; integrity and sizes come from the verified manifest. */
|
|
17
17
|
archiveUrl?: string | null;
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Target file descriptors: every file with its URL in artifact protocol v1,
|
|
20
|
+
* or only the Hermes patch in v2, where native asks `filesUrl`.
|
|
21
|
+
*/
|
|
19
22
|
assets: UnsafeObject;
|
|
23
|
+
/**
|
|
24
|
+
* Artifact protocol v2: where native POSTs the paths of the files it
|
|
25
|
+
* downloads one by one, after reusing local files and choosing the archive.
|
|
26
|
+
*/
|
|
27
|
+
filesUrl?: string | null;
|
|
28
|
+
/** Headers for the `filesUrl` request, as the update check sent them. */
|
|
29
|
+
requestHeaders?: UnsafeObject | null;
|
|
30
|
+
/** Milliseconds the `filesUrl` request may take, as the update check's. */
|
|
31
|
+
requestTimeout?: number | null;
|
|
20
32
|
/** Full Release Catalog selection receipt committed with the staged Bundle. */
|
|
21
33
|
selection?: UnsafeObject | null;
|
|
22
34
|
}
|