@buoy-gg/time-machine 7.0.28 → 7.0.30

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 (68) hide show
  1. package/lib/commonjs/components/TimeMachineBody.js +13 -1
  2. package/lib/commonjs/components/TimeMachineBody.js.map +1 -1
  3. package/lib/commonjs/components/list/RestoreOutcomeCard.js +15 -4
  4. package/lib/commonjs/components/list/RestoreOutcomeCard.js.map +1 -1
  5. package/lib/commonjs/components/list/SnapshotRow.js +5 -0
  6. package/lib/commonjs/components/list/SnapshotRow.js.map +1 -1
  7. package/lib/commonjs/components/list/SourcesStrip.js +2 -0
  8. package/lib/commonjs/components/list/SourcesStrip.js.map +1 -1
  9. package/lib/commonjs/components/list/UndoDeleteBar.js +2 -0
  10. package/lib/commonjs/components/list/UndoDeleteBar.js.map +1 -1
  11. package/lib/commonjs/components/preview/ItemDiffPanel.js +3 -1
  12. package/lib/commonjs/components/preview/ItemDiffPanel.js.map +1 -1
  13. package/lib/commonjs/components/preview/RestorePreviewScreen.js +41 -7
  14. package/lib/commonjs/components/preview/RestorePreviewScreen.js.map +1 -1
  15. package/lib/commonjs/ui/primitives.js +9 -3
  16. package/lib/commonjs/ui/primitives.js.map +1 -1
  17. package/lib/module/components/TimeMachineBody.js +13 -1
  18. package/lib/module/components/TimeMachineBody.js.map +1 -1
  19. package/lib/module/components/list/RestoreOutcomeCard.js +15 -4
  20. package/lib/module/components/list/RestoreOutcomeCard.js.map +1 -1
  21. package/lib/module/components/list/SnapshotRow.js +5 -0
  22. package/lib/module/components/list/SnapshotRow.js.map +1 -1
  23. package/lib/module/components/list/SourcesStrip.js +2 -0
  24. package/lib/module/components/list/SourcesStrip.js.map +1 -1
  25. package/lib/module/components/list/UndoDeleteBar.js +2 -0
  26. package/lib/module/components/list/UndoDeleteBar.js.map +1 -1
  27. package/lib/module/components/preview/ItemDiffPanel.js +3 -1
  28. package/lib/module/components/preview/ItemDiffPanel.js.map +1 -1
  29. package/lib/module/components/preview/RestorePreviewScreen.js +41 -7
  30. package/lib/module/components/preview/RestorePreviewScreen.js.map +1 -1
  31. package/lib/module/ui/primitives.js +9 -3
  32. package/lib/module/ui/primitives.js.map +1 -1
  33. package/lib/typescript/components/list/RestoreOutcomeCard.d.ts.map +1 -1
  34. package/lib/typescript/components/list/SnapshotRow.d.ts.map +1 -1
  35. package/lib/typescript/components/list/SourcesStrip.d.ts.map +1 -1
  36. package/lib/typescript/components/preview/ItemDiffPanel.d.ts +2 -1
  37. package/lib/typescript/components/preview/ItemDiffPanel.d.ts.map +1 -1
  38. package/lib/typescript/components/preview/RestorePreviewScreen.d.ts.map +1 -1
  39. package/lib/typescript/ui/primitives.d.ts +6 -3
  40. package/lib/typescript/ui/primitives.d.ts.map +1 -1
  41. package/package.json +10 -11
  42. package/src/components/HeaderReloadButton.tsx +0 -45
  43. package/src/components/TimeMachineBody.tsx +0 -237
  44. package/src/components/TimeMachineModal.tsx +0 -75
  45. package/src/components/confirm.ts +0 -35
  46. package/src/components/format.ts +0 -17
  47. package/src/components/list/CaptureBar.tsx +0 -100
  48. package/src/components/list/RestoreOutcomeCard.tsx +0 -159
  49. package/src/components/list/SnapshotRow.tsx +0 -155
  50. package/src/components/list/SourcesStrip.tsx +0 -124
  51. package/src/components/list/UndoDeleteBar.tsx +0 -76
  52. package/src/components/list/WipeAllRow.tsx +0 -42
  53. package/src/components/preview/ItemDiffPanel.tsx +0 -77
  54. package/src/components/preview/PreviewFlow.tsx +0 -70
  55. package/src/components/preview/RestorePointNameRow.tsx +0 -80
  56. package/src/components/preview/RestorePreviewScreen.tsx +0 -1090
  57. package/src/components/preview/verdictMeta.ts +0 -40
  58. package/src/components/sources.ts +0 -92
  59. package/src/hooks/useTimeMachine.ts +0 -26
  60. package/src/index.tsx +0 -68
  61. package/src/preset.tsx +0 -47
  62. package/src/store/routeRestore.ts +0 -194
  63. package/src/store/snapshotVault.ts +0 -274
  64. package/src/store/timeMachineStore.ts +0 -881
  65. package/src/sync/timeMachineSyncAdapter.ts +0 -241
  66. package/src/ui/SwipeActionsRow.tsx +0 -199
  67. package/src/ui/primitives.tsx +0 -157
  68. package/src/ui/tmTheme.ts +0 -109
