@buoy-gg/shared-ui 7.0.75 → 7.0.77

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.
Files changed (92) hide show
  1. package/lib/commonjs/bugCase/capture.js +1 -0
  2. package/lib/commonjs/bugCase/format.js +3 -0
  3. package/lib/commonjs/bugCase/index.js +1 -0
  4. package/lib/commonjs/bugCase/lock.js +1 -0
  5. package/lib/commonjs/bugCase/recorder.js +1 -0
  6. package/lib/commonjs/bugCase/scrub.js +1 -0
  7. package/lib/commonjs/bugCase/steps.js +1 -0
  8. package/lib/commonjs/bugCase/types.js +1 -0
  9. package/lib/commonjs/index.js +1 -1
  10. package/lib/commonjs/license/AccountSetupContent.js +1 -1
  11. package/lib/commonjs/license/licenseModule.js +1 -1
  12. package/lib/commonjs/storage/devToolsStorageKeys.js +1 -1
  13. package/lib/commonjs/utils/appIdentity.js +1 -0
  14. package/lib/commonjs/utils/index.js +1 -1
  15. package/lib/commonjs/utils/minimalSuperJSON.js +1 -1
  16. package/lib/commonjs/utils/nativeWeb.js +1 -1
  17. package/lib/commonjs/utils/reloadPlatform.js +1 -1
  18. package/lib/module/bugCase/capture.js +1 -0
  19. package/lib/module/bugCase/format.js +3 -0
  20. package/lib/module/bugCase/index.js +1 -0
  21. package/lib/module/bugCase/lock.js +1 -0
  22. package/lib/module/bugCase/recorder.js +1 -0
  23. package/lib/module/bugCase/scrub.js +1 -0
  24. package/lib/module/bugCase/steps.js +1 -0
  25. package/lib/module/bugCase/types.js +1 -0
  26. package/lib/module/index.js +1 -1
  27. package/lib/module/license/AccountSetupContent.js +1 -1
  28. package/lib/module/license/licenseModule.js +1 -1
  29. package/lib/module/storage/devToolsStorageKeys.js +1 -1
  30. package/lib/module/utils/appIdentity.js +1 -0
  31. package/lib/module/utils/index.js +1 -1
  32. package/lib/module/utils/minimalSuperJSON.js +1 -1
  33. package/lib/module/utils/nativeWeb.js +1 -1
  34. package/lib/module/utils/reloadPlatform.js +1 -1
  35. package/lib/typescript/commonjs/bugCase/capture.d.ts +20 -0
  36. package/lib/typescript/commonjs/bugCase/format.d.ts +15 -0
  37. package/lib/typescript/commonjs/bugCase/index.d.ts +14 -0
  38. package/lib/typescript/commonjs/bugCase/lock.d.ts +99 -0
  39. package/lib/typescript/commonjs/bugCase/recorder.d.ts +8 -0
  40. package/lib/typescript/commonjs/bugCase/scrub.d.ts +59 -0
  41. package/lib/typescript/commonjs/bugCase/steps.d.ts +44 -0
  42. package/lib/typescript/commonjs/bugCase/types.d.ts +92 -0
  43. package/lib/typescript/commonjs/hooks/safe-area-impl.d.ts +1 -1
  44. package/lib/typescript/commonjs/index.d.ts +3 -1
  45. package/lib/typescript/commonjs/license/AccountSetupContent.d.ts +1 -1
  46. package/lib/typescript/commonjs/license/licenseModule.d.ts +7 -0
  47. package/lib/typescript/commonjs/storage/devToolsStorageKeys.d.ts +14 -0
  48. package/lib/typescript/commonjs/utils/appIdentity.d.ts +3 -0
  49. package/lib/typescript/commonjs/utils/index.d.ts +1 -1
  50. package/lib/typescript/commonjs/utils/minimalSuperJSON.d.ts +6 -0
  51. package/lib/typescript/commonjs/utils/nativeWeb.d.ts +8 -1
  52. package/lib/typescript/module/bugCase/capture.d.ts +20 -0
  53. package/lib/typescript/module/bugCase/format.d.ts +15 -0
  54. package/lib/typescript/module/bugCase/index.d.ts +14 -0
  55. package/lib/typescript/module/bugCase/lock.d.ts +99 -0
  56. package/lib/typescript/module/bugCase/recorder.d.ts +8 -0
  57. package/lib/typescript/module/bugCase/scrub.d.ts +59 -0
  58. package/lib/typescript/module/bugCase/steps.d.ts +44 -0
  59. package/lib/typescript/module/bugCase/types.d.ts +92 -0
  60. package/lib/typescript/module/hooks/safe-area-impl.d.ts +1 -1
  61. package/lib/typescript/module/index.d.ts +3 -1
  62. package/lib/typescript/module/license/AccountSetupContent.d.ts +1 -1
  63. package/lib/typescript/module/license/licenseModule.d.ts +7 -0
  64. package/lib/typescript/module/storage/devToolsStorageKeys.d.ts +14 -0
  65. package/lib/typescript/module/utils/appIdentity.d.ts +3 -0
  66. package/lib/typescript/module/utils/index.d.ts +1 -1
  67. package/lib/typescript/module/utils/minimalSuperJSON.d.ts +6 -0
  68. package/lib/typescript/module/utils/nativeWeb.d.ts +8 -1
  69. package/lib/web/chunks/{chunk-7CBB7NEY.mjs → chunk-4QFANR3K.mjs} +1 -1
  70. package/lib/web/chunks/{chunk-UQRRKDKX.mjs → chunk-BMITMQVB.mjs} +3 -3
  71. package/lib/web/chunks/chunk-DJD42EPL.mjs +1 -0
  72. package/lib/web/chunks/chunk-EY7GXWGI.mjs +1 -0
  73. package/lib/web/chunks/{chunk-RMLVR5LI.mjs → chunk-FPMEM2QO.mjs} +1 -1
  74. package/lib/web/chunks/{chunk-G2SCTDOW.mjs → chunk-GN75GBYZ.mjs} +1 -1
  75. package/lib/web/chunks/{chunk-3HELV44Y.mjs → chunk-GTRVOJUH.mjs} +1 -1
  76. package/lib/web/chunks/{chunk-G27JNYZ3.mjs → chunk-OF3VWR6K.mjs} +1 -1
  77. package/lib/web/chunks/{chunk-CJTGUGMQ.mjs → chunk-OVTASJUJ.mjs} +1 -1
  78. package/lib/web/chunks/chunk-QXVVA64P.mjs +1 -0
  79. package/lib/web/chunks/{chunk-HIAN3HBD.mjs → chunk-XUYN4NOF.mjs} +1 -1
  80. package/lib/web/chunks/{persistentStorage.web-24PEE4I7.mjs → persistentStorage.web-7JL3GE3F.mjs} +1 -1
  81. package/lib/web/dataViewer.mjs +1 -1
  82. package/lib/web/history.mjs +1 -1
  83. package/lib/web/hooks.mjs +1 -1
  84. package/lib/web/index.mjs +7 -3
  85. package/lib/web/native.mjs +1 -1
  86. package/lib/web/ui.mjs +1 -1
  87. package/lib/web/utils.mjs +1 -1
  88. package/package.json +5 -5
  89. package/lib/web/chunks/chunk-2STKTXD3.mjs +0 -1
  90. package/lib/web/chunks/chunk-4HIK66DZ.mjs +0 -1
  91. package/lib/web/chunks/chunk-5G6RSRP4.mjs +0 -1
  92. package/lib/web/chunks/chunk-GMM6TGFO.mjs +0 -1
