react-native-update 10.46.0 → 10.47.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.
- package/package.json +1 -1
- package/src/client.ts +77 -0
- package/src/telemetry.ts +83 -0
- package/src/type.ts +6 -0
package/package.json
CHANGED
package/src/client.ts
CHANGED
|
@@ -41,6 +41,11 @@ import {
|
|
|
41
41
|
import i18n from './i18n';
|
|
42
42
|
import { toUpdateError, UpdateError, UpdateErrorCode } from './error';
|
|
43
43
|
import { dedupeEndpoints, executeEndpointFallback } from './endpoint';
|
|
44
|
+
import {
|
|
45
|
+
resolveServerEventHash,
|
|
46
|
+
resolveServerEventType,
|
|
47
|
+
truncateDetail,
|
|
48
|
+
} from './telemetry';
|
|
44
49
|
|
|
45
50
|
/**
|
|
46
51
|
* Receives every error the client reports, alongside the report event type.
|
|
@@ -130,6 +135,9 @@ export class Pushy {
|
|
|
130
135
|
clientType: 'Pushy' | 'Cresc' = 'Pushy';
|
|
131
136
|
lastChecking?: number;
|
|
132
137
|
lastRespJson?: Promise<CheckResult>;
|
|
138
|
+
// Endpoint that most recently served a successful checkUpdate; telemetry
|
|
139
|
+
// reuses it instead of re-running the fallback race.
|
|
140
|
+
private lastWorkingEndpoint?: string;
|
|
133
141
|
|
|
134
142
|
version = cInfo.rnu;
|
|
135
143
|
loggerPromise = (() => {
|
|
@@ -207,6 +215,8 @@ export class Pushy {
|
|
|
207
215
|
data?: Record<string, string | number>;
|
|
208
216
|
}) => {
|
|
209
217
|
log(`${type} ${code ? `[${code}] ` : ''}${message}`);
|
|
218
|
+
// Fire-and-forget server telemetry; must not wait for the logger below.
|
|
219
|
+
this.reportToServer({ type, message, code, data });
|
|
210
220
|
if (this.options.logger === noop) {
|
|
211
221
|
// Wait briefly for a logger to arrive via setOptions (e.g. the rollback
|
|
212
222
|
// report fires in the constructor before the user configures one), but
|
|
@@ -242,6 +252,72 @@ export class Pushy {
|
|
|
242
252
|
log('logger error:', e?.message || e);
|
|
243
253
|
}
|
|
244
254
|
};
|
|
255
|
+
/**
|
|
256
|
+
* Best-effort lifecycle event reporting to the update server (aggregate
|
|
257
|
+
* counts + sampled failure details power the version health view and the
|
|
258
|
+
* rollback safety net server-side). Single POST to the last known working
|
|
259
|
+
* endpoint, no retry, no fallback race; any failure is swallowed — telemetry
|
|
260
|
+
* must never affect the update flow. Opt out with disableTelemetry.
|
|
261
|
+
*/
|
|
262
|
+
private reportToServer = ({
|
|
263
|
+
type,
|
|
264
|
+
message = '',
|
|
265
|
+
code,
|
|
266
|
+
data = {},
|
|
267
|
+
}: {
|
|
268
|
+
type: EventType;
|
|
269
|
+
message?: string;
|
|
270
|
+
code?: UpdateErrorCode;
|
|
271
|
+
data?: Record<string, string | number>;
|
|
272
|
+
}) => {
|
|
273
|
+
try {
|
|
274
|
+
if (__DEV__ || this.options.disableTelemetry) {
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const serverType = resolveServerEventType(type, code);
|
|
278
|
+
if (!serverType) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
const { appKey } = this.options;
|
|
282
|
+
const endpoint =
|
|
283
|
+
this.lastWorkingEndpoint || this.options.server?.main?.[0];
|
|
284
|
+
if (!appKey || !endpoint) {
|
|
285
|
+
return;
|
|
286
|
+
}
|
|
287
|
+
const hash = resolveServerEventHash({ serverType, data, currentVersion });
|
|
288
|
+
if (!hash) {
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
const send = (payloadType: typeof serverType, detail?: string) =>
|
|
292
|
+
fetchWithTimeout(
|
|
293
|
+
`${endpoint}/report/${appKey}`,
|
|
294
|
+
{
|
|
295
|
+
method: 'POST',
|
|
296
|
+
headers: { 'Content-Type': 'application/json' },
|
|
297
|
+
body: JSON.stringify({
|
|
298
|
+
type: payloadType,
|
|
299
|
+
hash,
|
|
300
|
+
packageVersion:
|
|
301
|
+
this.options.overridePackageVersion || packageVersion,
|
|
302
|
+
cInfo,
|
|
303
|
+
detail: truncateDetail(detail),
|
|
304
|
+
}),
|
|
305
|
+
},
|
|
306
|
+
DEFAULT_FETCH_TIMEOUT_MS,
|
|
307
|
+
).catch((e: any) => {
|
|
308
|
+
log('telemetry report failed:', e?.message || e);
|
|
309
|
+
});
|
|
310
|
+
send(serverType, message || undefined);
|
|
311
|
+
// A download that only succeeded after an incremental patch failed is
|
|
312
|
+
// still a patch_fail signal server-side (diff quality), carried in
|
|
313
|
+
// data.error alongside the downloadSuccess event.
|
|
314
|
+
if (serverType === 'download_success' && data.error) {
|
|
315
|
+
send('patch_fail', String(data.error));
|
|
316
|
+
}
|
|
317
|
+
} catch (e: any) {
|
|
318
|
+
log('telemetry error:', e?.message || e);
|
|
319
|
+
}
|
|
320
|
+
};
|
|
245
321
|
throwIfEnabled = (e: Error) => {
|
|
246
322
|
if (this.options.throwError) {
|
|
247
323
|
throw e;
|
|
@@ -387,6 +463,7 @@ export class Pushy {
|
|
|
387
463
|
});
|
|
388
464
|
|
|
389
465
|
log('check endpoint success', endpoint);
|
|
466
|
+
this.lastWorkingEndpoint = endpoint;
|
|
390
467
|
return value;
|
|
391
468
|
};
|
|
392
469
|
assertDebug = (matter: string) => {
|
package/src/telemetry.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import type { UpdateErrorCode } from './error';
|
|
2
|
+
import type { EventType } from './type';
|
|
3
|
+
|
|
4
|
+
// Server-side lifecycle event intake (POST {endpoint}/report/{appKey}); the
|
|
5
|
+
// enum must stay in sync with the server's client_event_type. Only these five
|
|
6
|
+
// aggregate types exist server-side — everything else stays local-only.
|
|
7
|
+
export type ServerEventType =
|
|
8
|
+
| 'download_success'
|
|
9
|
+
| 'download_fail'
|
|
10
|
+
| 'patch_fail'
|
|
11
|
+
| 'rollback'
|
|
12
|
+
| 'mark_success';
|
|
13
|
+
|
|
14
|
+
// Failure detail is stored server-side in a VARCHAR(512); stay under it.
|
|
15
|
+
export const MAX_DETAIL_LENGTH = 500;
|
|
16
|
+
|
|
17
|
+
export interface ServerReportPayload {
|
|
18
|
+
type: ServerEventType;
|
|
19
|
+
hash: string;
|
|
20
|
+
packageVersion?: string;
|
|
21
|
+
cInfo?: {
|
|
22
|
+
rnu?: string;
|
|
23
|
+
rn?: string;
|
|
24
|
+
os?: string;
|
|
25
|
+
uuid?: string;
|
|
26
|
+
};
|
|
27
|
+
detail?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Maps a local report event to the server-side aggregate type, or undefined
|
|
32
|
+
* for events the server does not collect. A DOWNLOAD_FAILED whose underlying
|
|
33
|
+
* native code was PATCH_FAILED counts as patch_fail (the download itself
|
|
34
|
+
* worked; applying it did not), same for switch-version failures.
|
|
35
|
+
*/
|
|
36
|
+
export const resolveServerEventType = (
|
|
37
|
+
type: EventType,
|
|
38
|
+
code?: UpdateErrorCode,
|
|
39
|
+
): ServerEventType | undefined => {
|
|
40
|
+
switch (type) {
|
|
41
|
+
case 'downloadSuccess':
|
|
42
|
+
return 'download_success';
|
|
43
|
+
case 'errorUpdate':
|
|
44
|
+
return code === 'PATCH_FAILED' ? 'patch_fail' : 'download_fail';
|
|
45
|
+
case 'errorSwitchVersion':
|
|
46
|
+
return 'patch_fail';
|
|
47
|
+
case 'markSuccess':
|
|
48
|
+
return 'mark_success';
|
|
49
|
+
case 'rollback':
|
|
50
|
+
return 'rollback';
|
|
51
|
+
default:
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The version hash a server event is about. Server-side rows key on it, so an
|
|
58
|
+
* event without one is not reportable (returns '').
|
|
59
|
+
*/
|
|
60
|
+
export const resolveServerEventHash = ({
|
|
61
|
+
serverType,
|
|
62
|
+
data,
|
|
63
|
+
currentVersion,
|
|
64
|
+
}: {
|
|
65
|
+
serverType: ServerEventType;
|
|
66
|
+
data: Record<string, string | number>;
|
|
67
|
+
currentVersion: string;
|
|
68
|
+
}): string => {
|
|
69
|
+
if (serverType === 'rollback') {
|
|
70
|
+
return String(data.rolledBackVersion || '');
|
|
71
|
+
}
|
|
72
|
+
if (serverType === 'mark_success') {
|
|
73
|
+
return String(data.newVersion || currentVersion || '');
|
|
74
|
+
}
|
|
75
|
+
return String(data.newVersion || '');
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
export const truncateDetail = (detail?: string) => {
|
|
79
|
+
if (!detail) {
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
return detail.slice(0, MAX_DETAIL_LENGTH);
|
|
83
|
+
};
|
package/src/type.ts
CHANGED
|
@@ -129,6 +129,12 @@ export interface ClientOptions {
|
|
|
129
129
|
overridePackageVersion?: string;
|
|
130
130
|
/** Maximum number of retry attempts for failed downloads (default: 3) */
|
|
131
131
|
maxRetries?: number;
|
|
132
|
+
/**
|
|
133
|
+
* Disable reporting update lifecycle events (download/patch failures,
|
|
134
|
+
* rollback, mark success) to the update server. These aggregate stats power
|
|
135
|
+
* the version health view in the console. Default: false (enabled).
|
|
136
|
+
*/
|
|
137
|
+
disableTelemetry?: boolean;
|
|
132
138
|
}
|
|
133
139
|
|
|
134
140
|
export interface UpdateTestPayload {
|