expo-observe 58.0.14 → 58.0.16
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/CHANGELOG.md +15 -0
- package/build/index.d.ts +1 -1
- package/build/index.js.map +1 -1
- package/build/integrations/react-native-reanimated/init.d.ts +13 -0
- package/build/integrations/react-native-reanimated/init.js +129 -0
- package/build/integrations/react-native-reanimated/init.js.map +1 -0
- package/build/integrations/react-native-reanimated/reanimated.d.ts +13 -0
- package/build/integrations/react-native-reanimated/reanimated.js +18 -0
- package/build/integrations/react-native-reanimated/reanimated.js.map +1 -0
- package/build/integrations/react-native-reanimated/stack.d.ts +5 -0
- package/build/integrations/react-native-reanimated/stack.js +27 -0
- package/build/integrations/react-native-reanimated/stack.js.map +1 -0
- package/build/module.js +7 -0
- package/build/module.js.map +1 -1
- package/build/reportCaughtError.d.ts +4 -3
- package/build/reportCaughtError.js +5 -4
- package/build/reportCaughtError.js.map +1 -1
- package/build/types.d.ts +40 -0
- package/build/types.js.map +1 -1
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/{58.0.14/expo.modules.observe-58.0.14-sources.jar → 58.0.16/expo.modules.observe-58.0.16-sources.jar} +0 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.16/expo.modules.observe-58.0.16-sources.jar.md5 +1 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.16/expo.modules.observe-58.0.16-sources.jar.sha1 +1 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.16/expo.modules.observe-58.0.16-sources.jar.sha256 +1 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.16/expo.modules.observe-58.0.16-sources.jar.sha512 +1 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/{58.0.14/expo.modules.observe-58.0.14.aar → 58.0.16/expo.modules.observe-58.0.16.aar} +0 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.16/expo.modules.observe-58.0.16.aar.md5 +1 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.16/expo.modules.observe-58.0.16.aar.sha1 +1 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.16/expo.modules.observe-58.0.16.aar.sha256 +1 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.16/expo.modules.observe-58.0.16.aar.sha512 +1 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/{58.0.14/expo.modules.observe-58.0.14.module → 58.0.16/expo.modules.observe-58.0.16.module} +22 -22
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.16/expo.modules.observe-58.0.16.module.md5 +1 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.16/expo.modules.observe-58.0.16.module.sha1 +1 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.16/expo.modules.observe-58.0.16.module.sha256 +1 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.16/expo.modules.observe-58.0.16.module.sha512 +1 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/{58.0.14/expo.modules.observe-58.0.14.pom → 58.0.16/expo.modules.observe-58.0.16.pom} +2 -2
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.16/expo.modules.observe-58.0.16.pom.md5 +1 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.16/expo.modules.observe-58.0.16.pom.sha1 +1 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.16/expo.modules.observe-58.0.16.pom.sha256 +1 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.16/expo.modules.observe-58.0.16.pom.sha512 +1 -0
- package/package.json +11 -5
- package/src/index.ts +1 -0
- package/src/integrations/react-native-reanimated/init.ts +157 -0
- package/src/integrations/react-native-reanimated/reanimated.ts +29 -0
- package/src/integrations/react-native-reanimated/stack.ts +28 -0
- package/src/module.ts +10 -0
- package/src/reportCaughtError.ts +8 -4
- package/src/types.ts +41 -0
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.14/expo.modules.observe-58.0.14-sources.jar.md5 +0 -1
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.14/expo.modules.observe-58.0.14-sources.jar.sha1 +0 -1
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.14/expo.modules.observe-58.0.14-sources.jar.sha256 +0 -1
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.14/expo.modules.observe-58.0.14-sources.jar.sha512 +0 -1
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.14/expo.modules.observe-58.0.14.aar.md5 +0 -1
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.14/expo.modules.observe-58.0.14.aar.sha1 +0 -1
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.14/expo.modules.observe-58.0.14.aar.sha256 +0 -1
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.14/expo.modules.observe-58.0.14.aar.sha512 +0 -1
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.14/expo.modules.observe-58.0.14.module.md5 +0 -1
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.14/expo.modules.observe-58.0.14.module.sha1 +0 -1
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.14/expo.modules.observe-58.0.14.module.sha256 +0 -1
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.14/expo.modules.observe-58.0.14.module.sha512 +0 -1
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.14/expo.modules.observe-58.0.14.pom.md5 +0 -1
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.14/expo.modules.observe-58.0.14.pom.sha1 +0 -1
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.14/expo.modules.observe-58.0.14.pom.sha256 +0 -1
- package/local-maven-repo/expo/modules/observe/expo.modules.observe/58.0.14/expo.modules.observe-58.0.14.pom.sha512 +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 58.0.16
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Add a `react-native-reanimated` integration that reports Reanimated errors, and optionally warnings, to EAS Observe. ([#50576](https://github.com/expo/expo/pull/50576) by [@douglowder](https://github.com/douglowder))
|
|
8
|
+
- Updated dependencies. ([#51720](https://github.com/expo/expo/pull/51720))
|
|
9
|
+
- expo-app-metrics@58.0.14
|
|
10
|
+
|
|
11
|
+
## 58.0.15
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- Updated dependencies. ([#51609](https://github.com/expo/expo/pull/51609))
|
|
16
|
+
- expo-app-metrics@58.0.13
|
|
17
|
+
|
|
3
18
|
## 58.0.14
|
|
4
19
|
|
|
5
20
|
### Patch Changes
|
package/build/index.d.ts
CHANGED
|
@@ -12,5 +12,5 @@ export { ObserveRoot } from './ObserveRoot';
|
|
|
12
12
|
export { Observe };
|
|
13
13
|
/** @deprecated Import the named `Observe` export instead. */
|
|
14
14
|
export default Observe;
|
|
15
|
-
export type { ObserveAttribute, ObserveAttributes, ObserveConfig, ObserveIntegrationsConfig, ObserveModule, ObserveModuleEvents, ObserveNavigationIntegrationConfig, ObserveNetworkTracesConfig, } from './types';
|
|
15
|
+
export type { ObserveAttribute, ObserveAttributes, ObserveConfig, ObserveIntegrationsConfig, ObserveModule, ObserveModuleEvents, ObserveNavigationIntegrationConfig, ObserveNetworkTracesConfig, ObserveReanimatedIntegrationConfig, } from './types';
|
|
16
16
|
export { useObserve } from './useObserve';
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["index.ts"],"sourcesContent":[null],"names":["Observe","default","AppMetrics","ObserveErrorBoundary","ObserveInteractiveMarker","ObserveRoot","setBundleDefaults","environment","process","env","NODE_ENV","isJsDev","__DEV__","useObserve"],"mappings":"AAAA,OAAOA,aAAa,WAAW;AAE/B;;CAEC,GACD,SAASC,WAAWC,UAAU,QAAQ,mBAAmB;AAWzD,SAASC,oBAAoB,QAAQ,yBAAyB;AAK9D,SAASC,wBAAwB,QAAQ,6BAA6B;AAEtE,SAASC,WAAW,QAAQ,gBAAgB;AAE5CL,QAAQM,iBAAiB,CAAC;IACxBC,aAAaC,QAAQC,GAAG,CAACC,QAAQ,IAAI;IACrCC,SAAS,CAAC,CAACC;AACb;AAEA,SAASZ,OAAO,GAAG;AAEnB,2DAA2D,GAC3D,eAAeA,QAAQ;
|
|
1
|
+
{"version":3,"sources":["index.ts"],"sourcesContent":[null],"names":["Observe","default","AppMetrics","ObserveErrorBoundary","ObserveInteractiveMarker","ObserveRoot","setBundleDefaults","environment","process","env","NODE_ENV","isJsDev","__DEV__","useObserve"],"mappings":"AAAA,OAAOA,aAAa,WAAW;AAE/B;;CAEC,GACD,SAASC,WAAWC,UAAU,QAAQ,mBAAmB;AAWzD,SAASC,oBAAoB,QAAQ,yBAAyB;AAK9D,SAASC,wBAAwB,QAAQ,6BAA6B;AAEtE,SAASC,WAAW,QAAQ,gBAAgB;AAE5CL,QAAQM,iBAAiB,CAAC;IACxBC,aAAaC,QAAQC,GAAG,CAACC,QAAQ,IAAI;IACrCC,SAAS,CAAC,CAACC;AACb;AAEA,SAASZ,OAAO,GAAG;AAEnB,2DAA2D,GAC3D,eAAeA,QAAQ;AAavB,SAASa,UAAU,QAAQ,eAAe"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ObserveIntegrationsConfig } from '../../types';
|
|
2
|
+
/**
|
|
3
|
+
* Configures Reanimated's logger with the integration's `level` and `strict` settings and a
|
|
4
|
+
* callback that reports Reanimated errors to Observe as `reanimated.error` errors. When
|
|
5
|
+
* `reportWarnings` is set, the callback also reports Reanimated warnings as `reanimated.warning`
|
|
6
|
+
* events.
|
|
7
|
+
*/
|
|
8
|
+
export declare function initReanimatedIntegration(config: NonNullable<ObserveIntegrationsConfig['react-native-reanimated']>): void;
|
|
9
|
+
/**
|
|
10
|
+
* Stops reporting Reanimated errors and warnings to Observe. Reanimated's logger keeps its
|
|
11
|
+
* configuration.
|
|
12
|
+
*/
|
|
13
|
+
export declare function disableReanimatedIntegration(): void;
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import AppMetrics from 'expo-app-metrics';
|
|
2
|
+
import { reportCaughtError } from '../../reportCaughtError';
|
|
3
|
+
import { loadReanimated } from './reanimated';
|
|
4
|
+
import { removeFirstFrame } from './stack';
|
|
5
|
+
// Value of Reanimated's `ReanimatedLogLevel.error`.
|
|
6
|
+
const LOG_LEVEL_ERROR = 2;
|
|
7
|
+
// `configureReanimatedLogger` accepts an `onLog` callback since Reanimated 4.7.0.
|
|
8
|
+
const MIN_MAJOR = 4;
|
|
9
|
+
const MIN_MINOR = 7;
|
|
10
|
+
const REANIMATED_ERROR_NAME = 'reanimated.error';
|
|
11
|
+
const REANIMATED_WARNING_EVENT = 'reanimated.warning';
|
|
12
|
+
// A UI-runtime log can repeat every frame, so each distinct message is reported at most once per
|
|
13
|
+
// window. The cap bounds the reports in a window when messages embed varying values, and the
|
|
14
|
+
// window lets new messages be reported again after a surge. Errors and warnings have separate
|
|
15
|
+
// windows, so a screen with many distinct warnings cannot stop errors from being reported.
|
|
16
|
+
const REPORT_WINDOW_MS = 15 * 60_000;
|
|
17
|
+
const MAX_DISTINCT_MESSAGES_PER_WINDOW = 20;
|
|
18
|
+
// Attribute values are sent on every dispatch, and strict-mode messages append a docs
|
|
19
|
+
// reference, so the copied message is capped. Messages are also deduplicated by this capped
|
|
20
|
+
// text, so two messages that differ only after the cap do not send the same attribute twice.
|
|
21
|
+
const MAX_MESSAGE_LENGTH = 500;
|
|
22
|
+
// Maps the capped text of each message reported in the current window to the time it was
|
|
23
|
+
// reported. A `Map` keeps insertion order, so the oldest report is always first. The time comes
|
|
24
|
+
// from the monotonic `performance.now()`, so a change to the device clock cannot stop expiry.
|
|
25
|
+
const reportedErrors = new Map();
|
|
26
|
+
const reportedWarnings = new Map();
|
|
27
|
+
// The callback stays registered in Reanimated after the integration is turned off, because
|
|
28
|
+
// configuring the logger again would reset the app's `level` and `strict`. It checks this flag.
|
|
29
|
+
let isEnabled = false;
|
|
30
|
+
let shouldReportWarnings = false;
|
|
31
|
+
/**
|
|
32
|
+
* A Reanimated error reported to Observe. The stack is set explicitly so it points at the
|
|
33
|
+
* callback's caller rather than at this constructor.
|
|
34
|
+
*/ class ReanimatedError extends Error {
|
|
35
|
+
constructor(message, stack){
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = REANIMATED_ERROR_NAME;
|
|
38
|
+
if (stack !== undefined) {
|
|
39
|
+
this.stack = stack;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function supportsOnLog(version) {
|
|
44
|
+
const match = /^(\d+)\.(\d+)/.exec(version);
|
|
45
|
+
if (!match) {
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
const major = Number(match[1]);
|
|
49
|
+
const minor = Number(match[2]);
|
|
50
|
+
return major > MIN_MAJOR || major === MIN_MAJOR && minor >= MIN_MINOR;
|
|
51
|
+
}
|
|
52
|
+
function removeExpiredReports(reported, now) {
|
|
53
|
+
for (const [message, reportedAt] of reported){
|
|
54
|
+
if (now - reportedAt < REPORT_WINDOW_MS) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
reported.delete(message);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
function shouldReport(reported, cappedMessage) {
|
|
61
|
+
const now = performance.now();
|
|
62
|
+
removeExpiredReports(reported, now);
|
|
63
|
+
if (reported.has(cappedMessage) || reported.size >= MAX_DISTINCT_MESSAGES_PER_WINDOW) {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
reported.set(cappedMessage, now);
|
|
67
|
+
return true;
|
|
68
|
+
}
|
|
69
|
+
// Reanimated already prints every log to the console, so this only reports to Observe. The name
|
|
70
|
+
// is specific to Observe, so `removeFirstFrame` cannot remove a frame of an app function.
|
|
71
|
+
function __expo_observe_reportReanimatedLog({ level, message }) {
|
|
72
|
+
if (!isEnabled) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const isError = level === LOG_LEVEL_ERROR;
|
|
76
|
+
if (!isError && !shouldReportWarnings) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const cappedMessage = message.slice(0, MAX_MESSAGE_LENGTH);
|
|
80
|
+
if (!shouldReport(isError ? reportedErrors : reportedWarnings, cappedMessage)) {
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
if (isError) {
|
|
84
|
+
// For a log on the React Native runtime, Reanimated calls `onLog` synchronously, so this
|
|
85
|
+
// stack includes the frames that led to the log. A log on the UI runtime is delivered later,
|
|
86
|
+
// so its stack has no frames left after `removeFirstFrame`.
|
|
87
|
+
const stack = removeFirstFrame(new Error(message).stack, __expo_observe_reportReanimatedLog.name);
|
|
88
|
+
reportCaughtError(new ReanimatedError(message, stack), 'integration');
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
AppMetrics.logEvent(REANIMATED_WARNING_EVENT, {
|
|
92
|
+
displayName: 'Reanimated warning',
|
|
93
|
+
body: message,
|
|
94
|
+
severity: 'warn',
|
|
95
|
+
// `eas observe:events` and `observe:session` show `attributes` but not `body`, so the
|
|
96
|
+
// message is copied here to stay queryable.
|
|
97
|
+
attributes: {
|
|
98
|
+
message: cappedMessage
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Configures Reanimated's logger with the integration's `level` and `strict` settings and a
|
|
104
|
+
* callback that reports Reanimated errors to Observe as `reanimated.error` errors. When
|
|
105
|
+
* `reportWarnings` is set, the callback also reports Reanimated warnings as `reanimated.warning`
|
|
106
|
+
* events.
|
|
107
|
+
*/ export function initReanimatedIntegration(config) {
|
|
108
|
+
const reanimated = loadReanimated();
|
|
109
|
+
if (!reanimated) {
|
|
110
|
+
console.warn("[expo-observe] `integrations: { 'react-native-reanimated': ... }` was set, but " + '`react-native-reanimated` is not installed. The integration will not initialize.');
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
if (!supportsOnLog(reanimated.version)) {
|
|
114
|
+
console.warn(`[expo-observe] The 'react-native-reanimated' integration requires Reanimated 4.7.0 or later, ` + `but Reanimated ${reanimated.version} is installed. Reanimated errors and warnings will not be ` + 'reported to EAS Observe. Upgrade react-native-reanimated to 4.7.0 or later.');
|
|
115
|
+
return;
|
|
116
|
+
}
|
|
117
|
+
const { reportWarnings = false, ...loggerConfig } = typeof config === 'object' ? config : {};
|
|
118
|
+
reanimated.configureReanimatedLogger(loggerConfig, __expo_observe_reportReanimatedLog);
|
|
119
|
+
shouldReportWarnings = reportWarnings;
|
|
120
|
+
isEnabled = true;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Stops reporting Reanimated errors and warnings to Observe. Reanimated's logger keeps its
|
|
124
|
+
* configuration.
|
|
125
|
+
*/ export function disableReanimatedIntegration() {
|
|
126
|
+
isEnabled = false;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
//# sourceMappingURL=init.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["integrations/react-native-reanimated/init.ts"],"sourcesContent":[null],"names":["AppMetrics","reportCaughtError","loadReanimated","removeFirstFrame","LOG_LEVEL_ERROR","MIN_MAJOR","MIN_MINOR","REANIMATED_ERROR_NAME","REANIMATED_WARNING_EVENT","REPORT_WINDOW_MS","MAX_DISTINCT_MESSAGES_PER_WINDOW","MAX_MESSAGE_LENGTH","reportedErrors","Map","reportedWarnings","isEnabled","shouldReportWarnings","ReanimatedError","Error","message","stack","name","undefined","supportsOnLog","version","match","exec","major","Number","minor","removeExpiredReports","reported","now","reportedAt","delete","shouldReport","cappedMessage","performance","has","size","set","__expo_observe_reportReanimatedLog","level","isError","slice","logEvent","displayName","body","severity","attributes","initReanimatedIntegration","config","reanimated","console","warn","reportWarnings","loggerConfig","configureReanimatedLogger","disableReanimatedIntegration"],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export type ReanimatedLogData = {
|
|
2
|
+
level: number;
|
|
3
|
+
message: string;
|
|
4
|
+
};
|
|
5
|
+
export type ReanimatedLoggerConfig = {
|
|
6
|
+
level?: number;
|
|
7
|
+
strict?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export interface LoadedReanimated {
|
|
10
|
+
version: string;
|
|
11
|
+
configureReanimatedLogger(config: ReanimatedLoggerConfig, onLog?: (data: ReanimatedLogData) => void): void;
|
|
12
|
+
}
|
|
13
|
+
export declare function loadReanimated(): LoadedReanimated | null;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// react-native-reanimated is an optional peerDependency of expo-observe. It is required lazily,
|
|
2
|
+
// only when the integration is enabled, so an app that doesn't enable it never loads Reanimated
|
|
3
|
+
// through expo-observe. This lives in its own file because a `require` wrapped in try/catch
|
|
4
|
+
// doesn't work with Metro's `inlineRequires` when it shares a file with other imports (see
|
|
5
|
+
// expo-gl's `GLWorkletContextManager`).
|
|
6
|
+
export function loadReanimated() {
|
|
7
|
+
try {
|
|
8
|
+
const { reanimatedVersion, configureReanimatedLogger } = require('react-native-reanimated');
|
|
9
|
+
return {
|
|
10
|
+
version: reanimatedVersion,
|
|
11
|
+
configureReanimatedLogger
|
|
12
|
+
};
|
|
13
|
+
} catch {
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=reanimated.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["integrations/react-native-reanimated/reanimated.ts"],"sourcesContent":[null],"names":["loadReanimated","reanimatedVersion","configureReanimatedLogger","require","version"],"mappings":"AAAA,gGAAgG;AAChG,gGAAgG;AAChG,4FAA4F;AAC5F,2FAA2F;AAC3F,wCAAwC;AAcxC,OAAO,SAASA;IACd,IAAI;QACF,MAAM,EAAEC,iBAAiB,EAAEC,yBAAyB,EAAE,GAAGC,QAAQ;QAIjE,OAAO;YAAEC,SAASH;YAAmBC;QAA0B;IACjE,EAAE,OAAM;QACN,OAAO;IACT;AACF"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Removes the first frame of the stack when it is a frame of `functionName`. The message can
|
|
3
|
+
* contain newlines, so the first frame is the first line that is a stack frame.
|
|
4
|
+
*/
|
|
5
|
+
export declare function removeFirstFrame(stack: string | undefined, functionName: string): string | undefined;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
const STACK_FRAME_PATTERN = /^\s*at /;
|
|
2
|
+
function escapeRegExp(text) {
|
|
3
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Removes the first frame of the stack when it is a frame of `functionName`. The message can
|
|
7
|
+
* contain newlines, so the first frame is the first line that is a stack frame.
|
|
8
|
+
*/ export function removeFirstFrame(stack, functionName) {
|
|
9
|
+
if (stack === undefined) {
|
|
10
|
+
return undefined;
|
|
11
|
+
}
|
|
12
|
+
const lines = stack.split('\n');
|
|
13
|
+
const firstFrameIndex = lines.findIndex((line)=>STACK_FRAME_PATTERN.test(line));
|
|
14
|
+
if (firstFrameIndex === -1) {
|
|
15
|
+
return stack;
|
|
16
|
+
}
|
|
17
|
+
const functionFramePattern = new RegExp(`^\\s*at ${escapeRegExp(functionName)} `);
|
|
18
|
+
if (!functionFramePattern.test(lines[firstFrameIndex] ?? '')) {
|
|
19
|
+
return stack;
|
|
20
|
+
}
|
|
21
|
+
return [
|
|
22
|
+
...lines.slice(0, firstFrameIndex),
|
|
23
|
+
...lines.slice(firstFrameIndex + 1)
|
|
24
|
+
].join('\n');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
//# sourceMappingURL=stack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["integrations/react-native-reanimated/stack.ts"],"sourcesContent":[null],"names":["STACK_FRAME_PATTERN","escapeRegExp","text","replace","removeFirstFrame","stack","functionName","undefined","lines","split","firstFrameIndex","findIndex","line","test","functionFramePattern","RegExp","slice","join"],"mappings":"AAAA,MAAMA,sBAAsB;AAE5B,SAASC,aAAaC,IAAY;IAChC,OAAOA,KAAKC,OAAO,CAAC,uBAAuB;AAC7C;AAEA;;;CAGC,GACD,OAAO,SAASC,iBACdC,KAAyB,EACzBC,YAAoB;IAEpB,IAAID,UAAUE,WAAW;QACvB,OAAOA;IACT;IACA,MAAMC,QAAQH,MAAMI,KAAK,CAAC;IAC1B,MAAMC,kBAAkBF,MAAMG,SAAS,CAAC,CAACC,OAASZ,oBAAoBa,IAAI,CAACD;IAC3E,IAAIF,oBAAoB,CAAC,GAAG;QAC1B,OAAOL;IACT;IACA,MAAMS,uBAAuB,IAAIC,OAAO,CAAC,QAAQ,EAAEd,aAAaK,cAAc,CAAC,CAAC;IAChF,IAAI,CAACQ,qBAAqBD,IAAI,CAACL,KAAK,CAACE,gBAAgB,IAAI,KAAK;QAC5D,OAAOL;IACT;IACA,OAAO;WAAIG,MAAMQ,KAAK,CAAC,GAAGN;WAAqBF,MAAMQ,KAAK,CAACN,kBAAkB;KAAG,CAACO,IAAI,CAAC;AACxF"}
|
package/build/module.js
CHANGED
|
@@ -2,6 +2,7 @@ import { requireNativeModule } from 'expo';
|
|
|
2
2
|
import AppMetrics, { setErrorHandlerEnabled } from 'expo-app-metrics';
|
|
3
3
|
import { initRouterIntegration } from './integrations/expo-router/init';
|
|
4
4
|
import { isRouterInstalled } from './integrations/expo-router/router';
|
|
5
|
+
import { disableReanimatedIntegration, initReanimatedIntegration } from './integrations/react-native-reanimated/init';
|
|
5
6
|
import { initReactNavigationIntegration } from './integrations/react-navigation/init';
|
|
6
7
|
import { isReactNavigationInstalled } from './integrations/react-navigation/reactNavigation';
|
|
7
8
|
import { reportCaughtError } from './reportCaughtError';
|
|
@@ -64,6 +65,12 @@ const Observe = new Proxy(native, {
|
|
|
64
65
|
} else if (shouldInitReactNavigationIntegration) {
|
|
65
66
|
initReactNavigationIntegration(config.integrations?.['react-navigation']);
|
|
66
67
|
}
|
|
68
|
+
const reanimatedConfig = config.integrations?.['react-native-reanimated'];
|
|
69
|
+
if (reanimatedConfig) {
|
|
70
|
+
initReanimatedIntegration(reanimatedConfig);
|
|
71
|
+
} else {
|
|
72
|
+
disableReanimatedIntegration();
|
|
73
|
+
}
|
|
67
74
|
return target.configure(config);
|
|
68
75
|
};
|
|
69
76
|
}
|
package/build/module.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["module.ts"],"sourcesContent":[null],"names":["requireNativeModule","AppMetrics","setErrorHandlerEnabled","initRouterIntegration","isRouterInstalled","initReactNavigationIntegration","isReactNavigationInstalled","reportCaughtError","networkTracesConfigFromOption","networkTraces","option","enabled","__DEV__","malformed","filter","hosts","host","test","length","console","warn","join","native","Observe","Proxy","get","target","prop","receiver","config","errorHandlingEnabled","setNetworkTracesConfig","routerEnabled","integrations","reactNavigationEnabled","shouldInitRouterIntegration","shouldInitReactNavigationIntegration","configure","error","name","callback","registerIntegrationImpl","Object","keys","includes","Reflect","getIntegrations","subscription","addListener","remove"],"mappings":"AAAA,SAASA,mBAAmB,QAAQ,OAAO;AAC3C,OAAOC,cAAcC,sBAAsB,QAAQ,mBAAmB;AAEtE,SAASC,qBAAqB,QAAQ,kCAAkC;AACxE,SAASC,iBAAiB,QAAQ,oCAAoC;AACtE,SAASC,8BAA8B,QAAQ,uCAAuC;AACtF,SAASC,0BAA0B,QAAQ,kDAAkD;AAC7F,SAASC,iBAAiB,QAAQ,sBAAsB;AAGxD;;;;CAIC,GACD,SAASC,8BAA8BC,aAA6C;IAClF,MAAMC,SAASD,iBAAiB;IAChC,IAAI,OAAOC,WAAW,WAAW;QAC/B,OAAO;YAAEC,SAASD;QAAO;IAC3B;IACA,IAAIE,SAAS;QACX,uFAAuF;QACvF,4CAA4C;QAC5C,MAAMC,YAAYH,OAAOI,MAAM,EAAEC,OAAOD,OAAO,CAACE,OAAS,OAAOC,IAAI,CAACD;QACrE,IAAIH,WAAWK,QAAQ;YACrBC,QAAQC,IAAI,CACV,CAAC,8EAA8E,EAAEP,UAAUQ,IAAI,CAAC,MAAM,EAAE,CAAC,GACvG;QAEN;IACF;IACA,0FAA0F;IAC1F,wFAAwF;IACxF,MAAMV,UAAUD,OAAOC,OAAO,IAAI;IAClC,OAAOD,OAAOI,MAAM,IAAI,OAAO;QAAEH;QAASG,QAAQJ,OAAOI,MAAM;IAAC,IAAI;QAAEH;IAAQ;AAChF;AAEA,MAAMW,
|
|
1
|
+
{"version":3,"sources":["module.ts"],"sourcesContent":[null],"names":["requireNativeModule","AppMetrics","setErrorHandlerEnabled","initRouterIntegration","isRouterInstalled","disableReanimatedIntegration","initReanimatedIntegration","initReactNavigationIntegration","isReactNavigationInstalled","reportCaughtError","networkTracesConfigFromOption","networkTraces","option","enabled","__DEV__","malformed","filter","hosts","host","test","length","console","warn","join","native","Observe","Proxy","get","target","prop","receiver","config","errorHandlingEnabled","setNetworkTracesConfig","routerEnabled","integrations","reactNavigationEnabled","shouldInitRouterIntegration","shouldInitReactNavigationIntegration","reanimatedConfig","configure","error","name","callback","registerIntegrationImpl","Object","keys","includes","Reflect","getIntegrations","subscription","addListener","remove"],"mappings":"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"}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Reports a caught value as a non-fatal
|
|
3
|
-
*
|
|
2
|
+
* Reports a caught value as a non-fatal error through the AppMetrics module, shared by the native
|
|
3
|
+
* and web `Observe.reportError` implementations and by integrations. `source` is `reportedByUser`
|
|
4
|
+
* for an error the app reports, and `integration` for an error an integration reports for a library.
|
|
4
5
|
*
|
|
5
6
|
* Never throws: it's called from a `catch` block, so a failure here (a pathological thrown value, or
|
|
6
7
|
* a native call that rejects the payload) must not turn a handled error into an unhandled one.
|
|
7
8
|
*/
|
|
8
|
-
export declare function reportCaughtError(error: unknown): void;
|
|
9
|
+
export declare function reportCaughtError(error: unknown, source?: 'reportedByUser' | 'integration'): void;
|
|
@@ -22,15 +22,16 @@ import AppMetrics from 'expo-app-metrics';
|
|
|
22
22
|
};
|
|
23
23
|
}
|
|
24
24
|
/**
|
|
25
|
-
* Reports a caught value as a non-fatal
|
|
26
|
-
*
|
|
25
|
+
* Reports a caught value as a non-fatal error through the AppMetrics module, shared by the native
|
|
26
|
+
* and web `Observe.reportError` implementations and by integrations. `source` is `reportedByUser`
|
|
27
|
+
* for an error the app reports, and `integration` for an error an integration reports for a library.
|
|
27
28
|
*
|
|
28
29
|
* Never throws: it's called from a `catch` block, so a failure here (a pathological thrown value, or
|
|
29
30
|
* a native call that rejects the payload) must not turn a handled error into an unhandled one.
|
|
30
|
-
*/ export function reportCaughtError(error) {
|
|
31
|
+
*/ export function reportCaughtError(error, source = 'reportedByUser') {
|
|
31
32
|
try {
|
|
32
33
|
AppMetrics.reportError({
|
|
33
|
-
source
|
|
34
|
+
source,
|
|
34
35
|
...normalizeReportedError(error),
|
|
35
36
|
isFatal: false
|
|
36
37
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["reportCaughtError.ts"],"sourcesContent":[null],"names":["AppMetrics","stringOrUndefined","value","undefined","normalizeReportedError","error","Error","type","name","message","String","stacktrace","stack","reportCaughtError","
|
|
1
|
+
{"version":3,"sources":["reportCaughtError.ts"],"sourcesContent":[null],"names":["AppMetrics","stringOrUndefined","value","undefined","normalizeReportedError","error","Error","type","name","message","String","stacktrace","stack","reportCaughtError","source","reportError","isFatal","reportingError","__DEV__","console","warn"],"mappings":"AAAA,OAAOA,gBAAgB,mBAAmB;AAa1C,wGAAwG,GACxG,SAASC,kBAAkBC,KAAc;IACvC,OAAO,OAAOA,UAAU,WAAWA,QAAQC;AAC7C;AAEA;;;CAGC,GACD,SAASC,uBAAuBC,KAAc;IAC5C,iGAAiG;IACjG,mGAAmG;IACnG,yCAAyC;IACzC,IAAIA,iBAAiBC,OAAO;QAC1B,OAAO;YACLC,MAAMN,kBAAkBI,MAAMG,IAAI;YAClCC,SAASR,kBAAkBI,MAAMI,OAAO,KAAKC,OAAOL;YACpDM,YAAYV,kBAAkBI,MAAMO,KAAK;QAC3C;IACF;IACA,kGAAkG;IAClG,OAAO;QAAEH,SAASC,OAAOL;IAAO;AAClC;AAEA;;;;;;;CAOC,GACD,OAAO,SAASQ,kBACdR,KAAc,EACdS,SAA2C,gBAAgB;IAE3D,IAAI;QACFd,WAAWe,WAAW,CAAC;YACrBD;YACA,GAAGV,uBAAuBC,MAAM;YAChCW,SAAS;QACX;IACF,EAAE,OAAOC,gBAAgB;QACvB,IAAIC,SAAS;YACXC,QAAQC,IAAI,CAAC,4DAA4DH;QAC3E;IACF;AACF"}
|
package/build/types.d.ts
CHANGED
|
@@ -139,7 +139,47 @@ export interface ObserveIntegrationsConfig {
|
|
|
139
139
|
* @default false
|
|
140
140
|
*/
|
|
141
141
|
'react-navigation'?: boolean | ObserveNavigationIntegrationConfig;
|
|
142
|
+
/**
|
|
143
|
+
* Enables the `react-native-reanimated` integration, which reports Reanimated errors to Observe
|
|
144
|
+
* as errors named `reanimated.error`. To also report Reanimated warnings as events named
|
|
145
|
+
* `reanimated.warning`, set `reportWarnings`. Reanimated still prints errors and warnings to the
|
|
146
|
+
* console. The integration reports each distinct message at most once every 15 minutes. It
|
|
147
|
+
* reports at most 20 distinct errors and 20 distinct warnings in any 15-minute period.
|
|
148
|
+
*
|
|
149
|
+
* Requires `react-native-reanimated` 4.7.0 or later to be installed.
|
|
150
|
+
*
|
|
151
|
+
* The integration configures Reanimated's logger with `configureReanimatedLogger`. To set the
|
|
152
|
+
* logger's `level` and `strict` options, pass an object here. Don't call
|
|
153
|
+
* `configureReanimatedLogger` in your app. A later call removes the integration's callback, and
|
|
154
|
+
* the integration replaces the `level` and `strict` options of an earlier call.
|
|
155
|
+
*
|
|
156
|
+
* @default false
|
|
157
|
+
*/
|
|
158
|
+
'react-native-reanimated'?: boolean | ObserveReanimatedIntegrationConfig;
|
|
142
159
|
}
|
|
160
|
+
export type ObserveReanimatedIntegrationConfig = {
|
|
161
|
+
/**
|
|
162
|
+
* The minimum log level that Reanimated prints and reports. Pass a `ReanimatedLogLevel` value
|
|
163
|
+
* from `react-native-reanimated`: `ReanimatedLogLevel.warn` (`1`) or `ReanimatedLogLevel.error`
|
|
164
|
+
* (`2`).
|
|
165
|
+
*
|
|
166
|
+
* @default ReanimatedLogLevel.warn
|
|
167
|
+
*/
|
|
168
|
+
level?: 1 | 2;
|
|
169
|
+
/**
|
|
170
|
+
* Whether Reanimated also prints and reports its strict-mode warnings.
|
|
171
|
+
*
|
|
172
|
+
* @default true
|
|
173
|
+
*/
|
|
174
|
+
strict?: boolean;
|
|
175
|
+
/**
|
|
176
|
+
* Whether the integration also reports Reanimated warnings to Observe, as events named
|
|
177
|
+
* `reanimated.warning`. Reanimated prints warnings to the console either way.
|
|
178
|
+
*
|
|
179
|
+
* @default false
|
|
180
|
+
*/
|
|
181
|
+
reportWarnings?: boolean;
|
|
182
|
+
};
|
|
143
183
|
/**
|
|
144
184
|
* Events emitted by the native `ExpoObserve` module.
|
|
145
185
|
*/
|
package/build/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["types.ts"],"sourcesContent":[null],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"sources":["types.ts"],"sourcesContent":[null],"names":[],"mappings":"AA8MA,WAyJC"}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
6635ff468ff08ed50dde81ad0ab24bc1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
27be8bc32a8afbb84df92ec0966eeeed1b206829
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
c76770935713ad519193541fcb769a2fcd68f23a401d6c698843d84fbd1f7da0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
997be2ee63594820e4184fbce65b61a4beba2716682ee30161b4fa92db554a7e2c8a100a6ff1c88db10d484d0f72c35a49b258b22d703329cae6d67e2d69d037
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
cca677ea690b4997313e35cef5f73f5d
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
04943132c7c93348101691ce33046bede7b17c4d
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
c37c74fe309480e5f5278110bcdcd8c8ed1cdda889aa88a6a4ea03b8e78b3bd7
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
2c1a46d58d9c82b8c127e42c234cade56a9ba2d7aafec09204ce6cf173461dcde7c88d698dcf39b7912c069519ce3848c7df5a78278ca5e2c26c1c77e3520d54
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"component": {
|
|
4
4
|
"group": "expo.modules.observe",
|
|
5
5
|
"module": "expo.modules.observe",
|
|
6
|
-
"version": "58.0.
|
|
6
|
+
"version": "58.0.16",
|
|
7
7
|
"attributes": {
|
|
8
8
|
"org.gradle.status": "release"
|
|
9
9
|
}
|
|
@@ -24,13 +24,13 @@
|
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
{
|
|
27
|
-
"name": "expo.modules.observe-58.0.
|
|
28
|
-
"url": "expo.modules.observe-58.0.
|
|
29
|
-
"size":
|
|
30
|
-
"sha512": "
|
|
31
|
-
"sha256": "
|
|
32
|
-
"sha1": "
|
|
33
|
-
"md5": "
|
|
27
|
+
"name": "expo.modules.observe-58.0.16.aar",
|
|
28
|
+
"url": "expo.modules.observe-58.0.16.aar",
|
|
29
|
+
"size": 302597,
|
|
30
|
+
"sha512": "2c1a46d58d9c82b8c127e42c234cade56a9ba2d7aafec09204ce6cf173461dcde7c88d698dcf39b7912c069519ce3848c7df5a78278ca5e2c26c1c77e3520d54",
|
|
31
|
+
"sha256": "c37c74fe309480e5f5278110bcdcd8c8ed1cdda889aa88a6a4ea03b8e78b3bd7",
|
|
32
|
+
"sha1": "04943132c7c93348101691ce33046bede7b17c4d",
|
|
33
|
+
"md5": "cca677ea690b4997313e35cef5f73f5d"
|
|
34
34
|
}
|
|
35
35
|
]
|
|
36
36
|
},
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"group": "expo.modules.appmetrics",
|
|
62
62
|
"module": "expo.modules.appmetrics",
|
|
63
63
|
"version": {
|
|
64
|
-
"requires": "58.0.
|
|
64
|
+
"requires": "58.0.14"
|
|
65
65
|
}
|
|
66
66
|
},
|
|
67
67
|
{
|
|
@@ -120,13 +120,13 @@
|
|
|
120
120
|
],
|
|
121
121
|
"files": [
|
|
122
122
|
{
|
|
123
|
-
"name": "expo.modules.observe-58.0.
|
|
124
|
-
"url": "expo.modules.observe-58.0.
|
|
125
|
-
"size":
|
|
126
|
-
"sha512": "
|
|
127
|
-
"sha256": "
|
|
128
|
-
"sha1": "
|
|
129
|
-
"md5": "
|
|
123
|
+
"name": "expo.modules.observe-58.0.16.aar",
|
|
124
|
+
"url": "expo.modules.observe-58.0.16.aar",
|
|
125
|
+
"size": 302597,
|
|
126
|
+
"sha512": "2c1a46d58d9c82b8c127e42c234cade56a9ba2d7aafec09204ce6cf173461dcde7c88d698dcf39b7912c069519ce3848c7df5a78278ca5e2c26c1c77e3520d54",
|
|
127
|
+
"sha256": "c37c74fe309480e5f5278110bcdcd8c8ed1cdda889aa88a6a4ea03b8e78b3bd7",
|
|
128
|
+
"sha1": "04943132c7c93348101691ce33046bede7b17c4d",
|
|
129
|
+
"md5": "cca677ea690b4997313e35cef5f73f5d"
|
|
130
130
|
}
|
|
131
131
|
]
|
|
132
132
|
},
|
|
@@ -140,13 +140,13 @@
|
|
|
140
140
|
},
|
|
141
141
|
"files": [
|
|
142
142
|
{
|
|
143
|
-
"name": "expo.modules.observe-58.0.
|
|
144
|
-
"url": "expo.modules.observe-58.0.
|
|
143
|
+
"name": "expo.modules.observe-58.0.16-sources.jar",
|
|
144
|
+
"url": "expo.modules.observe-58.0.16-sources.jar",
|
|
145
145
|
"size": 27883,
|
|
146
|
-
"sha512": "
|
|
147
|
-
"sha256": "
|
|
148
|
-
"sha1": "
|
|
149
|
-
"md5": "
|
|
146
|
+
"sha512": "997be2ee63594820e4184fbce65b61a4beba2716682ee30161b4fa92db554a7e2c8a100a6ff1c88db10d484d0f72c35a49b258b22d703329cae6d67e2d69d037",
|
|
147
|
+
"sha256": "c76770935713ad519193541fcb769a2fcd68f23a401d6c698843d84fbd1f7da0",
|
|
148
|
+
"sha1": "27be8bc32a8afbb84df92ec0966eeeed1b206829",
|
|
149
|
+
"md5": "6635ff468ff08ed50dde81ad0ab24bc1"
|
|
150
150
|
}
|
|
151
151
|
]
|
|
152
152
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
22fd3986bf62551fe671e3f9a4e09c0d
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
8f1598df2f9dfc033a10d0a150dabad37849f3ee
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
0cbea66a354c468fbfd8c6b7e27a396655687fcc010f76d68d437f4b8d2b0f05
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
929b60dbf425200c3dd9e14d8f86ea53a9367d4adab82207f010b8fa306afb65e528e9654a5ebd2c6810031a530d86ab784dc3b369c94180ea93d291fe6fa9c3
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
<modelVersion>4.0.0</modelVersion>
|
|
10
10
|
<groupId>expo.modules.observe</groupId>
|
|
11
11
|
<artifactId>expo.modules.observe</artifactId>
|
|
12
|
-
<version>58.0.
|
|
12
|
+
<version>58.0.16</version>
|
|
13
13
|
<packaging>aar</packaging>
|
|
14
14
|
<name>expo.modules.observe</name>
|
|
15
15
|
<url>https://github.com/expo/expo</url>
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
<dependency>
|
|
53
53
|
<groupId>expo.modules.appmetrics</groupId>
|
|
54
54
|
<artifactId>expo.modules.appmetrics</artifactId>
|
|
55
|
-
<version>58.0.
|
|
55
|
+
<version>58.0.14</version>
|
|
56
56
|
<scope>runtime</scope>
|
|
57
57
|
</dependency>
|
|
58
58
|
<dependency>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
b8b751a107f58eadfcf70ca09f900ac3
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1578e69d0a68eb426a0c1f7e6a59f89e051cd0e9
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
a1eab751d5bb4b299af12ad881d4f942a16765461052b1bc12595b6a622153c6
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
06fcee23ec778c6ea48b9face7250f15854c047c580b37fcef3a2f8c65f1c442b5a1fb4faab2c6f729edd94d01c7ec5899d4cb9de52f2a0100e27b37aac0f8d5
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-observe",
|
|
3
|
-
"version": "58.0.
|
|
3
|
+
"version": "58.0.16",
|
|
4
4
|
"description": "Expo module that dispatches collected app metrics to EAS Observe",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"EAS",
|
|
@@ -42,22 +42,25 @@
|
|
|
42
42
|
}
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"expo-app-metrics": "~58.0.
|
|
45
|
+
"expo-app-metrics": "~58.0.14",
|
|
46
46
|
"expo-eas-client": "~58.0.2"
|
|
47
47
|
},
|
|
48
48
|
"devDependencies": {
|
|
49
|
-
"@expo/internal-scripts": "58.0.
|
|
49
|
+
"@expo/internal-scripts": "58.0.4",
|
|
50
50
|
"@react-navigation/native": "^7.1.33",
|
|
51
51
|
"@testing-library/react-native": "^14.0.1",
|
|
52
52
|
"@types/react": "~19.3.0",
|
|
53
|
-
"expo": "58.0.
|
|
53
|
+
"expo": "58.0.17",
|
|
54
|
+
"react-native-reanimated": "4.7.0",
|
|
55
|
+
"react-native-worklets": "0.13.0"
|
|
54
56
|
},
|
|
55
57
|
"peerDependencies": {
|
|
56
58
|
"@react-navigation/native": "^7.0.0",
|
|
57
59
|
"expo": "*",
|
|
58
60
|
"expo-router": "*",
|
|
59
61
|
"react": "*",
|
|
60
|
-
"react-native": "*"
|
|
62
|
+
"react-native": "*",
|
|
63
|
+
"react-native-reanimated": ">=4.7.0"
|
|
61
64
|
},
|
|
62
65
|
"peerDependenciesMeta": {
|
|
63
66
|
"expo-router": {
|
|
@@ -65,6 +68,9 @@
|
|
|
65
68
|
},
|
|
66
69
|
"@react-navigation/native": {
|
|
67
70
|
"optional": true
|
|
71
|
+
},
|
|
72
|
+
"react-native-reanimated": {
|
|
73
|
+
"optional": true
|
|
68
74
|
}
|
|
69
75
|
},
|
|
70
76
|
"title": "Expo Observe",
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import AppMetrics from 'expo-app-metrics';
|
|
2
|
+
|
|
3
|
+
import { reportCaughtError } from '../../reportCaughtError';
|
|
4
|
+
import type { ObserveIntegrationsConfig } from '../../types';
|
|
5
|
+
import { loadReanimated, type ReanimatedLogData } from './reanimated';
|
|
6
|
+
import { removeFirstFrame } from './stack';
|
|
7
|
+
|
|
8
|
+
// Value of Reanimated's `ReanimatedLogLevel.error`.
|
|
9
|
+
const LOG_LEVEL_ERROR = 2;
|
|
10
|
+
|
|
11
|
+
// `configureReanimatedLogger` accepts an `onLog` callback since Reanimated 4.7.0.
|
|
12
|
+
const MIN_MAJOR = 4;
|
|
13
|
+
const MIN_MINOR = 7;
|
|
14
|
+
|
|
15
|
+
const REANIMATED_ERROR_NAME = 'reanimated.error';
|
|
16
|
+
const REANIMATED_WARNING_EVENT = 'reanimated.warning';
|
|
17
|
+
|
|
18
|
+
// A UI-runtime log can repeat every frame, so each distinct message is reported at most once per
|
|
19
|
+
// window. The cap bounds the reports in a window when messages embed varying values, and the
|
|
20
|
+
// window lets new messages be reported again after a surge. Errors and warnings have separate
|
|
21
|
+
// windows, so a screen with many distinct warnings cannot stop errors from being reported.
|
|
22
|
+
const REPORT_WINDOW_MS = 15 * 60_000;
|
|
23
|
+
const MAX_DISTINCT_MESSAGES_PER_WINDOW = 20;
|
|
24
|
+
// Attribute values are sent on every dispatch, and strict-mode messages append a docs
|
|
25
|
+
// reference, so the copied message is capped. Messages are also deduplicated by this capped
|
|
26
|
+
// text, so two messages that differ only after the cap do not send the same attribute twice.
|
|
27
|
+
const MAX_MESSAGE_LENGTH = 500;
|
|
28
|
+
|
|
29
|
+
// Maps the capped text of each message reported in the current window to the time it was
|
|
30
|
+
// reported. A `Map` keeps insertion order, so the oldest report is always first. The time comes
|
|
31
|
+
// from the monotonic `performance.now()`, so a change to the device clock cannot stop expiry.
|
|
32
|
+
const reportedErrors = new Map<string, number>();
|
|
33
|
+
const reportedWarnings = new Map<string, number>();
|
|
34
|
+
|
|
35
|
+
// The callback stays registered in Reanimated after the integration is turned off, because
|
|
36
|
+
// configuring the logger again would reset the app's `level` and `strict`. It checks this flag.
|
|
37
|
+
let isEnabled = false;
|
|
38
|
+
let shouldReportWarnings = false;
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* A Reanimated error reported to Observe. The stack is set explicitly so it points at the
|
|
42
|
+
* callback's caller rather than at this constructor.
|
|
43
|
+
*/
|
|
44
|
+
class ReanimatedError extends Error {
|
|
45
|
+
constructor(message: string, stack: string | undefined) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.name = REANIMATED_ERROR_NAME;
|
|
48
|
+
if (stack !== undefined) {
|
|
49
|
+
this.stack = stack;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function supportsOnLog(version: string): boolean {
|
|
55
|
+
const match = /^(\d+)\.(\d+)/.exec(version);
|
|
56
|
+
if (!match) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
const major = Number(match[1]);
|
|
60
|
+
const minor = Number(match[2]);
|
|
61
|
+
return major > MIN_MAJOR || (major === MIN_MAJOR && minor >= MIN_MINOR);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function removeExpiredReports(reported: Map<string, number>, now: number): void {
|
|
65
|
+
for (const [message, reportedAt] of reported) {
|
|
66
|
+
if (now - reportedAt < REPORT_WINDOW_MS) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
reported.delete(message);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function shouldReport(reported: Map<string, number>, cappedMessage: string): boolean {
|
|
74
|
+
const now = performance.now();
|
|
75
|
+
removeExpiredReports(reported, now);
|
|
76
|
+
if (reported.has(cappedMessage) || reported.size >= MAX_DISTINCT_MESSAGES_PER_WINDOW) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
reported.set(cappedMessage, now);
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// Reanimated already prints every log to the console, so this only reports to Observe. The name
|
|
84
|
+
// is specific to Observe, so `removeFirstFrame` cannot remove a frame of an app function.
|
|
85
|
+
function __expo_observe_reportReanimatedLog({ level, message }: ReanimatedLogData): void {
|
|
86
|
+
if (!isEnabled) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
const isError = level === LOG_LEVEL_ERROR;
|
|
90
|
+
if (!isError && !shouldReportWarnings) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const cappedMessage = message.slice(0, MAX_MESSAGE_LENGTH);
|
|
94
|
+
if (!shouldReport(isError ? reportedErrors : reportedWarnings, cappedMessage)) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
if (isError) {
|
|
98
|
+
// For a log on the React Native runtime, Reanimated calls `onLog` synchronously, so this
|
|
99
|
+
// stack includes the frames that led to the log. A log on the UI runtime is delivered later,
|
|
100
|
+
// so its stack has no frames left after `removeFirstFrame`.
|
|
101
|
+
const stack = removeFirstFrame(
|
|
102
|
+
new Error(message).stack,
|
|
103
|
+
__expo_observe_reportReanimatedLog.name
|
|
104
|
+
);
|
|
105
|
+
reportCaughtError(new ReanimatedError(message, stack), 'integration');
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
AppMetrics.logEvent(REANIMATED_WARNING_EVENT, {
|
|
109
|
+
displayName: 'Reanimated warning',
|
|
110
|
+
body: message,
|
|
111
|
+
severity: 'warn',
|
|
112
|
+
// `eas observe:events` and `observe:session` show `attributes` but not `body`, so the
|
|
113
|
+
// message is copied here to stay queryable.
|
|
114
|
+
attributes: { message: cappedMessage },
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Configures Reanimated's logger with the integration's `level` and `strict` settings and a
|
|
120
|
+
* callback that reports Reanimated errors to Observe as `reanimated.error` errors. When
|
|
121
|
+
* `reportWarnings` is set, the callback also reports Reanimated warnings as `reanimated.warning`
|
|
122
|
+
* events.
|
|
123
|
+
*/
|
|
124
|
+
export function initReanimatedIntegration(
|
|
125
|
+
config: NonNullable<ObserveIntegrationsConfig['react-native-reanimated']>
|
|
126
|
+
): void {
|
|
127
|
+
const reanimated = loadReanimated();
|
|
128
|
+
if (!reanimated) {
|
|
129
|
+
console.warn(
|
|
130
|
+
"[expo-observe] `integrations: { 'react-native-reanimated': ... }` was set, but " +
|
|
131
|
+
'`react-native-reanimated` is not installed. The integration will not initialize.'
|
|
132
|
+
);
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
if (!supportsOnLog(reanimated.version)) {
|
|
137
|
+
console.warn(
|
|
138
|
+
`[expo-observe] The 'react-native-reanimated' integration requires Reanimated 4.7.0 or later, ` +
|
|
139
|
+
`but Reanimated ${reanimated.version} is installed. Reanimated errors and warnings will not be ` +
|
|
140
|
+
'reported to EAS Observe. Upgrade react-native-reanimated to 4.7.0 or later.'
|
|
141
|
+
);
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const { reportWarnings = false, ...loggerConfig } = typeof config === 'object' ? config : {};
|
|
146
|
+
reanimated.configureReanimatedLogger(loggerConfig, __expo_observe_reportReanimatedLog);
|
|
147
|
+
shouldReportWarnings = reportWarnings;
|
|
148
|
+
isEnabled = true;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Stops reporting Reanimated errors and warnings to Observe. Reanimated's logger keeps its
|
|
153
|
+
* configuration.
|
|
154
|
+
*/
|
|
155
|
+
export function disableReanimatedIntegration(): void {
|
|
156
|
+
isEnabled = false;
|
|
157
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
// react-native-reanimated is an optional peerDependency of expo-observe. It is required lazily,
|
|
2
|
+
// only when the integration is enabled, so an app that doesn't enable it never loads Reanimated
|
|
3
|
+
// through expo-observe. This lives in its own file because a `require` wrapped in try/catch
|
|
4
|
+
// doesn't work with Metro's `inlineRequires` when it shares a file with other imports (see
|
|
5
|
+
// expo-gl's `GLWorkletContextManager`).
|
|
6
|
+
|
|
7
|
+
export type ReanimatedLogData = { level: number; message: string };
|
|
8
|
+
|
|
9
|
+
export type ReanimatedLoggerConfig = { level?: number; strict?: boolean };
|
|
10
|
+
|
|
11
|
+
export interface LoadedReanimated {
|
|
12
|
+
version: string;
|
|
13
|
+
configureReanimatedLogger(
|
|
14
|
+
config: ReanimatedLoggerConfig,
|
|
15
|
+
onLog?: (data: ReanimatedLogData) => void
|
|
16
|
+
): void;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function loadReanimated(): LoadedReanimated | null {
|
|
20
|
+
try {
|
|
21
|
+
const { reanimatedVersion, configureReanimatedLogger } = require('react-native-reanimated') as {
|
|
22
|
+
reanimatedVersion: string;
|
|
23
|
+
configureReanimatedLogger: LoadedReanimated['configureReanimatedLogger'];
|
|
24
|
+
};
|
|
25
|
+
return { version: reanimatedVersion, configureReanimatedLogger };
|
|
26
|
+
} catch {
|
|
27
|
+
return null;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
const STACK_FRAME_PATTERN = /^\s*at /;
|
|
2
|
+
|
|
3
|
+
function escapeRegExp(text: string): string {
|
|
4
|
+
return text.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Removes the first frame of the stack when it is a frame of `functionName`. The message can
|
|
9
|
+
* contain newlines, so the first frame is the first line that is a stack frame.
|
|
10
|
+
*/
|
|
11
|
+
export function removeFirstFrame(
|
|
12
|
+
stack: string | undefined,
|
|
13
|
+
functionName: string
|
|
14
|
+
): string | undefined {
|
|
15
|
+
if (stack === undefined) {
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
const lines = stack.split('\n');
|
|
19
|
+
const firstFrameIndex = lines.findIndex((line) => STACK_FRAME_PATTERN.test(line));
|
|
20
|
+
if (firstFrameIndex === -1) {
|
|
21
|
+
return stack;
|
|
22
|
+
}
|
|
23
|
+
const functionFramePattern = new RegExp(`^\\s*at ${escapeRegExp(functionName)} `);
|
|
24
|
+
if (!functionFramePattern.test(lines[firstFrameIndex] ?? '')) {
|
|
25
|
+
return stack;
|
|
26
|
+
}
|
|
27
|
+
return [...lines.slice(0, firstFrameIndex), ...lines.slice(firstFrameIndex + 1)].join('\n');
|
|
28
|
+
}
|
package/src/module.ts
CHANGED
|
@@ -3,6 +3,10 @@ import AppMetrics, { setErrorHandlerEnabled } from 'expo-app-metrics';
|
|
|
3
3
|
|
|
4
4
|
import { initRouterIntegration } from './integrations/expo-router/init';
|
|
5
5
|
import { isRouterInstalled } from './integrations/expo-router/router';
|
|
6
|
+
import {
|
|
7
|
+
disableReanimatedIntegration,
|
|
8
|
+
initReanimatedIntegration,
|
|
9
|
+
} from './integrations/react-native-reanimated/init';
|
|
6
10
|
import { initReactNavigationIntegration } from './integrations/react-navigation/init';
|
|
7
11
|
import { isReactNavigationInstalled } from './integrations/react-navigation/reactNavigation';
|
|
8
12
|
import { reportCaughtError } from './reportCaughtError';
|
|
@@ -80,6 +84,12 @@ const Observe: ObserveModule = new Proxy(native, {
|
|
|
80
84
|
} else if (shouldInitReactNavigationIntegration) {
|
|
81
85
|
initReactNavigationIntegration(config.integrations?.['react-navigation']);
|
|
82
86
|
}
|
|
87
|
+
const reanimatedConfig = config.integrations?.['react-native-reanimated'];
|
|
88
|
+
if (reanimatedConfig) {
|
|
89
|
+
initReanimatedIntegration(reanimatedConfig);
|
|
90
|
+
} else {
|
|
91
|
+
disableReanimatedIntegration();
|
|
92
|
+
}
|
|
83
93
|
return target.configure(config);
|
|
84
94
|
};
|
|
85
95
|
}
|
package/src/reportCaughtError.ts
CHANGED
|
@@ -36,16 +36,20 @@ function normalizeReportedError(error: unknown): NormalizedReportedError {
|
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
|
-
* Reports a caught value as a non-fatal
|
|
40
|
-
*
|
|
39
|
+
* Reports a caught value as a non-fatal error through the AppMetrics module, shared by the native
|
|
40
|
+
* and web `Observe.reportError` implementations and by integrations. `source` is `reportedByUser`
|
|
41
|
+
* for an error the app reports, and `integration` for an error an integration reports for a library.
|
|
41
42
|
*
|
|
42
43
|
* Never throws: it's called from a `catch` block, so a failure here (a pathological thrown value, or
|
|
43
44
|
* a native call that rejects the payload) must not turn a handled error into an unhandled one.
|
|
44
45
|
*/
|
|
45
|
-
export function reportCaughtError(
|
|
46
|
+
export function reportCaughtError(
|
|
47
|
+
error: unknown,
|
|
48
|
+
source: 'reportedByUser' | 'integration' = 'reportedByUser'
|
|
49
|
+
): void {
|
|
46
50
|
try {
|
|
47
51
|
AppMetrics.reportError({
|
|
48
|
-
source
|
|
52
|
+
source,
|
|
49
53
|
...normalizeReportedError(error),
|
|
50
54
|
isFatal: false,
|
|
51
55
|
});
|
package/src/types.ts
CHANGED
|
@@ -150,8 +150,49 @@ export interface ObserveIntegrationsConfig {
|
|
|
150
150
|
* @default false
|
|
151
151
|
*/
|
|
152
152
|
'react-navigation'?: boolean | ObserveNavigationIntegrationConfig;
|
|
153
|
+
/**
|
|
154
|
+
* Enables the `react-native-reanimated` integration, which reports Reanimated errors to Observe
|
|
155
|
+
* as errors named `reanimated.error`. To also report Reanimated warnings as events named
|
|
156
|
+
* `reanimated.warning`, set `reportWarnings`. Reanimated still prints errors and warnings to the
|
|
157
|
+
* console. The integration reports each distinct message at most once every 15 minutes. It
|
|
158
|
+
* reports at most 20 distinct errors and 20 distinct warnings in any 15-minute period.
|
|
159
|
+
*
|
|
160
|
+
* Requires `react-native-reanimated` 4.7.0 or later to be installed.
|
|
161
|
+
*
|
|
162
|
+
* The integration configures Reanimated's logger with `configureReanimatedLogger`. To set the
|
|
163
|
+
* logger's `level` and `strict` options, pass an object here. Don't call
|
|
164
|
+
* `configureReanimatedLogger` in your app. A later call removes the integration's callback, and
|
|
165
|
+
* the integration replaces the `level` and `strict` options of an earlier call.
|
|
166
|
+
*
|
|
167
|
+
* @default false
|
|
168
|
+
*/
|
|
169
|
+
'react-native-reanimated'?: boolean | ObserveReanimatedIntegrationConfig;
|
|
153
170
|
}
|
|
154
171
|
|
|
172
|
+
export type ObserveReanimatedIntegrationConfig = {
|
|
173
|
+
/**
|
|
174
|
+
* The minimum log level that Reanimated prints and reports. Pass a `ReanimatedLogLevel` value
|
|
175
|
+
* from `react-native-reanimated`: `ReanimatedLogLevel.warn` (`1`) or `ReanimatedLogLevel.error`
|
|
176
|
+
* (`2`).
|
|
177
|
+
*
|
|
178
|
+
* @default ReanimatedLogLevel.warn
|
|
179
|
+
*/
|
|
180
|
+
level?: 1 | 2;
|
|
181
|
+
/**
|
|
182
|
+
* Whether Reanimated also prints and reports its strict-mode warnings.
|
|
183
|
+
*
|
|
184
|
+
* @default true
|
|
185
|
+
*/
|
|
186
|
+
strict?: boolean;
|
|
187
|
+
/**
|
|
188
|
+
* Whether the integration also reports Reanimated warnings to Observe, as events named
|
|
189
|
+
* `reanimated.warning`. Reanimated prints warnings to the console either way.
|
|
190
|
+
*
|
|
191
|
+
* @default false
|
|
192
|
+
*/
|
|
193
|
+
reportWarnings?: boolean;
|
|
194
|
+
};
|
|
195
|
+
|
|
155
196
|
/**
|
|
156
197
|
* Events emitted by the native `ExpoObserve` module.
|
|
157
198
|
*/
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
57d1852cd6856c787f39ccf7dc67fe22
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
268e21bc0d85402b0ccc18c7d7d267271c08d60e
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
2fe94a3000018f70581d3ab1c396164525960de1ecf98c266d1e24689d915150
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
dc0f3f96ba7e53fe360f9d84663b73f314427d709b5923e49a8d95088bf66280660405b777ed342e2e14f969619abfc2b2aa4116e0ac0567b6931cba3b7a05c4
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
338d8842318510f8caf14b01aefdfe6a
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
95adad7bab839e049d62c8416cc5ee285c82629e
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
d0286094f7cdc9325087139447ec5ec6c4563901d7229252a4460fc64379a0f1
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
011e6ad1efa46ed83a7c1f27b8e240a49e2875d3c712d61dce2269207330b9cf94fc0d8a4a3295b31d450cca9a773bc22f94f3d5ece0f5ec57399e902ea878ae
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
5e68a5dcd710c86ef6bbb022c3094ab8
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
ef32ee0da70e1659d6a9d7cf485bc61ba5f9491e
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
e9476a7fc0643a6caf1a8aea50792a3be158a7d69cac46e525832da4e7d07d05
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
e36d1782fd020027e4811bb6a2496d48b5758df93463f0e052de99ddafe602cc29f2bc5e1ddbec20f3031d2bd6ee07e1cdc72eb78b39a58bb42fa2398ef00372
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
a2eb34425d5c0e5a7de3e272c3171670
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
d501becb18a0b0ba40057c29e5016bb4d3300f85
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
22e1c654c571938460b3fdf9b2a21f101a7c9b0ee1dc6765171080dbae436c52
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
796a8c93a6920a0899e054ce91d6fc83274f66e8bb30429f04dbf539134f9fdd61e5da440fa9dc0817a7899a5ca5b12b7d5b74d30ef7d356d183a13a623a3946
|