@@ -0,0 +1,92 @@
1
+ /**
2
+ * BugCase v1 — what one bug report holds. Every field was earned in the
3
+ * bug-links labs (research/bug-links-2026-10/LEDGER.md); the comment says by
4
+ * which bug it was needed.
5
+ */
6
+ import type { SuperJSONResult } from "../utils/minimalSuperJSON";
7
+ import type { ScrubbedItem } from "./scrub";
8
+ import type { BugCaseStep, BugCaseTouch } from "./steps";
9
+ export declare const BUG_CASE_VERSION = 1;
10
+ export interface BugCaseNetworkCall {
11
+ t: number;
12
+ method: string;
13
+ url: string;
14
+ status?: number;
15
+ /** Transport failure ("Network request failed", a timeout) instead of a status. */
16
+ error?: string;
17
+ durationMs?: number;
18
+ requestHeaders?: Record<string, string>;
19
+ requestData?: unknown;
20
+ responseHeaders?: Record<string, string>;
21
+ responseData?: unknown;
22
+ /** True when a body was over the case budget and left out. */
23
+ bodyOmitted?: boolean;
24
+ }
25
+ export interface BugCaseConsoleLine {
26
+ t: number;
27
+ level: string;
28
+ text: string;
29
+ }
30
+ export interface BugCaseScreenElement {
31
+ name: string;
32
+ role?: string;
33
+ testID?: string;
34
+ label?: string;
35
+ text?: string;
36
+ control?: string;
37
+ value?: number | boolean;
38
+ }
39
+ /** A part the capture tried to take and could not, so a reader knows it is missing. */
40
+ export interface BugCaseMissing {
41
+ part: string;
42
+ reason: string;
43
+ }
44
+ export interface BugCase {
45
+ v: typeof BUG_CASE_VERSION;
46
+ createdAt: string;
47
+ note?: string;
48
+ app: {
49
+ platform: string;
50
+ os: string;
51
+ appearance?: string;
52
+ locale?: string;
53
+ timeZone?: string;
54
+ window?: {
55
+ width: number;
56
+ height: number;
57
+ scale?: number;
58
+ fontScale?: number;
59
+ };
60
+ };
61
+ /** B4: the route and its params. */
62
+ route: {
63
+ pathname: string;
64
+ href: string;
65
+ } | null;
66
+ /** B3: the app clock, when Buoy's clock tool had it overridden. */
67
+ clock: {
68
+ active: boolean;
69
+ virtualIso?: string;
70
+ offsetMs?: number;
71
+ rate?: number;
72
+ } | null;
73
+ /** Buoy overrides that were on, so nobody chases a bug Buoy made. */
74
+ overrides: string[];
75
+ /** B1, B6: every Time Machine source, superjson-encoded and scrubbed. */
76
+ state: SuperJSONResult;
77
+ /** B6's cause, written without AI. */
78
+ steps: BugCaseStep[];
79
+ touches: BugCaseTouch[];
80
+ /** Lab 3's largest gain: what the screen said. */
81
+ screen: BugCaseScreenElement[];
82
+ /** B2: newest first, with answers for replay. */
83
+ network: BugCaseNetworkCall[];
84
+ console: BugCaseConsoleLine[];
85
+ missing: BugCaseMissing[];
86
+ scrub: {
87
+ removed: number;
88
+ byKind: Record<string, number>;
89
+ items: ScrubbedItem[];
90
+ };
91
+ }
92
+ //# sourceMappingURL=types.d.ts.map
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Auto-generated safe area implementation
3
3
  * Detected: none
