yaver-feedback-react-native 0.9.9 → 0.9.10
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/app.plugin.js +24 -10
- package/dist/DogfoodRuntime.d.ts +6 -1
- package/dist/DogfoodRuntime.js +9 -3
- package/dist/DogfoodSessionUi.d.ts +1 -0
- package/dist/DogfoodSessionUi.js +5 -2
- package/dist/FeedbackModal.js +249 -278
- package/dist/FeedbackModalTheme.d.ts +5 -0
- package/dist/FeedbackModalTheme.js +29 -0
- package/dist/P2PClient.d.ts +2 -0
- package/dist/P2PClient.js +1 -1
- package/dist/P2PDogfoodDriver.js +17 -0
- package/dist/__tests__/DogfoodRuntime.test.js +14 -0
- package/dist/__tests__/FeedbackModalContract.test.d.ts +1 -0
- package/dist/__tests__/FeedbackModalContract.test.js +70 -0
- package/dist/__tests__/NativeDogfoodShortcut.test.js +23 -0
- package/dist/__tests__/P2PDogfoodDriver.test.js +4 -1
- package/dist/index.d.ts +4 -5
- package/dist/index.js +4 -5
- package/ios/YaverHotReload.swift +3 -4
- package/package.json +1 -1
- package/src/DogfoodRuntime.ts +21 -4
- package/src/DogfoodSessionUi.tsx +6 -2
- package/src/FeedbackModal.tsx +319 -372
- package/src/FeedbackModalTheme.ts +29 -0
- package/src/P2PClient.ts +3 -1
- package/src/P2PDogfoodDriver.ts +17 -0
- package/src/__tests__/DogfoodRuntime.test.ts +15 -0
- package/src/__tests__/FeedbackModalContract.test.ts +80 -0
- package/src/__tests__/NativeDogfoodShortcut.test.ts +25 -0
- package/src/__tests__/P2PDogfoodDriver.test.ts +4 -0
- package/src/index.ts +4 -5
package/app.plugin.js
CHANGED
|
@@ -227,7 +227,9 @@ function withYaverAppDelegateHook(config) {
|
|
|
227
227
|
// Existing consumers may already have the hot-reload hook from an older
|
|
228
228
|
// SDK. Still apply newer, independently-versioned native contracts.
|
|
229
229
|
if (contents.includes("YaverHotReload")) {
|
|
230
|
-
config.modResults.contents = patchDogfoodAppShortcut(
|
|
230
|
+
config.modResults.contents = patchDogfoodAppShortcut(
|
|
231
|
+
patchHotReloadBootConfirmation(contents)
|
|
232
|
+
);
|
|
231
233
|
return config;
|
|
232
234
|
}
|
|
233
235
|
|
|
@@ -273,20 +275,14 @@ function withYaverAppDelegateHook(config) {
|
|
|
273
275
|
name: Notification.Name("YaverHotReloadBundle"),
|
|
274
276
|
object: nil
|
|
275
277
|
)
|
|
276
|
-
// Crash-revert safety net:
|
|
277
|
-
//
|
|
278
|
-
//
|
|
279
|
-
// YaverHotReload.bundleURL() will eventually revert to the
|
|
280
|
-
// TestFlight-installed bundle after 3 failed boots. See
|
|
281
|
-
// YaverHotReload.swift for the full state machine.
|
|
278
|
+
// Crash-revert safety net: only a real first React frame confirms boot.
|
|
279
|
+
// Uptime is not success: JS can fail while the native process remains
|
|
280
|
+
// alive on its launch screen indefinitely.
|
|
282
281
|
NotificationCenter.default.addObserver(
|
|
283
282
|
forName: NSNotification.Name(rawValue: "RCTContentDidAppearNotification"),
|
|
284
283
|
object: nil,
|
|
285
284
|
queue: .main
|
|
286
285
|
) { _ in YaverHotReload.markBootSuccessful() }
|
|
287
|
-
DispatchQueue.main.asyncAfter(deadline: .now() + 10) {
|
|
288
|
-
YaverHotReload.markBootSuccessful()
|
|
289
|
-
}
|
|
290
286
|
}
|
|
291
287
|
|
|
292
288
|
@objc private func yaverHandleHotReload(_ notification: Notification) {
|
|
@@ -374,6 +370,23 @@ function withYaverAppDelegateHook(config) {
|
|
|
374
370
|
});
|
|
375
371
|
}
|
|
376
372
|
|
|
373
|
+
/** Upgrade an already-generated AppDelegate from the pre-0.9.10 boot guard.
|
|
374
|
+
* Older plugins treated ten seconds of process uptime as a successful React
|
|
375
|
+
* boot. A JS exception can leave that process alive on the native splash, so
|
|
376
|
+
* the timer reset the crash counter forever and prevented bundle rollback. */
|
|
377
|
+
function patchHotReloadBootConfirmation(contents) {
|
|
378
|
+
let patched = contents;
|
|
379
|
+
patched = patched.replace(
|
|
380
|
+
/ \/\/ Crash-revert safety net: clear the boot-attempt counter once\n \/\/ RN renders its first frame, OR after 10 s of uptime — whichever\n \/\/ fires first\. If neither fires \(bundle crashes before render\),\n \/\/ YaverHotReload\.bundleURL\(\) will eventually revert to the\n \/\/ TestFlight-installed bundle after 3 failed boots\. See\n \/\/ YaverHotReload\.swift for the full state machine\./,
|
|
381
|
+
` // Crash-revert safety net: only a real first React frame confirms boot.\n // Uptime is not success: JS can fail while the native process remains\n // alive on its launch screen indefinitely.`
|
|
382
|
+
);
|
|
383
|
+
patched = patched.replace(
|
|
384
|
+
/ DispatchQueue\.main\.asyncAfter\(deadline: \.now\(\) \+ 10\) \{\n YaverHotReload\.markBootSuccessful\(\)\n \}\n?/g,
|
|
385
|
+
""
|
|
386
|
+
);
|
|
387
|
+
return patched;
|
|
388
|
+
}
|
|
389
|
+
|
|
377
390
|
/** Wire the dynamic iOS Home Screen shortcut into the SDK native module.
|
|
378
391
|
* The shortcut itself is created at runtime only after backend ACL success;
|
|
379
392
|
* this hook merely consumes a user-selected action on warm/cold launch. */
|
|
@@ -820,6 +833,7 @@ const yaverFeedbackPlugin = createRunOncePlugin(
|
|
|
820
833
|
// config-plugin seam catches template drift before a consumer discovers it in
|
|
821
834
|
// an archive build.
|
|
822
835
|
yaverFeedbackPlugin.__test = {
|
|
836
|
+
patchHotReloadBootConfirmation,
|
|
823
837
|
patchDogfoodAppShortcut,
|
|
824
838
|
patchDogfoodSceneDelegate,
|
|
825
839
|
findAppDelegateClassClose,
|
package/dist/DogfoodRuntime.d.ts
CHANGED
|
@@ -32,9 +32,14 @@ export interface DogfoodLaneOption {
|
|
|
32
32
|
/** One framework-to-lane matrix for Yaver and third-party consumers. */
|
|
33
33
|
export declare function dogfoodLaneOptions(framework: string, capabilities?: {
|
|
34
34
|
nativeRuntimeAvailable?: boolean;
|
|
35
|
+
browserRuntimeAvailable?: boolean;
|
|
35
36
|
selfDevelopment?: boolean;
|
|
36
37
|
}): DogfoodLaneOption[];
|
|
37
|
-
export declare function defaultDogfoodLane(framework: string
|
|
38
|
+
export declare function defaultDogfoodLane(framework: string, capabilities?: {
|
|
39
|
+
nativeRuntimeAvailable?: boolean;
|
|
40
|
+
browserRuntimeAvailable?: boolean;
|
|
41
|
+
selfDevelopment?: boolean;
|
|
42
|
+
}): DogfoodLane;
|
|
38
43
|
export interface DogfoodLogLine {
|
|
39
44
|
text: string;
|
|
40
45
|
at: number;
|
package/dist/DogfoodRuntime.js
CHANGED
|
@@ -21,7 +21,10 @@ exports.runtimeLogLinesFromDevEvent = runtimeLogLinesFromDevEvent;
|
|
|
21
21
|
function dogfoodLaneOptions(framework, capabilities = {}) {
|
|
22
22
|
const normalized = String(framework || '').trim().toLowerCase();
|
|
23
23
|
const reactNative = normalized === 'expo' || normalized === 'react-native';
|
|
24
|
-
|
|
24
|
+
// The framework matrix is the safe default. A positively detected browser
|
|
25
|
+
// target may add an exception (for example SwiftWasm/Tokamak), but a missing
|
|
26
|
+
// browser binary must not incorrectly remove RN/Flutter's browser build lane.
|
|
27
|
+
const browserCapable = capabilities.browserRuntimeAvailable === true || reactNative || [
|
|
25
28
|
'flutter', 'web', 'next', 'nextjs', 'vite', 'remix', 'svelte', 'vue', 'angular',
|
|
26
29
|
].includes(normalized);
|
|
27
30
|
const nativeAvailable = capabilities.nativeRuntimeAvailable === true;
|
|
@@ -40,8 +43,11 @@ function dogfoodLaneOptions(framework, capabilities = {}) {
|
|
|
40
43
|
},
|
|
41
44
|
];
|
|
42
45
|
}
|
|
43
|
-
function defaultDogfoodLane(framework) {
|
|
44
|
-
|
|
46
|
+
function defaultDogfoodLane(framework, capabilities = {}) {
|
|
47
|
+
const options = dogfoodLaneOptions(framework, capabilities);
|
|
48
|
+
return options.find((option) => option.default && option.supported)?.lane
|
|
49
|
+
|| options.find((option) => option.supported)?.lane
|
|
50
|
+
|| 'browser';
|
|
45
51
|
}
|
|
46
52
|
class DogfoodRuntimeError extends Error {
|
|
47
53
|
constructor(failure) {
|
|
@@ -40,6 +40,7 @@ export declare const DogfoodLanePicker: React.FC<{
|
|
|
40
40
|
* Logs; Hermes/WebRTC use the same lifecycle and failure/remedy treatment. */
|
|
41
41
|
export declare const DogfoodLiveConsole: React.FC<{
|
|
42
42
|
lane: DogfoodLane;
|
|
43
|
+
sourceLabel?: string;
|
|
43
44
|
phase: DogfoodPhase;
|
|
44
45
|
message: string;
|
|
45
46
|
logs: readonly DogfoodLogLine[];
|
package/dist/DogfoodSessionUi.js
CHANGED
|
@@ -91,15 +91,17 @@ function runtimeTone(phase, colors) {
|
|
|
91
91
|
}
|
|
92
92
|
/** Shared second-stage live console. Browser lane deliberately names Browser
|
|
93
93
|
* Logs; Hermes/WebRTC use the same lifecycle and failure/remedy treatment. */
|
|
94
|
-
const DogfoodLiveConsole = ({ lane, phase, message, logs, failure, maxLines = 80, colors: colorOverrides, renderText }) => {
|
|
94
|
+
const DogfoodLiveConsole = ({ lane, sourceLabel, phase, message, logs, failure, maxLines = 80, colors: colorOverrides, renderText }) => {
|
|
95
95
|
const colors = resolvedColors(colorOverrides);
|
|
96
96
|
const text = logs.slice(-maxLines).map((line) => line.text).join('\n');
|
|
97
97
|
const title = lane === 'browser' ? 'Browser Logs' : lane === 'hermes' ? 'Hermes Logs' : 'WebRTC Logs';
|
|
98
|
-
|
|
98
|
+
const accessibleTitle = sourceLabel ? `${title} · ${sourceLabel}` : title;
|
|
99
|
+
return (<react_native_1.View style={[styles.console, { backgroundColor: colors.console, borderColor: colors.border }]} accessibilityLabel={accessibleTitle}>
|
|
99
100
|
<react_native_1.View style={styles.consoleHeader}>
|
|
100
101
|
<react_native_1.View style={[styles.statusDot, { backgroundColor: runtimeTone(phase, colors) }]}/>
|
|
101
102
|
<react_native_1.Text style={[styles.consoleTitle, { color: colors.text }]}>{title}</react_native_1.Text>
|
|
102
103
|
</react_native_1.View>
|
|
104
|
+
{sourceLabel ? <react_native_1.Text style={[styles.consoleSource, { color: colors.muted }]}>Source · {sourceLabel}</react_native_1.Text> : null}
|
|
103
105
|
<react_native_1.Text style={[styles.consoleStatus, { color: colors.muted }]}>{message}</react_native_1.Text>
|
|
104
106
|
{text ? (renderText ? renderText(text) : <react_native_1.Text selectable style={[styles.consoleText, { color: colors.text }]}>{text}</react_native_1.Text>) : (<react_native_1.Text style={[styles.consoleEmpty, { color: colors.muted }]}>Waiting for the first line from the remote PC…</react_native_1.Text>)}
|
|
105
107
|
{failure ? (<react_native_1.View style={[styles.failure, { borderColor: colors.blocked }]}>
|
|
@@ -126,6 +128,7 @@ const styles = react_native_1.StyleSheet.create({
|
|
|
126
128
|
console: { width: '100%', maxHeight: 320, overflow: 'hidden', marginTop: 10, borderWidth: 1, borderRadius: 10, padding: 11, gap: 7 },
|
|
127
129
|
consoleHeader: { flexDirection: 'row', alignItems: 'center', gap: 7 },
|
|
128
130
|
consoleTitle: { fontSize: 12, fontWeight: '800' },
|
|
131
|
+
consoleSource: { fontSize: 10, lineHeight: 14 },
|
|
129
132
|
consoleStatus: { fontSize: 11, lineHeight: 16 },
|
|
130
133
|
consoleText: { fontFamily: 'monospace', fontSize: 10, lineHeight: 15 },
|
|
131
134
|
consoleEmpty: { fontSize: 10, fontStyle: 'italic' },
|