@@ -1,274 +0,0 @@
1
- /**
2
- * Snapshot persistence for Time Machine.
3
- *
4
- * Snapshots live ON-DEVICE in persistentStorage (FileSystem → AsyncStorage →
5
- * localStorage → Memory fallback): no size caps, survives restarts, and never
6
- * crosses the 2MB external-sync snapshot budget — only metadata does.
7
- *
8
- * Layout: ONE storage key per snapshot (persistentStorage's FileSystem
9
- * backend writes one file per key, and its multiGet is sequential — a single
10
- * big key beats many small ones), plus one index key holding the metadata
11
- * list for cheap listing.
12
- *
13
- * Keys use the `@react_buoy` family so every tool's isDevToolsStorageKey
14
- * filter (including our own storage provider) excludes the vault itself from
15
- * snapshots — a snapshot must never contain snapshots.
16
- */
17
- import {
18
- persistentStorage,
19
- type SuperJSONResult,
20
- } from "@buoy-gg/shared-ui";
21
- import type { SnapshotRoute } from "./routeRestore";
22
-
23
- const INDEX_KEY = "@react_buoy_time_machine:index";
24
- const SNAP_PREFIX = "@react_buoy_time_machine:snap:";
25
-
26
- export interface SnapshotSourceMeta {
27
- warnings: string[];
28
- }
29
-
30
- export interface SnapshotMeta {
31
- id: string;
32
- name: string;
33
- createdAt: number;
34
- /** Serialized size of the whole stored snapshot. */
35
- sizeBytes: number;
36
- /**
37
- * A baseline snapshot has NO captured data — restoring it wipes to
38
- * fresh-install state (clear + reload).
39
- */
40
- baseline?: boolean;
41
- /**
42
- * User-saved restore scope: compound "sourceId::itemKey" strings. When set,
43
- * restoring this snapshot touches ONLY these items — "this restore point
44
- * means just my cart". Absent = full restore.
45
- *
46
- * Set through the MCP/adapter `setScope` action. The tool's own UI writes
47
- * `excludedKeys` instead — see there for why the two exist.
48
- */
49
- scope?: string[];
50
- /**
51
- * Items the user switched OFF in the restore preview and saved: compound
52
- * "sourceId::itemKey" strings that every later restore of this snapshot
53
- * leaves untouched, including the one-tap RESTORE on the list.
54
- *
55
- * The inverse of `scope`, and the right default for "I unchecked one of
56
- * these ten keys": naming what to SKIP lets everything else through, so a
57
- * key that only starts differing tomorrow is still restored. An include
58
- * list built from today's diff would silently freeze the restore point to
59
- * whatever happened to differ when it was saved.
60
- */
61
- excludedKeys?: string[];
62
- /**
63
- * The route the app was on when this snapshot was captured. Absent when the
64
- * app has no expo-router (nothing to return to). A restore can navigate back
65
- * to it — see routeRestore.ts.
66
- */
67
- route?: SnapshotRoute;
68
- /**
69
- * Whether restoring this point should also navigate back to `route`.
70
- * Undefined means "yes, if there is a route" — the useful default, and the
71
- * reason there is no longer a prompt on every restore.
72
- */
73
- restoreRoute?: boolean;
74
- /** When this point was last restored, for the "restored 4m ago" marker. */
75
- lastRestoredAt?: number;
76
- /** Source ids captured, with their capture warnings. */
77
- sources: Record<string, SnapshotSourceMeta>;
78
- }
79
-
80
- export interface StoredSnapshot {
81
- meta: SnapshotMeta;
82
- /** Per-source superjson payloads (absent for baseline snapshots). */
83
- data: Record<string, SuperJSONResult>;
84
- }
85
-
86
- export async function loadIndex(): Promise<SnapshotMeta[]> {
87
- try {
88
- const raw = await persistentStorage.getItem(INDEX_KEY);
89
- if (!raw) return [];
90
- const parsed = JSON.parse(raw) as SnapshotMeta[];
91
- return Array.isArray(parsed) ? parsed : [];
92
- } catch {
93
- return [];
94
- }
95
- }
96
-
97
- async function saveIndex(metas: SnapshotMeta[]): Promise<void> {
98
- await persistentStorage.setItem(INDEX_KEY, JSON.stringify(metas));
99
- }
100
-
101
- /** Persists the snapshot, stamps meta.sizeBytes, and updates the index. */
102
- export async function saveSnapshot(
103
- snapshot: StoredSnapshot,
104
- metas: SnapshotMeta[]
105
- ): Promise<SnapshotMeta[]> {
106
- const serialized = JSON.stringify(snapshot);
107
- snapshot.meta.sizeBytes = serialized.length;
108
- await persistentStorage.setItem(
109
- SNAP_PREFIX + snapshot.meta.id,
110
- // Re-stringify so the persisted copy carries the final sizeBytes.
111
- JSON.stringify(snapshot)
112
- );
113
- const next = [
114
- snapshot.meta,
115
- ...metas.filter((m) => m.id !== snapshot.meta.id),
116
- ];
117
- await saveIndex(next);
118
- return next;
119
- }
120
-
121
- export async function loadSnapshot(id: string): Promise<StoredSnapshot | null> {
122
- try {
123
- const raw = await persistentStorage.getItem(SNAP_PREFIX + id);
124
- return raw ? (JSON.parse(raw) as StoredSnapshot) : null;
125
- } catch {
126
- return null;
127
- }
128
- }
129
-
130
- export async function deleteSnapshot(
131
- id: string,
132
- metas: SnapshotMeta[]
133
- ): Promise<SnapshotMeta[]> {
134
- await persistentStorage.removeItem(SNAP_PREFIX + id);
135
- const next = metas.filter((m) => m.id !== id);
136
- await saveIndex(next);
137
- return next;
138
- }
139
-
140
- /**
141
- * Rewrite one snapshot's metadata in BOTH places it lives — the index and the
142
- * snapshot's own record — so a reload can't resurrect the old value from
143
- * whichever one was missed.
144
- */
145
- async function patchMeta(
146
- id: string,
147
- patch: (meta: SnapshotMeta) => SnapshotMeta,
148
- metas: SnapshotMeta[]
149
- ): Promise<SnapshotMeta[]> {
150
- const apply = (m: SnapshotMeta): SnapshotMeta => (m.id === id ? patch(m) : m);
151
- const next = metas.map(apply);
152
- await persistentStorage.setItem(INDEX_KEY, JSON.stringify(next));
153
- const stored = await loadSnapshot(id);
154
- if (stored) {
155
- stored.meta = apply(stored.meta);
156
- await persistentStorage.setItem(SNAP_PREFIX + id, JSON.stringify(stored));
157
- }
158
- return next;
159
- }
160
-
161
- /** Set (or clear with null/empty) the "only these items" restore scope. */
162
- export function setSnapshotScope(
163
- id: string,
164
- scope: string[] | null,
165
- metas: SnapshotMeta[]
166
- ): Promise<SnapshotMeta[]> {
167
- return patchMeta(
168
- id,
169
- (m) => {
170
- const next = { ...m };
171
- if (scope && scope.length > 0) next.scope = scope;
172
- else delete next.scope;
173
- return next;
174
- },
175
- metas
176
- );
177
- }
178
-
179
- /**
180
- * Set (or clear with null/empty) the items a restore of this snapshot must
181
- * leave alone. Saving exclusions also clears any legacy `scope`: the two
182
- * answer the same question in opposite directions, and the one the user just
183
- * chose in the preview wins.
184
- */
185
- export function setSnapshotExclusions(
186
- id: string,
187
- excludedKeys: string[] | null,
188
- metas: SnapshotMeta[]
189
- ): Promise<SnapshotMeta[]> {
190
- return patchMeta(
191
- id,
192
- (m) => {
193
- const next = { ...m };
194
- delete next.scope;
195
- if (excludedKeys && excludedKeys.length > 0)
196
- next.excludedKeys = excludedKeys;
197
- else delete next.excludedKeys;
198
- return next;
199
- },
200
- metas
201
- );
202
- }
203
-
204
- /** Turn this point's route restore on or off — the row's route toggle. */
205
- export function setSnapshotRestoreRoute(
206
- id: string,
207
- restoreRoute: boolean,
208
- metas: SnapshotMeta[]
209
- ): Promise<SnapshotMeta[]> {
210
- return patchMeta(id, (m) => ({ ...m, restoreRoute }), metas);
211
- }
212
-
213
- /** Stamp a restore so the list can say which point you are currently in. */
214
- export function markSnapshotRestored(
215
- id: string,
216
- at: number,
217
- metas: SnapshotMeta[]
218
- ): Promise<SnapshotMeta[]> {
219
- return patchMeta(id, (m) => ({ ...m, lastRestoredAt: at }), metas);
220
- }
221
-
222
- /**
223
- * Copy a stored snapshot under a new id and name. The payload is copied by
224
- * reference into a fresh record — the vault serializes it on write, so the
225
- * two never share mutable state.
226
- */
227
- export async function duplicateSnapshot(
228
- id: string,
229
- name: string,
230
- metas: SnapshotMeta[]
231
- ): Promise<{ metas: SnapshotMeta[]; meta: SnapshotMeta } | null> {
232
- const stored = await loadSnapshot(id);
233
- if (!stored) return null;
234
- const copy: StoredSnapshot = {
235
- meta: {
236
- ...stored.meta,
237
- id: `${stored.meta.id}_copy_${Date.now().toString(36)}`,
238
- name,
239
- createdAt: Date.now(),
240
- lastRestoredAt: undefined,
241
- },
242
- data: stored.data,
243
- };
244
- delete copy.meta.lastRestoredAt;
245
- return { metas: await saveSnapshot(copy, metas), meta: copy.meta };
246
- }
247
-
248
- /** Read a whole record so a delete can be held in memory and undone. */
249
- export async function readSnapshot(id: string): Promise<StoredSnapshot | null> {
250
- return loadSnapshot(id);
251
- }
252
-
253
- /** Put a held record back exactly as it was. */
254
- export async function restoreDeletedSnapshot(
255
- stored: StoredSnapshot,
256
- metas: SnapshotMeta[]
257
- ): Promise<SnapshotMeta[]> {
258
- return saveSnapshot(stored, metas);
259
- }
260
-
261
- export async function renameSnapshot(
262
- id: string,
263
- name: string,
264
- metas: SnapshotMeta[]
265
- ): Promise<SnapshotMeta[]> {
266
- const next = metas.map((m) => (m.id === id ? { ...m, name } : m));
267
- await saveIndex(next);
268
- const stored = await loadSnapshot(id);
269
- if (stored) {
270
- stored.meta.name = name;
271
- await persistentStorage.setItem(SNAP_PREFIX + id, JSON.stringify(stored));
272
- }
273
- return next;
274
- }