4
- * Generated at: 2026-10-22T04:38:19.324Z
4
+ * Generated at: 2026-10-23T02:40:12.661Z
5
5
  *
6
6
  * DO NOT EDIT - This file is generated by scripts/detect-safe-area.js
7
7
  *
@@ -1,5 +1,6 @@
1
1
  export * from "./ui";
2
2
  export * from "./stores";
3
+ export * from "./bugCase";
3
4
  export * from "./sync/keyedArrays";
4
5
  export * from "./sync/valueShape";
5
6
  export * from "./sync/valuePath";
@@ -52,7 +53,8 @@ export { HintsProvider, useHintsDisabled, useHintsContext } from "./context";
52
53
  export * from "./history";
53
54
  export { FeatureGate, UpgradePrompt, useFeatureGate, ProFeatureBanner, UpgradeModal, BuoyUpgradeSheet, BuoySignInCard, BuoyNeedsPlanCard, useSignInState, ProBadge, ProUpgradeModal, FreeAccountPrompt, LOGIN_COMMAND, getUseIsPro, getUseLicense, getUseTier, signOutOfBuoy, TIER_LIMITS, useLimit, resolveEffectiveTier } from "./license";
54
55
  export type { FeatureGateProps, ProFeatureBannerProps, UpgradeModalProps, BuoyUpgradeSheetProps, ProUpgradeModalProps, FreeAccountPromptProps, BuoyTier, TierLimitKey } from "./license";
55
- export { getAccountAccess, hasAccountAccess, assertAccountAccess, subscribeAccountAccess, getUseAccountAccess, retryAccountAccess, isProNow } from "./license/licenseModule";
56
+ export { getAccountAccess, hasAccountAccess, assertAccountAccess, subscribeAccountAccess, getUseAccountAccess, retryAccountAccess, isProNow, getTeamCredential } from "./license/licenseModule";
57
+ export { setBuoyAppId, getBuoyAppId } from "./utils/appIdentity";
56
58
  export { guardToolAdapter } from "./sync/toolActionRegistry";
57
59
  export { AccountSetup } from "./license/AccountSetup";
58
60
  export { AccountSetupButton } from "./license/AccountSetupContent";
@@ -1,4 +1,4 @@
1
- export declare const LOGIN_COMMAND = "npx buoy login";
1
+ export declare const LOGIN_COMMAND = "npx --package=@buoy-gg/core buoy login";
2
2
  /** Shared account UI; each platform supplies positioning and dismissal. */
