@buoy-gg/time-machine 7.0.17

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 (60) hide show
  1. package/LICENSE +58 -0
  2. package/README.md +55 -0
  3. package/lib/commonjs/components/TimeMachineBody.js +420 -0
  4. package/lib/commonjs/components/TimeMachineBody.js.map +1 -0
  5. package/lib/commonjs/components/TimeMachineModal.js +74 -0
  6. package/lib/commonjs/components/TimeMachineModal.js.map +1 -0
  7. package/lib/commonjs/hooks/useTimeMachine.js +24 -0
  8. package/lib/commonjs/hooks/useTimeMachine.js.map +1 -0
  9. package/lib/commonjs/index.js +64 -0
  10. package/lib/commonjs/index.js.map +1 -0
  11. package/lib/commonjs/package.json +1 -0
  12. package/lib/commonjs/preset.js +45 -0
  13. package/lib/commonjs/preset.js.map +1 -0
  14. package/lib/commonjs/store/snapshotVault.js +83 -0
  15. package/lib/commonjs/store/snapshotVault.js.map +1 -0
  16. package/lib/commonjs/store/timeMachineStore.js +335 -0
  17. package/lib/commonjs/store/timeMachineStore.js.map +1 -0
  18. package/lib/commonjs/sync/timeMachineSyncAdapter.js +139 -0
  19. package/lib/commonjs/sync/timeMachineSyncAdapter.js.map +1 -0
  20. package/lib/module/components/TimeMachineBody.js +415 -0
  21. package/lib/module/components/TimeMachineBody.js.map +1 -0
  22. package/lib/module/components/TimeMachineModal.js +68 -0
  23. package/lib/module/components/TimeMachineModal.js.map +1 -0
  24. package/lib/module/hooks/useTimeMachine.js +19 -0
  25. package/lib/module/hooks/useTimeMachine.js.map +1 -0
  26. package/lib/module/index.js +29 -0
  27. package/lib/module/index.js.map +1 -0
  28. package/lib/module/preset.js +40 -0
  29. package/lib/module/preset.js.map +1 -0
  30. package/lib/module/store/snapshotVault.js +74 -0
  31. package/lib/module/store/snapshotVault.js.map +1 -0
  32. package/lib/module/store/timeMachineStore.js +327 -0
  33. package/lib/module/store/timeMachineStore.js.map +1 -0
  34. package/lib/module/sync/timeMachineSyncAdapter.js +134 -0
  35. package/lib/module/sync/timeMachineSyncAdapter.js.map +1 -0
  36. package/lib/typescript/components/TimeMachineBody.d.ts +2 -0
  37. package/lib/typescript/components/TimeMachineBody.d.ts.map +1 -0
  38. package/lib/typescript/components/TimeMachineModal.d.ts +12 -0
  39. package/lib/typescript/components/TimeMachineModal.d.ts.map +1 -0
  40. package/lib/typescript/hooks/useTimeMachine.d.ts +6 -0
  41. package/lib/typescript/hooks/useTimeMachine.d.ts.map +1 -0
  42. package/lib/typescript/index.d.ts +18 -0
  43. package/lib/typescript/index.d.ts.map +1 -0
  44. package/lib/typescript/preset.d.ts +38 -0
  45. package/lib/typescript/preset.d.ts.map +1 -0
  46. package/lib/typescript/store/snapshotVault.d.ts +46 -0
  47. package/lib/typescript/store/snapshotVault.d.ts.map +1 -0
  48. package/lib/typescript/store/timeMachineStore.d.ts +97 -0
  49. package/lib/typescript/store/timeMachineStore.d.ts.map +1 -0
  50. package/lib/typescript/sync/timeMachineSyncAdapter.d.ts +59 -0
  51. package/lib/typescript/sync/timeMachineSyncAdapter.d.ts.map +1 -0
  52. package/package.json +59 -0
  53. package/src/components/TimeMachineBody.tsx +455 -0
  54. package/src/components/TimeMachineModal.tsx +75 -0
  55. package/src/hooks/useTimeMachine.ts +26 -0
  56. package/src/index.tsx +45 -0
  57. package/src/preset.tsx +38 -0
  58. package/src/store/snapshotVault.ts +117 -0
  59. package/src/store/timeMachineStore.ts +368 -0
  60. package/src/sync/timeMachineSyncAdapter.ts +128 -0
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ import { useEffect, useState, useSyncExternalStore } from "react";
4
+ import { getStateSnapshotProviders, subscribeToStateSnapshotProviders } from "@buoy-gg/shared-ui";
5
+ import { timeMachineStore } from "../store/timeMachineStore";
6
+ export function useTimeMachineState() {
7
+ return useSyncExternalStore(timeMachineStore.subscribe, () => timeMachineStore.getState());
8
+ }
9
+
10
+ /** Registered snapshot providers (query registers late, hence the subscribe). */
11
+ export function useSnapshotProviders() {
12
+ const [providers, setProviders] = useState(getStateSnapshotProviders);
13
+ useEffect(() => {
14
+ setProviders(getStateSnapshotProviders());
15
+ return subscribeToStateSnapshotProviders(() => setProviders(getStateSnapshotProviders()));
16
+ }, []);
17
+ return providers;
18
+ }
19
+ //# sourceMappingURL=useTimeMachine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["useEffect","useState","useSyncExternalStore","getStateSnapshotProviders","subscribeToStateSnapshotProviders","timeMachineStore","useTimeMachineState","subscribe","getState","useSnapshotProviders","providers","setProviders"],"sourceRoot":"../../../src","sources":["hooks/useTimeMachine.ts"],"mappings":";;AAAA,SAASA,SAAS,EAAEC,QAAQ,EAAEC,oBAAoB,QAAQ,OAAO;AACjE,SACEC,yBAAyB,EACzBC,iCAAiC,QAE5B,oBAAoB;AAC3B,SAASC,gBAAgB,QAAQ,2BAA2B;AAG5D,OAAO,SAASC,mBAAmBA,CAAA,EAAqB;EACtD,OAAOJ,oBAAoB,CAACG,gBAAgB,CAACE,SAAS,EAAE,MACtDF,gBAAgB,CAACG,QAAQ,CAAC,CAC5B,CAAC;AACH;;AAEA;AACA,OAAO,SAASC,oBAAoBA,CAAA,EAA4B;EAC9D,MAAM,CAACC,SAAS,EAAEC,YAAY,CAAC,GAAGV,QAAQ,CAACE,yBAAyB,CAAC;EACrEH,SAAS,CAAC,MAAM;IACdW,YAAY,CAACR,yBAAyB,CAAC,CAAC,CAAC;IACzC,OAAOC,iCAAiC,CAAC,MACvCO,YAAY,CAACR,yBAAyB,CAAC,CAAC,CAC1C,CAAC;EACH,CAAC,EAAE,EAAE,CAAC;EACN,OAAOO,SAAS;AAClB","ignoreList":[]}
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * @buoy-gg/time-machine
5
+ *
6
+ * Time Machine — snapshot & restore app state for React Native DevTools.
7
+ *
8
+ * Capture the complete client-side state of the app (storage, Redux,
9
+ * Zustand, Jotai, React Query) as a named snapshot; restore any snapshot in
10
+ * one tap to iterate on multi-step test flows without rebuilding state.
11
+ *
12
+ * PUBLIC API - Only these exports are supported for external use.
13
+ */
14
+
15
+ // Tool preset for FloatingDevTools
16
+ export { timeMachineToolPreset, createTimeMachineTool } from "./preset";
17
+
18
+ // Components
19
+ export { TimeMachineModal, TimeMachineToolView } from "./components/TimeMachineModal";
20
+
21
+ // External-sync adapter (auto-registered by @buoy-gg/core)
22
+ export { timeMachineSyncAdapter } from "./sync/timeMachineSyncAdapter";
23
+
24
+ // Programmatic snapshot control (also used by tests / power users)
25
+ export { timeMachineStore, RESTORE_ORDER } from "./store/timeMachineStore";
26
+
27
+ // Buoy Desktop remote-mirror seam
28
+ export { setRemoteTimeMachineHandler, replaceTimeMachineFromSnapshot } from "./store/timeMachineStore";
29
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["timeMachineToolPreset","createTimeMachineTool","TimeMachineModal","TimeMachineToolView","timeMachineSyncAdapter","timeMachineStore","RESTORE_ORDER","setRemoteTimeMachineHandler","replaceTimeMachineFromSnapshot"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,SAASA,qBAAqB,EAAEC,qBAAqB,QAAQ,UAAU;;AAEvE;AACA,SACEC,gBAAgB,EAChBC,mBAAmB,QAEd,+BAA+B;;AAEtC;AACA,SAASC,sBAAsB,QAAQ,+BAA+B;;AAEtE;AACA,SACEC,gBAAgB,EAChBC,aAAa,QAKR,0BAA0B;;AAEjC;AACA,SACEC,2BAA2B,EAC3BC,8BAA8B,QACzB,0BAA0B","ignoreList":[]}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Pre-configured Time Machine tool for FloatingDevTools.
5
+ *
6
+ * @example
7
+ * ```tsx
8
+ * import { timeMachineToolPreset } from '@buoy-gg/time-machine';
9
+ *
10
+ * <FloatingDevTools apps={[timeMachineToolPreset]} />
11
+ * ```
12
+ */
13
+
14
+ import { TimeMachineIcon, TIME_MACHINE_ICON_COLOR } from "@buoy-gg/shared-ui";
15
+ import { TimeMachineModal } from "./components/TimeMachineModal";
16
+ import { jsx as _jsx } from "react/jsx-runtime";
17
+ export const timeMachineToolPreset = {
18
+ id: "time-machine",
19
+ name: "TIME MACHINE",
20
+ description: "Snapshot & restore app state (storage, stores, query cache)",
21
+ slot: "both",
22
+ icon: ({
23
+ size,
24
+ color
25
+ }) => /*#__PURE__*/_jsx(TimeMachineIcon, {
26
+ size: size,
27
+ color: color || TIME_MACHINE_ICON_COLOR
28
+ }),
29
+ component: TimeMachineModal
30
+ };
31
+
32
+ /** Create a custom Time Machine tool configuration. */
33
+ export function createTimeMachineTool(options = {}) {
34
+ return {
35
+ ...timeMachineToolPreset,
36
+ name: options.name ?? timeMachineToolPreset.name,
37
+ description: options.description ?? timeMachineToolPreset.description
38
+ };
39
+ }
40
+ //# sourceMappingURL=preset.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["TimeMachineIcon","TIME_MACHINE_ICON_COLOR","TimeMachineModal","jsx","_jsx","timeMachineToolPreset","id","name","description","slot","icon","size","color","component","createTimeMachineTool","options"],"sourceRoot":"../../src","sources":["preset.tsx"],"mappings":";;AAAA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,SACEA,eAAe,EACfC,uBAAuB,QAClB,oBAAoB;AAC3B,SAASC,gBAAgB,QAAQ,+BAA+B;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAEjE,OAAO,MAAMC,qBAAqB,GAAG;EACnCC,EAAE,EAAE,cAAc;EAClBC,IAAI,EAAE,cAAc;EACpBC,WAAW,EAAE,6DAA6D;EAC1EC,IAAI,EAAE,MAAe;EACrBC,IAAI,EAAEA,CAAC;IAAEC,IAAI;IAAEC;EAAwC,CAAC,kBACtDR,IAAA,CAACJ,eAAe;IAACW,IAAI,EAAEA,IAAK;IAACC,KAAK,EAAEA,KAAK,IAAIX;EAAwB,CAAE,CACxE;EACDY,SAAS,EAAEX;AACb,CAAC;;AAED;AACA,OAAO,SAASY,qBAAqBA,CACnCC,OAAgD,GAAG,CAAC,CAAC,EACrD;EACA,OAAO;IACL,GAAGV,qBAAqB;IACxBE,IAAI,EAAEQ,OAAO,CAACR,IAAI,IAAIF,qBAAqB,CAACE,IAAI;IAChDC,WAAW,EAAEO,OAAO,CAACP,WAAW,IAAIH,qBAAqB,CAACG;EAC5D,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,74 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Snapshot persistence for Time Machine.
5
+ *
6
+ * Snapshots live ON-DEVICE in persistentStorage (FileSystem → AsyncStorage →
7
+ * localStorage → Memory fallback): no size caps, survives restarts, and never
8
+ * crosses the 2MB external-sync snapshot budget — only metadata does.
9
+ *
10
+ * Layout: ONE storage key per snapshot (persistentStorage's FileSystem
11
+ * backend writes one file per key, and its multiGet is sequential — a single
12
+ * big key beats many small ones), plus one index key holding the metadata
13
+ * list for cheap listing.
14
+ *
15
+ * Keys use the `@react_buoy` family so every tool's isDevToolsStorageKey
16
+ * filter (including our own storage provider) excludes the vault itself from
17
+ * snapshots — a snapshot must never contain snapshots.
18
+ */
19
+ import { persistentStorage } from "@buoy-gg/shared-ui";
20
+ const INDEX_KEY = "@react_buoy_time_machine:index";
21
+ const SNAP_PREFIX = "@react_buoy_time_machine:snap:";
22
+ export async function loadIndex() {
23
+ try {
24
+ const raw = await persistentStorage.getItem(INDEX_KEY);
25
+ if (!raw) return [];
26
+ const parsed = JSON.parse(raw);
27
+ return Array.isArray(parsed) ? parsed : [];
28
+ } catch {
29
+ return [];
30
+ }
31
+ }
32
+ async function saveIndex(metas) {
33
+ await persistentStorage.setItem(INDEX_KEY, JSON.stringify(metas));
34
+ }
35
+
36
+ /** Persists the snapshot, stamps meta.sizeBytes, and updates the index. */
37
+ export async function saveSnapshot(snapshot, metas) {
38
+ const serialized = JSON.stringify(snapshot);
39
+ snapshot.meta.sizeBytes = serialized.length;
40
+ await persistentStorage.setItem(SNAP_PREFIX + snapshot.meta.id,
41
+ // Re-stringify so the persisted copy carries the final sizeBytes.
42
+ JSON.stringify(snapshot));
43
+ const next = [snapshot.meta, ...metas.filter(m => m.id !== snapshot.meta.id)];
44
+ await saveIndex(next);
45
+ return next;
46
+ }
47
+ export async function loadSnapshot(id) {
48
+ try {
49
+ const raw = await persistentStorage.getItem(SNAP_PREFIX + id);
50
+ return raw ? JSON.parse(raw) : null;
51
+ } catch {
52
+ return null;
53
+ }
54
+ }
55
+ export async function deleteSnapshot(id, metas) {
56
+ await persistentStorage.removeItem(SNAP_PREFIX + id);
57
+ const next = metas.filter(m => m.id !== id);
58
+ await saveIndex(next);
59
+ return next;
60
+ }
61
+ export async function renameSnapshot(id, name, metas) {
62
+ const next = metas.map(m => m.id === id ? {
63
+ ...m,
64
+ name
65
+ } : m);
66
+ await saveIndex(next);
67
+ const stored = await loadSnapshot(id);
68
+ if (stored) {
69
+ stored.meta.name = name;
70
+ await persistentStorage.setItem(SNAP_PREFIX + id, JSON.stringify(stored));
71
+ }
72
+ return next;
73
+ }
74
+ //# sourceMappingURL=snapshotVault.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["persistentStorage","INDEX_KEY","SNAP_PREFIX","loadIndex","raw","getItem","parsed","JSON","parse","Array","isArray","saveIndex","metas","setItem","stringify","saveSnapshot","snapshot","serialized","meta","sizeBytes","length","id","next","filter","m","loadSnapshot","deleteSnapshot","removeItem","renameSnapshot","name","map","stored"],"sourceRoot":"../../../src","sources":["store/snapshotVault.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,327 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Time Machine orchestrator — snapshot CRUD + capture/restore across every
5
+ * registered StateSnapshotProvider (storage, redux, zustand, jotai, query,
6
+ * plus any custom providers the app registers).
7
+ *
8
+ * Restore ordering is fixed: persisted storage FIRST (so store persist
9
+ * middleware writing through after an in-memory restore converges with what
10
+ * we just wrote), then redux → zustand → jotai, query LAST (restored queries
11
+ * may derive from store state). Custom providers run after, in data order.
12
+ *
13
+ * Two restore modes:
14
+ * - "live": in-place state replacement, capability-gated per source.
15
+ * - "reload": restore ONLY persisted storage, then reload the JS bundle —
16
+ * in-memory stores rebuild themselves from the restored storage.
17
+ * Baseline snapshots always use this path (clear + reload).
18
+ */
19
+ import { getStateSnapshotProvider, getStateSnapshotProviders, scheduleReloadApp, superJsonDeserialize, superJsonSerialize } from "@buoy-gg/shared-ui";
20
+ import { deleteSnapshot, loadIndex, loadSnapshot, renameSnapshot, saveSnapshot } from "./snapshotVault";
21
+ export const RESTORE_ORDER = ["storage", "redux", "zustand", "jotai", "query"];
22
+
23
+ /** Provider capability row as mirrored to a remote dashboard. */
24
+
25
+ let remoteHandler = null;
26
+ function skippedResult(reason) {
27
+ return {
28
+ ok: false,
29
+ applied: 0,
30
+ skipped: [{
31
+ id: "*",
32
+ reason
33
+ }],
34
+ warnings: []
35
+ };
36
+ }
37
+ let idCounter = 0;
38
+ function nextId() {
39
+ idCounter += 1;
40
+ return `snap_${Date.now().toString(36)}_${idCounter.toString(36)}`;
41
+ }
42
+ class TimeMachineStore {
43
+ state = {
44
+ snapshots: [],
45
+ hasLoaded: false,
46
+ busy: null,
47
+ lastOutcome: null,
48
+ remoteProviders: null
49
+ };
50
+ listeners = new Set();
51
+ loadPromise = null;
52
+ getState() {
53
+ return this.state;
54
+ }
55
+ subscribe = listener => {
56
+ this.listeners.add(listener);
57
+ void this.ensureLoaded();
58
+ return () => {
59
+ this.listeners.delete(listener);
60
+ };
61
+ };
62
+ setState(patch) {
63
+ this.state = {
64
+ ...this.state,
65
+ ...patch
66
+ };
67
+ this.listeners.forEach(l => {
68
+ try {
69
+ l();
70
+ } catch {
71
+ // listener errors must not break the store
72
+ }
73
+ });
74
+ }
75
+ ensureLoaded() {
76
+ if (remoteHandler) return Promise.resolve(); // mirror mode — device owns the vault
77
+ if (!this.loadPromise) {
78
+ this.loadPromise = loadIndex().then(snapshots => {
79
+ if (remoteHandler) return;
80
+ this.setState({
81
+ snapshots,
82
+ hasLoaded: true
83
+ });
84
+ });
85
+ }
86
+ return this.loadPromise;
87
+ }
88
+
89
+ /** @internal Buoy Desktop: mirror the device's synced metadata payload. */
90
+ replaceFromSnapshot(payload) {
91
+ this.setState({
92
+ snapshots: payload.snapshots ?? [],
93
+ busy: payload.busy ?? null,
94
+ lastOutcome: payload.lastOutcome ?? null,
95
+ remoteProviders: payload.providers ?? [],
96
+ hasLoaded: true
97
+ });
98
+ }
99
+
100
+ /** Capture all capturable sources (or a subset) into a named snapshot. */
101
+ async capture(name, sourceIds) {
102
+ if (remoteHandler) {
103
+ const result = await remoteHandler("capture", {
104
+ name,
105
+ sourceIds
106
+ });
107
+ return result.snapshot;
108
+ }
109
+ await this.ensureLoaded();
110
+ this.setState({
111
+ busy: "capture"
112
+ });
113
+ try {
114
+ const providers = getStateSnapshotProviders().filter(p => p.status().canCapture && (!sourceIds || sourceIds.includes(p.id)));
115
+ const data = {};
116
+ const sources = {};
117
+ for (const provider of providers) {
118
+ try {
119
+ const captured = await provider.capture();
120
+ data[provider.id] = superJsonSerialize(captured.data);
121
+ sources[provider.id] = {
122
+ warnings: captured.warnings
123
+ };
124
+ } catch (e) {
125
+ sources[provider.id] = {
126
+ warnings: [`capture failed: ${String(e)}`]
127
+ };
128
+ }
129
+ }
130
+ const snapshot = {
131
+ meta: {
132
+ id: nextId(),
133
+ name: name.trim() || "Untitled snapshot",
134
+ createdAt: Date.now(),
135
+ sizeBytes: 0,
136
+ sources
137
+ },
138
+ data
139
+ };
140
+ const snapshots = await saveSnapshot(snapshot, this.state.snapshots);
141
+ this.setState({
142
+ snapshots
143
+ });
144
+ return snapshot.meta;
145
+ } finally {
146
+ this.setState({
147
+ busy: null
148
+ });
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Capture the fresh-install baseline: an EMPTY snapshot whose restore
154
+ * wipes app state (clear + reload) — regardless of what state the app is
155
+ * in when the button is pressed.
156
+ */
157
+ async captureBaseline() {
158
+ if (remoteHandler) {
159
+ const result = await remoteHandler("captureBaseline", {});
160
+ return result.snapshot;
161
+ }
162
+ await this.ensureLoaded();
163
+ const snapshot = {
164
+ meta: {
165
+ id: nextId(),
166
+ name: "Fresh install",
167
+ createdAt: Date.now(),
168
+ sizeBytes: 0,
169
+ baseline: true,
170
+ sources: {}
171
+ },
172
+ data: {}
173
+ };
174
+ const snapshots = await saveSnapshot(snapshot, this.state.snapshots);
175
+ this.setState({
176
+ snapshots
177
+ });
178
+ return snapshot.meta;
179
+ }
180
+ async restore(id, mode) {
181
+ if (remoteHandler) {
182
+ const outcome = await remoteHandler("restore", {
183
+ id,
184
+ mode
185
+ });
186
+ this.setState({
187
+ lastOutcome: outcome
188
+ });
189
+ return outcome;
190
+ }
191
+ await this.ensureLoaded();
192
+ this.setState({
193
+ busy: "restore"
194
+ });
195
+ try {
196
+ const stored = await loadSnapshot(id);
197
+ if (!stored) throw new Error(`No snapshot with id "${id}"`);
198
+ const outcome = {
199
+ snapshotId: id,
200
+ snapshotName: stored.meta.name,
201
+ mode,
202
+ at: Date.now(),
203
+ willReload: false,
204
+ results: {}
205
+ };
206
+ if (stored.meta.baseline) {
207
+ // Fresh install: wipe every clearable source, then reload so all
208
+ // in-memory state rebuilds from nothing.
209
+ for (const provider of getStateSnapshotProviders()) {
210
+ if (provider.clear) {
211
+ try {
212
+ outcome.results[provider.id] = await provider.clear();
213
+ } catch (e) {
214
+ outcome.results[provider.id] = skippedResult(String(e));
215
+ }
216
+ }
217
+ }
218
+ outcome.willReload = this.scheduleReload("buoy time-machine baseline");
219
+ this.setState({
220
+ lastOutcome: outcome
221
+ });
222
+ return outcome;
223
+ }
224
+ const sourceIds = [...RESTORE_ORDER.filter(sid => sid in stored.data), ...Object.keys(stored.data).filter(sid => !RESTORE_ORDER.includes(sid))];
225
+ if (mode === "reload") {
226
+ // Storage only; everything in-memory rebuilds after the reload.
227
+ if (stored.data.storage) {
228
+ outcome.results.storage = await this.restoreSource("storage", stored.data.storage);
229
+ }
230
+ outcome.willReload = this.scheduleReload("buoy time-machine restore");
231
+ this.setState({
232
+ lastOutcome: outcome
233
+ });
234
+ return outcome;
235
+ }
236
+ for (const sid of sourceIds) {
237
+ outcome.results[sid] = await this.restoreSource(sid, stored.data[sid]);
238
+ }
239
+ this.setState({
240
+ lastOutcome: outcome
241
+ });
242
+ return outcome;
243
+ } finally {
244
+ this.setState({
245
+ busy: null
246
+ });
247
+ }
248
+ }
249
+ async restoreSource(sourceId, payload) {
250
+ const provider = getStateSnapshotProvider(sourceId);
251
+ if (!provider) {
252
+ return skippedResult("provider not available (package missing or not initialized)");
253
+ }
254
+ const status = provider.status();
255
+ if (!status.canRestore) {
256
+ return skippedResult(status.detail ?? "restore unavailable");
257
+ }
258
+ try {
259
+ return await provider.restore(superJsonDeserialize(payload));
260
+ } catch (e) {
261
+ return skippedResult(String(e));
262
+ }
263
+ }
264
+ scheduleReload(reason) {
265
+ try {
266
+ scheduleReloadApp({
267
+ reason
268
+ });
269
+ return true;
270
+ } catch {
271
+ // No reload mechanism (bare production build?) — restore still stands.
272
+ return false;
273
+ }
274
+ }
275
+ async delete(id) {
276
+ if (remoteHandler) {
277
+ await remoteHandler("delete", {
278
+ id
279
+ });
280
+ return;
281
+ }
282
+ await this.ensureLoaded();
283
+ const snapshots = await deleteSnapshot(id, this.state.snapshots);
284
+ this.setState({
285
+ snapshots
286
+ });
287
+ }
288
+ async rename(id, name) {
289
+ if (remoteHandler) {
290
+ await remoteHandler("rename", {
291
+ id,
292
+ name
293
+ });
294
+ return;
295
+ }
296
+ await this.ensureLoaded();
297
+ const snapshots = await renameSnapshot(id, name, this.state.snapshots);
298
+ this.setState({
299
+ snapshots
300
+ });
301
+ }
302
+ clearLastOutcome() {
303
+ this.setState({
304
+ lastOutcome: null
305
+ });
306
+ }
307
+ }
308
+ export const timeMachineStore = new TimeMachineStore();
309
+
310
+ /**
311
+ * Buoy Desktop: route every Time Machine operation through a remote handler
312
+ * (the device's sync adapter actions) instead of running locally. Pass null
313
+ * to detach. While attached, feed device payloads to
314
+ * {@link replaceTimeMachineFromSnapshot}.
315
+ */
316
+ export function setRemoteTimeMachineHandler(handler) {
317
+ remoteHandler = handler;
318
+ if (!handler) {
319
+ timeMachineStore.replaceFromSnapshot({});
320
+ }
321
+ }
322
+
323
+ /** Buoy Desktop: mirror a device's synced Time Machine metadata payload. */
324
+ export function replaceTimeMachineFromSnapshot(payload) {
325
+ timeMachineStore.replaceFromSnapshot(payload);
326
+ }
327
+ //# sourceMappingURL=timeMachineStore.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["getStateSnapshotProvider","getStateSnapshotProviders","scheduleReloadApp","superJsonDeserialize","superJsonSerialize","deleteSnapshot","loadIndex","loadSnapshot","renameSnapshot","saveSnapshot","RESTORE_ORDER","remoteHandler","skippedResult","reason","ok","applied","skipped","id","warnings","idCounter","nextId","Date","now","toString","TimeMachineStore","state","snapshots","hasLoaded","busy","lastOutcome","remoteProviders","listeners","Set","loadPromise","getState","subscribe","listener","add","ensureLoaded","delete","setState","patch","forEach","l","Promise","resolve","then","replaceFromSnapshot","payload","providers","capture","name","sourceIds","result","snapshot","filter","p","status","canCapture","includes","data","sources","provider","captured","e","String","meta","trim","createdAt","sizeBytes","captureBaseline","baseline","restore","mode","outcome","stored","Error","snapshotId","snapshotName","at","willReload","results","clear","scheduleReload","sid","Object","keys","storage","restoreSource","sourceId","canRestore","detail","rename","clearLastOutcome","timeMachineStore","setRemoteTimeMachineHandler","handler","replaceTimeMachineFromSnapshot"],"sourceRoot":"../../../src","sources":["store/timeMachineStore.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+
3
+ /**
4
+ * Sync adapter for the Time Machine tool, consumed by @buoy-gg/external-sync's
5
+ * `useExternalSync` (structurally matches its ToolSyncAdapter interface so
6
+ * this package doesn't need a dependency on it).
7
+ *
8
+ * Snapshots stay ON-DEVICE — getSnapshot ships METADATA only (list, provider
9
+ * statuses, last restore outcome), far under the 2MB per-tool budget. Payload
10
+ * inspection goes through the `inspect` action (8MB action-result budget).
11
+ *
12
+ * The `restore` action uses the store's scheduleReloadApp path for reload
13
+ * mode, so the action RESULT is flushed to the broker before the JS realm
14
+ * dies — a remote caller always gets its answer.
15
+ */
16
+ import { getStateSnapshotProviders, subscribeToStateSnapshotProviders, superJsonDeserialize } from "@buoy-gg/shared-ui";
17
+ import { timeMachineStore } from "../store/timeMachineStore";
18
+ import { loadSnapshot } from "../store/snapshotVault";
19
+ function providerStatuses() {
20
+ return getStateSnapshotProviders().map(p => {
21
+ const s = p.status();
22
+ return {
23
+ id: p.id,
24
+ label: p.label,
25
+ canCapture: s.canCapture,
26
+ canRestore: s.canRestore,
27
+ detail: s.detail
28
+ };
29
+ });
30
+ }
31
+ function metadata() {
32
+ const {
33
+ snapshots,
34
+ busy,
35
+ lastOutcome
36
+ } = timeMachineStore.getState();
37
+ return {
38
+ snapshots,
39
+ busy,
40
+ lastOutcome,
41
+ providers: providerStatuses()
42
+ };
43
+ }
44
+ export const timeMachineSyncAdapter = {
45
+ version: 1,
46
+ getSnapshot: () => metadata(),
47
+ subscribe: onChange => {
48
+ const unsubStore = timeMachineStore.subscribe(onChange);
49
+ const unsubProviders = subscribeToStateSnapshotProviders(onChange);
50
+ return () => {
51
+ unsubStore();
52
+ unsubProviders();
53
+ };
54
+ },
55
+ actions: {
56
+ list: () => metadata(),
57
+ capture: async params => {
58
+ const {
59
+ name = "",
60
+ sourceIds
61
+ } = params ?? {};
62
+ const meta = await timeMachineStore.capture(name, sourceIds);
63
+ return {
64
+ captured: true,
65
+ snapshot: meta
66
+ };
67
+ },
68
+ captureBaseline: async () => {
69
+ const meta = await timeMachineStore.captureBaseline();
70
+ return {
71
+ captured: true,
72
+ snapshot: meta
73
+ };
74
+ },
75
+ /** mode "live" (default) replaces state in place; "reload" restores
76
+ * persisted storage then reloads the JS bundle (always the path for
77
+ * baseline snapshots). */
78
+ restore: async params => {
79
+ const {
80
+ id,
81
+ mode = "live"
82
+ } = params ?? {};
83
+ if (!id) throw new Error("restore requires a snapshot `id`");
84
+ return await timeMachineStore.restore(id, mode);
85
+ },
86
+ delete: async params => {
87
+ const {
88
+ id
89
+ } = params ?? {};
90
+ if (!id) throw new Error("delete requires a snapshot `id`");
91
+ await timeMachineStore.delete(id);
92
+ return {
93
+ deleted: true,
94
+ id
95
+ };
96
+ },
97
+ rename: async params => {
98
+ const {
99
+ id,
100
+ name
101
+ } = params ?? {};
102
+ if (!id || !name) throw new Error("rename requires `id` and `name`");
103
+ await timeMachineStore.rename(id, name);
104
+ return {
105
+ renamed: true,
106
+ id,
107
+ name
108
+ };
109
+ },
110
+ /** One source's captured payload, deserialized — for remote inspection. */
111
+ inspect: async params => {
112
+ const {
113
+ id,
114
+ sourceId
115
+ } = params ?? {};
116
+ if (!id || !sourceId) {
117
+ throw new Error("inspect requires `id` and `sourceId`");
118
+ }
119
+ const stored = await loadSnapshot(id);
120
+ if (!stored) throw new Error(`No snapshot with id "${id}"`);
121
+ const payload = stored.data[sourceId];
122
+ if (!payload) {
123
+ throw new Error(`Snapshot "${id}" has no "${sourceId}" source`);
124
+ }
125
+ return {
126
+ id,
127
+ sourceId,
128
+ warnings: stored.meta.sources[sourceId]?.warnings ?? [],
129
+ data: superJsonDeserialize(payload)
130
+ };
131
+ }
132
+ }
133
+ };
134
+ //# sourceMappingURL=timeMachineSyncAdapter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["getStateSnapshotProviders","subscribeToStateSnapshotProviders","superJsonDeserialize","timeMachineStore","loadSnapshot","providerStatuses","map","p","s","status","id","label","canCapture","canRestore","detail","metadata","snapshots","busy","lastOutcome","getState","providers","timeMachineSyncAdapter","version","getSnapshot","subscribe","onChange","unsubStore","unsubProviders","actions","list","capture","params","name","sourceIds","meta","captured","snapshot","captureBaseline","restore","mode","Error","delete","deleted","rename","renamed","inspect","sourceId","stored","payload","data","warnings","sources"],"sourceRoot":"../../../src","sources":["sync/timeMachineSyncAdapter.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ export declare function TimeMachineBody(): import("react").JSX.Element;
2
+ //# sourceMappingURL=TimeMachineBody.d.ts.map