3
3
  export declare function AccountSetupButton({ onPress, expanded, }: {
4
4
  onPress: () => void;
@@ -81,5 +81,12 @@ export declare function getSyncCredential(): {
81
81
  token: string;
82
82
  origin: string;
83
83
  } | null;
84
+ /** The token, team and named app for shared Scenarios, or null (no team, a plain key, or an old license package). */
85
+ export declare function getTeamCredential(): {
86
+ token: string;
87
+ origin: string;
88
+ team: string;
89
+ appId: string | null;
90
+ } | null;
84
91
  export {};
85
92
  //# sourceMappingURL=licenseModule.d.ts.map
@@ -131,6 +131,18 @@ export declare const devToolsStorageKeys: {
131
131
  readonly root: () => "@react_buoy_clock";
132
132
  readonly state: () => "@react_buoy_clock_state";
133
133
  };
134
+ /**
135
+ * Bug links storage keys. `links` is this phone's own reports (their keys
136
+ * included, so a lost chat message is not a lost case), `settings` the
137
+ * server and team choices, `loaded` the case loaded right now plus the undo
138
+ * point that puts the app back.
139
+ */
140
+ readonly bugLinks: {
141
+ readonly root: () => "@react_buoy_bug_links";
142
+ readonly links: () => "@react_buoy_bug_links_links";
143
+ readonly settings: () => "@react_buoy_bug_links_settings";
144
+ readonly loaded: () => "@react_buoy_bug_links_loaded";
145
+ };
134
146
  /**
135
147
  * Permission override storage keys. `state` holds the overrides plus the
136
148
  * tool's settings as one JSON blob, so it can be read synchronously at boot.
@@ -183,6 +195,8 @@ export declare const devToolsStorageKeys: {
183
195
  readonly modal: () => "@react_buoy_scenarios_modal";
184
196
  readonly library: () => "@react_buoy_scenarios_library";
185
197
  readonly active: () => "@react_buoy_scenarios_active";
198
+ /** The team's shared scenarios for this app, saved so they show offline. */
199
+ readonly team: () => "@react_buoy_scenarios_team";
186
200
  };
187
201
  /**
188
202
  * React Query-related storage keys
@@ -0,0 +1,3 @@
1
+ export declare function setBuoyAppId(id: string | null | undefined): void;
2
+ export declare function getBuoyAppId(): string | null;
3
+ //# sourceMappingURL=appIdentity.d.ts.map
@@ -8,7 +8,7 @@ export { parseValue, formatValue, getTypeColor, truncateText, flattenObject, for
8
8
  export { loadOptionalModule, getCachedOptionalModule } from "./loadOptionalModule";
9
9
  export { setRenderCaptureProvider, getRenderCaptureProvider, type RenderCaptureProvider, type RenderCaptureSummary, type RenderCaptureTopComponent, type RenderCauseCounts, } from "./renderCaptureRegistry";
10
10
  export { registerStateSnapshotProvider, getStateSnapshotProviders, getStateSnapshotProvider, subscribeToStateSnapshotProviders, type StateSnapshotProvider, type StateSnapshotProviderStatus, type StateSnapshotCapture, type StateSnapshotRestoreResult, type StateSnapshotPreview, type StateSnapshotPreviewItem, type StateSnapshotPreviewVerdict, } from "./stateSnapshotRegistry";
11
- export { serialize as superJsonSerialize, deserialize as superJsonDeserialize, type SuperJSONResult, } from "./minimalSuperJSON";
11
+ export { serialize as superJsonSerialize, deserialize as superJsonDeserialize, dropAnnotations as superJsonDropAnnotations, type SuperJSONResult, } from "./minimalSuperJSON";
12
12
  export { reloadApp, scheduleReloadApp, resolveReloadStrategy, REMOTE_RELOAD_DELAY_MS, type ReloadStrategy, type ResolvedReloadStrategy, } from "./reloadApp";
13
13
  export { getDevServerOrigin } from "./devServer";
14
14
  export { realNow } from "./realNow";
@@ -14,5 +14,11 @@ export interface SuperJSONResult {
14
14
  }
15
15
  export declare function serialize(object: any): SuperJSONResult;
16
16
  export declare function deserialize<T = unknown>(payload: SuperJSONResult): T;
17
+ /**
18
+ * Drop the annotations whose value `drop` rejects. A bug case's scrubber can
19
+ * replace a Date with "[removed:pii]"; the Date annotation left behind would
20
+ * turn that into Invalid Date (or throw, for a BigInt) on deserialize.
21
+ */
22
+ export declare function dropAnnotations(payload: SuperJSONResult, drop: (value: unknown) => boolean): SuperJSONResult;
17
23
  export {};
18
24
  //# sourceMappingURL=minimalSuperJSON.d.ts.map
@@ -1,8 +1,15 @@
1
1
  export * from 'react-native-web';
2
- export { unstable_createElement, NativeModules, AccessibilityInfo, Animated, Appearance, AppRegistry, AppState, BackHandler, Clipboard, Dimensions, Easing, I18nManager, Keyboard, InteractionManager, LayoutAnimation, Linking, NativeEventEmitter, PanResponder, PixelRatio, Platform, Share, StyleSheet, UIManager, Vibration, CheckBox, FlatList, Image, ImageBackground, KeyboardAvoidingView, Picker, ProgressBar, RefreshControl, SafeAreaView, SectionList, StatusBar, Touchable, TouchableNativeFeedback, VirtualizedList, YellowBox, LogBox, DeviceEventEmitter, useColorScheme, useLocaleContext, useWindowDimensions } from 'react-native-web';
2
+ export { unstable_createElement, NativeModules, AccessibilityInfo, Appearance, AppRegistry, AppState, BackHandler, Clipboard, Dimensions, Easing, I18nManager, Keyboard, InteractionManager, LayoutAnimation, Linking, NativeEventEmitter, PanResponder, PixelRatio, Platform, Share, UIManager, Vibration, CheckBox, FlatList, Image, ImageBackground, KeyboardAvoidingView, Picker, ProgressBar, RefreshControl, SafeAreaView, SectionList, StatusBar, Touchable, TouchableNativeFeedback, VirtualizedList, YellowBox, LogBox, DeviceEventEmitter, useColorScheme, useLocaleContext, useWindowDimensions } from 'react-native-web';
3
3
  import * as nativeWeb from 'react-native-web';
4
+ declare const rnw: {
5
+ StyleSheet: typeof import("react-native").StyleSheet;
6
+ Animated: typeof import("react-native").Animated;
7
+ };
8
+ /** Styles are converted once here, where RNW would otherwise warn. */
9
+ export declare const StyleSheet: typeof rnw.StyleSheet;
4
10
  export declare const View: typeof nativeWeb.View;
5
11
  export declare const Text: typeof nativeWeb.Text;
12
+ export declare const Animated: typeof rnw.Animated;
6
13
  export declare const TextInput: typeof nativeWeb.TextInput;
7
14
  export declare const TouchableOpacity: typeof nativeWeb.TouchableOpacity;
8
15
  export declare const TouchableHighlight: typeof nativeWeb.TouchableHighlight;
@@ -0,0 +1,20 @@
1
+ import { type ScrubRules } from "./scrub";
2
+ import { type BugCase } from "./types";
3
+ export interface BugCaseBudget {
4
+ networkCalls: number;
5
+ /** Bodies past this, summed over the case, are left out and marked. */
6
+ bodyBytes: number;
7
+ /** One call's bodies past this are left out and marked. */
8
+ callBodyBytes: number;
9
+ consoleLines: number;
10
+ touches: number;
11
+ screenElements: number;
12
+ }
13
+ export declare const DEFAULT_BUG_CASE_BUDGET: BugCaseBudget;
14
+ export interface CaptureBugCaseOptions {
15
+ note?: string;
16
+ rules?: ScrubRules;
17
+ budget?: Partial<BugCaseBudget>;
18
+ }
19
+ export declare function captureBugCase(options?: CaptureBugCaseOptions): Promise<BugCase>;
20
+ //# sourceMappingURL=capture.d.ts.map
@@ -0,0 +1,15 @@
1
+ /**
2
+ * A bug case as plain text, for a person or an AI to read: the link page's
3
+ * "Copy for AI", MCP's `get_bug_case`, and the phone's share sheet.
4
+ *
5
+ * A case is data from someone's app. It can hold text that looks like
6
+ * instructions, so the text says plainly that nothing inside it is one, and
7
+ * every value is quoted or fenced rather than spliced in as prose.
8
+ */
9
+ import type { BugCase, BugCaseNetworkCall } from "./types";
10
+ export declare function isFailedCall(call: BugCaseNetworkCall): boolean;
11
+ export declare function formatBugCase(kase: BugCase, options?: {
12
+ link?: string;
13
+ maxCalls?: number;
14
+ }): string;
15
+ //# sourceMappingURL=format.d.ts.map
@@ -0,0 +1,14 @@
1
+ export { captureBugCase, DEFAULT_BUG_CASE_BUDGET } from "./capture";
2
+ export type { BugCaseBudget, CaptureBugCaseOptions } from "./capture";
3
+ export { base64UrlDecode, base64UrlEncode, BUG_CASE_LOCK_FORMAT, bugCaseHeader, BugCaseLockError, bugLinkUrl, lockBugCase, MAX_BUG_CASE_BYTES, parseBugLink, readBugCaseHeader, unlockBugCase, webCaseCrypto, } from "./lock";
4
+ export type { BugCaseCrypto, BugCaseHeader, BugCaseLockErrorCode, LockedBugCase } from "./lock";
5
+ export { bugCaseRecorderStatus, startBugCaseRecorder, stopBugCaseRecorder } from "./recorder";
6
+ export type { BugCaseRecorderStatus } from "./recorder";
7
+ export { formatBugCase, isFailedCall } from "./format";
8
+ export { classifyKey, keyWords, REMOVED_MARK, removedMark, ScrubLimitError, scrubBugCase } from "./scrub";
9
+ export type { ScrubbedItem, ScrubKind, ScrubResult, ScrubRules } from "./scrub";
10
+ export { bugCaseSteps, formatBugCaseSteps, safeTouch } from "./steps";
11
+ export type { BugCaseRouteVisit, BugCaseStep, BugCaseTouch } from "./steps";
12
+ export { BUG_CASE_VERSION } from "./types";
13
+ export type { BugCase, BugCaseConsoleLine, BugCaseMissing, BugCaseNetworkCall, BugCaseScreenElement, } from "./types";
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Lock and unlock a bug case.
3
+ *
4
+ * A case leaves the phone locked with AES-256-GCM under a key made for it
5
+ * alone. The key goes after `#` in the link, and browsers never send that part
6
+ * to a server, so buoy.gg stores bytes it cannot read.
7
+ *
8
+ * The blob carries everything:
9
+ *
10
+ * "BUOYBUG" | format (1 byte) | header length (u32, big-endian) | header JSON | nonce (12) | sealed
11
+ *
12
+ * `sealed` is gzip(case JSON) under the key, GCM tag at the end. Every byte
13
+ * before it is the additional data, so the server can read the plain header
14
+ * (for its list and for Slack previews) but cannot change it: a changed header
15
+ * fails the unlock the same way a changed case does.
16
+ *
17
+ * The header is built field by field from safe facts, never spread from the
18
+ * case, so nothing a person typed or the app held can end up readable.
19
+ *
20
+ * The crypto is passed in. `webCaseCrypto` uses WebCrypto and
21
+ * CompressionStream, which browsers and Node have. Hermes has neither, nor a
22
+ * secure random source, so the phone passes its own.
23
+ */
24
+ import { type BugCase } from "./types";
25
+ export declare const BUG_CASE_LOCK_FORMAT = 1;
26
+ /** Case JSON past this is refused on lock and on unlock (a zip bomb stops here). */
27
+ export declare const MAX_BUG_CASE_BYTES: number;
28
+ /** What buoy.gg can read. Only facts that hold no user data. */
29
+ export interface BugCaseHeader {
30
+ v: typeof BUG_CASE_LOCK_FORMAT;
31
+ case: number;
32
+ createdAt: string;
33
+ platform: string;
34
+ os: string;
35
+ /** Case JSON size before zipping. */
36
+ bytes: number;
37
+ steps: number;
38
+ calls: number;
39
+ errors: number;
40
+ removed: number;
41
+ missing: number;
42
+ }
43
+ export interface LockedBugCase {
44
+ blob: Uint8Array;
45
+ /** base64url, for the part of the link after `#`. */
46
+ key: string;
47
+ header: BugCaseHeader;
48
+ }
49
+ export interface BugCaseCrypto {
50
+ randomBytes(length: number): Uint8Array;
51
+ /** AES-256-GCM; returns ciphertext with the 16-byte tag appended. */
52
+ seal(key: Uint8Array, nonce: Uint8Array, data: Uint8Array, aad: Uint8Array): Promise<Uint8Array>;
53
+ /** Throws when the key is wrong or a byte changed. */
54
+ open(key: Uint8Array, nonce: Uint8Array, sealed: Uint8Array, aad: Uint8Array): Promise<Uint8Array>;
55
+ gzip(data: Uint8Array): Promise<Uint8Array>;
56
+ /** Throws BugCaseLockError("too_big") once the output passes maxBytes. */
57
+ gunzip(data: Uint8Array, maxBytes: number): Promise<Uint8Array>;
58
+ }
59
+ export type BugCaseLockErrorCode =
60
+ /** No secure random source or no cipher on this platform. */
61
+ "no_crypto"
62
+ /** The key in the link is not a key. */
63
+ | "bad_link"
64
+ /** Not a bug case blob, or a blob from a newer Buoy. */
65
+ | "bad_blob"
66
+ /** Wrong key, or the blob was changed. GCM can't say which. */
67
+ | "locked" | "too_big";
68
+ export declare class BugCaseLockError extends Error {
69
+ readonly code: BugCaseLockErrorCode;
70
+ constructor(code: BugCaseLockErrorCode, message: string);
71
+ }
72
+ export declare function bugCaseHeader(kase: BugCase, bytes: number): BugCaseHeader;
73
+ /**
74
+ * `options.key` locks under an existing link's key (with a fresh nonce), so a
75
+ * case can be replaced, say to add a note, and the link people already have
76
+ * keeps working.
77
+ */
78
+ export declare function lockBugCase(kase: BugCase, crypto?: BugCaseCrypto, options?: {
79
+ key?: string;
80
+ }): Promise<LockedBugCase>;
81
+ /** For the server: the plain header, read without the key. */
82
+ export declare function readBugCaseHeader(blob: Uint8Array): BugCaseHeader;
83
+ export declare function unlockBugCase(blob: Uint8Array, key: string, options?: {
84
+ crypto?: BugCaseCrypto;
85
+ maxBytes?: number;
86
+ }): Promise<{
87
+ header: BugCaseHeader;
88
+ kase: BugCase;
89
+ }>;
90
+ export declare function bugLinkUrl(origin: string, id: string, key: string): string;
91
+ export declare function parseBugLink(link: string): {
92
+ id: string;
93
+ key: string;
94
+ } | null;
95
+ /** WebCrypto and CompressionStream: browsers, Node 18+, Workers. Not Hermes. */
96
+ export declare function webCaseCrypto(): BugCaseCrypto;
97
+ export declare function base64UrlEncode(bytes: Uint8Array): string;
98
+ export declare function base64UrlDecode(text: string): Uint8Array | null;
99
+ //# sourceMappingURL=lock.d.ts.map
@@ -0,0 +1,8 @@
1
+ export interface BugCaseRecorderStatus {
2
+ watching: string[];
3
+ touches: boolean;
4
+ }
5
+ export declare function startBugCaseRecorder(): Promise<BugCaseRecorderStatus>;
6
+ export declare function stopBugCaseRecorder(): void;
7
+ export declare function bugCaseRecorderStatus(): BugCaseRecorderStatus;
8
+ //# sourceMappingURL=recorder.d.ts.map
@@ -0,0 +1,59 @@
1
+ /**
2
+ * scrubBugCase — take secrets and personal data out of a bug case on the
3
+ * device, before any of it leaves.
4
+ *
5
+ * This is the winner of the scrub lab (research/bug-links-2026-10, Lab 1,
6
+ * "S14"): 0 of 36 planted secrets leaked, and 1 of 55 values a repro needs
7
+ * was lost. What decided it, in the order it mattered:
8
+ *
9
+ * KEYS ARE JUDGED BY WHOLE WORDS. `author` is not `auth`, `pin_attempts`
10
+ * is not a PIN, and `nextToken` is a page cursor. Substring lists failed
11
+ * both ways (18 secrets leaked, 4 repro values broken).
12
+ *
13
+ * A SECRET SEEN ONCE IS A SECRET EVERYWHERE. A token found in an
14
+ * Authorization header or under `password` is "learned", and a second pass
15
+ * removes that exact value wherever else it sits: under `v`, `p` or
16
+ * `@app/cache:a1`. This was the largest single gain.
17
+ *
18
+ * `{key, value}` LISTS ARE JUDGED BY THEIR KEY. MMKV storage arrives as
19
+ * `[{key: "auth.token", value: "..."}]`; judged by the word "value" every
20
+ * secret in it leaked. Found on the sim, not in the first corpus.
21
+ *
22
+ * NO "LOOKS RANDOM" RULE. Entropy caught nothing the rules above missed and
23
+ * broke order ids, hashes and commit SHAs. It was dropped on the evidence.
24
+ *
25
+ * Removed values become `[removed:secret]` / `[removed:pii]` so the loader can
26
+ * graft the teammate's own value back into the same spot (see graft.ts).
27
+ *
28
+ * Pure and synchronous so it can be argued with in a unit test. Callers on a
29
+ * phone run it after the capture has been shown as done, off the tap.
30
+ */
31
+ export type ScrubKind = "secret" | "pii";
32
+ export interface ScrubRules {
33
+ /** Paths or key names to always remove, e.g. "transfer.memo" or "memo". */
34
+ redact?: readonly string[];
35
+ /** Key names to always keep, even if a rule would remove them. */
36
+ keep?: readonly string[];
37
+ }
38
+ export interface ScrubbedItem {
39
+ path: string;
40
+ kind: ScrubKind;
41
+ /** Which rule fired: "key", "value", "header", "param", "learned", "app". */
42
+ rule: string;
43
+ }
44
+ export interface ScrubResult<T> {
45
+ value: T;
46
+ removed: ScrubbedItem[];
47
+ }
48
+ export declare const removedMark: (kind: ScrubKind) => string;
49
+ export declare const REMOVED_MARK: RegExp;
50
+ /** Thrown when a capture is too deep or too big to scrub. Send nothing. */
51
+ export declare class ScrubLimitError extends Error {
52
+ }
53
+ /** camelCase / snake_case / kebab-case / dotted keys -> lowercase words. */
54
+ export declare function keyWords(key: string): string[];
55
+ export declare function classifyKey(key: string): ScrubKind | null;
56
+ /** Own-property write, so a "__proto__" key in captured data can't reach a prototype. */
57
+ export declare function setOwn(o: Record<string, unknown>, k: string, v: unknown): void;
58
+ export declare function scrubBugCase<T>(input: T, rules?: ScrubRules): ScrubResult<T>;
59
+ //# sourceMappingURL=scrub.d.ts.map
@@ -0,0 +1,44 @@
1
+ /**
2
+ * bugCaseSteps — the steps to repeat a bug, written from the taps Buoy saw.
3
+ *
4
+ * No AI. In the bug-links lab (Lab 3) a model handed only the reporter's note
5
+ * wrote zero correct steps; handed these lines it wrote all six, and the
6
+ * folded repeat ("Tapped Apply SAVE10 2 times (368 ms apart)") was the cause
7
+ * of the double-coupon bug, written for free.
8
+ *
9
+ * Typed text never appears. A step says how many characters went into which
10
+ * field, because a field the capture can't see into may be a password.
11
+ */
12
+ /** One interaction, in the shape highlight-updates' touch capture records. */
13
+ export interface BugCaseTouch {
14
+ /** Capture order. Wins over `t`, which moves when the app clock is faked. */
15
+ seq?: number;
16
+ t: number;
17
+ kind: "press" | "longPress" | "text" | "toggle" | "slider";
18
+ target: {
19
+ name: string;
20
+ testID?: string;
21
+ label?: string;
22
+ text?: string;
23
+ control?: string;
24
+ value?: unknown;
25
+ };
26
+ value?: unknown;
27
+ }
28
+ export interface BugCaseRouteVisit {
29
+ t: number;
30
+ pathname: string;
31
+ }
32
+ export interface BugCaseStep {
33
+ t: number;
34
+ text: string;
35
+ }
36
+ /**
37
+ * Drop what a case must never carry: the text a field held or received.
38
+ * Toggle and slider values stay; they are what the step is about.
39
+ */
40
+ export declare function safeTouch(touch: BugCaseTouch): BugCaseTouch;
41
+ export declare function bugCaseSteps(touches: readonly BugCaseTouch[], routes?: readonly BugCaseRouteVisit[]): BugCaseStep[];
42
+ /** Numbered lines, the form a person or a model reads. */
43
+ export declare function formatBugCaseSteps(steps: readonly BugCaseStep[]): string;
44
+ //# sourceMappingURL=steps.d.ts.map
@@ -0,0 +1,92 @@
1
+ /**
2
+ * BugCase v1 — what one bug report holds. Every field was earned in the
3
+ * bug-links labs (research/bug-links-2026-10/LEDGER.md); the comment says by
4
+ * which bug it was needed.
5
+ */
6
+ import type { SuperJSONResult } from "../utils/minimalSuperJSON";
7
+ import type { ScrubbedItem } from "./scrub";
8
+ import type { BugCaseStep, BugCaseTouch } from "./steps";
9
+ export declare const BUG_CASE_VERSION = 1;
10
+ export interface BugCaseNetworkCall {
11
+ t: number;
12
+ method: string;
13
+ url: string;
14
+ status?: number;
15
+ /** Transport failure ("Network request failed", a timeout) instead of a status. */
16
+ error?: string;
17
+ durationMs?: number;
18
+ requestHeaders?: Record<string, string>;
19
+ requestData?: unknown;
20
+ responseHeaders?: Record<string, string>;
21
+ responseData?: unknown;
22
+ /** True when a body was over the case budget and left out. */
23
+ bodyOmitted?: boolean;
24
+ }
25
+ export interface BugCaseConsoleLine {
26
+ t: number;
27
+ level: string;
28
+ text: string;
29
+ }
30
+ export interface BugCaseScreenElement {
31
+ name: string;
32
+ role?: string;
33
+ testID?: string;
34
+ label?: string;
35
+ text?: string;
36
+ control?: string;
37
+ value?: number | boolean;
38
+ }
39
+ /** A part the capture tried to take and could not, so a reader knows it is missing. */
40
+ export interface BugCaseMissing {
41
+ part: string;
42
+ reason: string;
43
+ }
44
+ export interface BugCase {
45
+ v: typeof BUG_CASE_VERSION;
46
+ createdAt: string;
47
+ note?: string;
48
+ app: {
49
+ platform: string;
50
+ os: string;
51
+ appearance?: string;
52
+ locale?: string;
53
+ timeZone?: string;
54
+ window?: {
55
+ width: number;
56
+ height: number;
57
+ scale?: number;
58
+ fontScale?: number;
59
+ };
60
+ };
61
+ /** B4: the route and its params. */
62
+ route: {
63
+ pathname: string;
64
+ href: string;
65
+ } | null;
66
+ /** B3: the app clock, when Buoy's clock tool had it overridden. */
67
+ clock: {
68
+ active: boolean;
69
+ virtualIso?: string;
70
+ offsetMs?: number;
71
+ rate?: number;
72
+ } | null;
73
+ /** Buoy overrides that were on, so nobody chases a bug Buoy made. */
74
+ overrides: string[];
75
+ /** B1, B6: every Time Machine source, superjson-encoded and scrubbed. */
76
+ state: SuperJSONResult;
77
+ /** B6's cause, written without AI. */
78
+ steps: BugCaseStep[];
79
+ touches: BugCaseTouch[];
80
+ /** Lab 3's largest gain: what the screen said. */
81
+ screen: BugCaseScreenElement[];
82
+ /** B2: newest first, with answers for replay. */
83
+ network: BugCaseNetworkCall[];
84
+ console: BugCaseConsoleLine[];
85
+ missing: BugCaseMissing[];
86
+ scrub: {
87
+ removed: number;
88
+ byKind: Record<string, number>;
89
+ items: ScrubbedItem[];
90
+ };
91
+ }
92
+ //# sourceMappingURL=types.d.ts.map
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Auto-generated safe area implementation
3
3
  * Detected: none
4
- * Generated at: 2026-10-22T04:38:19.324Z
4
+ * Generated at: 2026-10-23T02:40:12.661Z
5
5
  *
6
6
  * DO NOT EDIT - This file is generated by scripts/detect-safe-area.js
7
7
  *
@@ -1,5 +1,6 @@
1
1
  export * from "./ui";
2
2
  export * from "./stores";
3
+ export * from "./bugCase";
3
4
  export * from "./sync/keyedArrays";
4
5
  export * from "./sync/valueShape";
5
6
  export * from "./sync/valuePath";
@@ -52,7 +53,8 @@ export { HintsProvider, useHintsDisabled, useHintsContext } from "./context";
52
53
  export * from "./history";
53
54
  export { FeatureGate, UpgradePrompt, useFeatureGate, ProFeatureBanner, UpgradeModal, BuoyUpgradeSheet, BuoySignInCard, BuoyNeedsPlanCard, useSignInState, ProBadge, ProUpgradeModal, FreeAccountPrompt, LOGIN_COMMAND, getUseIsPro, getUseLicense, getUseTier, signOutOfBuoy, TIER_LIMITS, useLimit, resolveEffectiveTier } from "./license";
54
55
  export type { FeatureGateProps, ProFeatureBannerProps, UpgradeModalProps, BuoyUpgradeSheetProps, ProUpgradeModalProps, FreeAccountPromptProps, BuoyTier, TierLimitKey } from "./license";
55
- export { getAccountAccess, hasAccountAccess, assertAccountAccess, subscribeAccountAccess, getUseAccountAccess, retryAccountAccess, isProNow } from "./license/licenseModule";
56
+ export { getAccountAccess, hasAccountAccess, assertAccountAccess, subscribeAccountAccess, getUseAccountAccess, retryAccountAccess, isProNow, getTeamCredential } from "./license/licenseModule";
57
+ export { setBuoyAppId, getBuoyAppId } from "./utils/appIdentity";
56
58
  export { guardToolAdapter } from "./sync/toolActionRegistry";
57
59
  export { AccountSetup } from "./license/AccountSetup";
58
60
  export { AccountSetupButton } from "./license/AccountSetupContent";
@@ -1,4 +1,4 @@
1
- export declare const LOGIN_COMMAND = "npx buoy login";
1
+ export declare const LOGIN_COMMAND = "npx --package=@buoy-gg/core buoy login";
2
2
  /** Shared account UI; each platform supplies positioning and dismissal. */
3
3
  export declare function AccountSetupButton({ onPress, expanded, }: {
4
4
  onPress: () => void;
@@ -81,5 +81,12 @@ export declare function getSyncCredential(): {
81
81
  token: string;
82
82
  origin: string;
83
83
  } | null;
84
+ /** The token, team and named app for shared Scenarios, or null (no team, a plain key, or an old license package). */
85
+ export declare function getTeamCredential(): {
86
+ token: string;
87
+ origin: string;
88
+ team: string;
89
+ appId: string | null;
90
+ } | null;
84
91
  export {};
85
92
  //# sourceMappingURL=licenseModule.d.ts.map
@@ -131,6 +131,18 @@ export declare const devToolsStorageKeys: {
131
131
  readonly root: () => "@react_buoy_clock";
132
132
  readonly state: () => "@react_buoy_clock_state";
133
133
  };
134
+ /**
135
+ * Bug links storage keys. `links` is this phone's own reports (their keys
136
+ * included, so a lost chat message is not a lost case), `settings` the
137
+ * server and team choices, `loaded` the case loaded right now plus the undo
138
+ * point that puts the app back.
139
+ */
140
+ readonly bugLinks: {
141
+ readonly root: () => "@react_buoy_bug_links";
142
+ readonly links: () => "@react_buoy_bug_links_links";
143
+ readonly settings: () => "@react_buoy_bug_links_settings";
144
+ readonly loaded: () => "@react_buoy_bug_links_loaded";
145
+ };
134
146
  /**
135
147
  * Permission override storage keys. `state` holds the overrides plus the
136
148
  * tool's settings as one JSON blob, so it can be read synchronously at boot.
@@ -183,6 +195,8 @@ export declare const devToolsStorageKeys: {
183
195
  readonly modal: () => "@react_buoy_scenarios_modal";
184
196
  readonly library: () => "@react_buoy_scenarios_library";
185
197
  readonly active: () => "@react_buoy_scenarios_active";
198
+ /** The team's shared scenarios for this app, saved so they show offline. */
199
+ readonly team: () => "@react_buoy_scenarios_team";
186
200
  };
187
201
  /**
188
202
  * React Query-related storage keys