@buoy-gg/zustand 7.0.41 → 7.0.43

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 (63) hide show
  1. package/README.md +11 -76
  2. package/lib/commonjs/index.js +1 -105
  3. package/lib/commonjs/preset.js +1 -102
  4. package/lib/commonjs/zustand/components/ZustandActionButton.js +1 -118
  5. package/lib/commonjs/zustand/components/ZustandDetailViewToggle.js +1 -48
  6. package/lib/commonjs/zustand/components/ZustandEventFilterView.js +1 -43
  7. package/lib/commonjs/zustand/components/ZustandIcon.js +1 -18
  8. package/lib/commonjs/zustand/components/ZustandModal.js +1 -772
  9. package/lib/commonjs/zustand/components/ZustandStateChangeItem.js +1 -117
  10. package/lib/commonjs/zustand/components/ZustandStateDetailContent.js +1 -372
  11. package/lib/commonjs/zustand/components/ZustandStateInfoView.js +1 -488
  12. package/lib/commonjs/zustand/components/ZustandStoreBrowser.js +1 -204
  13. package/lib/commonjs/zustand/components/ZustandStoreDetailContent.js +1 -471
  14. package/lib/commonjs/zustand/hooks/useZustandStateChanges.js +1 -74
  15. package/lib/commonjs/zustand/sync/zustandSyncAdapter.js +1 -418
  16. package/lib/commonjs/zustand/types/index.js +1 -1
  17. package/lib/commonjs/zustand/utils/buoyZustandMiddleware.js +1 -284
  18. package/lib/commonjs/zustand/utils/editableState.js +1 -146
  19. package/lib/commonjs/zustand/utils/snapshotProvider.js +1 -209
  20. package/lib/commonjs/zustand/utils/testIDs.js +1 -82
  21. package/lib/commonjs/zustand/utils/zustandStateStore.js +1 -379
  22. package/lib/module/index.js +1 -90
  23. package/lib/module/preset.js +1 -98
  24. package/lib/module/zustand/components/ZustandActionButton.js +1 -114
  25. package/lib/module/zustand/components/ZustandDetailViewToggle.js +1 -43
  26. package/lib/module/zustand/components/ZustandEventFilterView.js +1 -39
  27. package/lib/module/zustand/components/ZustandIcon.js +1 -11
  28. package/lib/module/zustand/components/ZustandModal.js +1 -767
  29. package/lib/module/zustand/components/ZustandStateChangeItem.js +1 -113
  30. package/lib/module/zustand/components/ZustandStateDetailContent.js +1 -368
  31. package/lib/module/zustand/components/ZustandStateInfoView.js +1 -483
  32. package/lib/module/zustand/components/ZustandStoreBrowser.js +1 -200
  33. package/lib/module/zustand/components/ZustandStoreDetailContent.js +1 -469
  34. package/lib/module/zustand/hooks/useZustandStateChanges.js +1 -70
  35. package/lib/module/zustand/sync/zustandSyncAdapter.js +1 -415
  36. package/lib/module/zustand/types/index.js +1 -1
  37. package/lib/module/zustand/utils/buoyZustandMiddleware.js +1 -278
  38. package/lib/module/zustand/utils/editableState.js +1 -138
  39. package/lib/module/zustand/utils/snapshotProvider.js +1 -209
  40. package/lib/module/zustand/utils/testIDs.js +1 -74
  41. package/lib/module/zustand/utils/zustandStateStore.js +1 -375
  42. package/lib/web/index.mjs +2 -3
  43. package/package.json +4 -7
  44. package/lib/typescript/index.d.ts.map +0 -1
  45. package/lib/typescript/preset.d.ts.map +0 -1
  46. package/lib/typescript/zustand/components/ZustandActionButton.d.ts.map +0 -1
  47. package/lib/typescript/zustand/components/ZustandDetailViewToggle.d.ts.map +0 -1
  48. package/lib/typescript/zustand/components/ZustandEventFilterView.d.ts.map +0 -1
  49. package/lib/typescript/zustand/components/ZustandIcon.d.ts.map +0 -1
  50. package/lib/typescript/zustand/components/ZustandModal.d.ts.map +0 -1
  51. package/lib/typescript/zustand/components/ZustandStateChangeItem.d.ts.map +0 -1
  52. package/lib/typescript/zustand/components/ZustandStateDetailContent.d.ts.map +0 -1
  53. package/lib/typescript/zustand/components/ZustandStateInfoView.d.ts.map +0 -1
  54. package/lib/typescript/zustand/components/ZustandStoreBrowser.d.ts.map +0 -1
  55. package/lib/typescript/zustand/components/ZustandStoreDetailContent.d.ts.map +0 -1
  56. package/lib/typescript/zustand/hooks/useZustandStateChanges.d.ts.map +0 -1
  57. package/lib/typescript/zustand/sync/zustandSyncAdapter.d.ts.map +0 -1
  58. package/lib/typescript/zustand/types/index.d.ts.map +0 -1
  59. package/lib/typescript/zustand/utils/buoyZustandMiddleware.d.ts.map +0 -1
  60. package/lib/typescript/zustand/utils/editableState.d.ts.map +0 -1
  61. package/lib/typescript/zustand/utils/snapshotProvider.d.ts.map +0 -1
  62. package/lib/typescript/zustand/utils/testIDs.d.ts.map +0 -1
  63. package/lib/typescript/zustand/utils/zustandStateStore.d.ts.map +0 -1
@@ -1,418 +1 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.zustandSyncAdapter = exports.STATE_ON_DEVICE = exports.PAYLOAD_ON_DEVICE = void 0;
7
- var _sharedUi = require("@buoy-gg/shared-ui");
8
- var _zustandStateStore = require("../utils/zustandStateStore");
9
- const isPlainRecord = v => typeof v === "object" && v !== null && !Array.isArray(v) && Object.getPrototypeOf(v) === Object.prototype;
10
-
11
- /**
12
- * Merge `patch` into `base` object by object. Anything that is not a plain object
13
- * on both sides (arrays, primitives, class instances, functions) is taken from
14
- * the patch as is.
15
- */
16
- function deepMergeInto(base, patch) {
17
- if (!isPlainRecord(base) || !isPlainRecord(patch)) return patch;
18
- const out = {
19
- ...base
20
- };
21
- for (const [k, v] of Object.entries(patch)) out[k] = k in base ? deepMergeInto(base[k], v) : v;
22
- return out;
23
- }
24
-
25
- /**
26
- * Sentinel used in WIRE-FORM snapshots in place of raw prevState/nextState.
27
- * Same hazard as redux: up to 200 changes × 2 full trees on every snapshot
28
- * freeze/OOM-killed large apps. Dashboards fetch trees via `getChangeDetail`.
29
- */
30
- const STATE_ON_DEVICE = exports.STATE_ON_DEVICE = (0, _sharedUi.onDeviceMarker)("State", "State trees stay on the device — fetched on demand via getChangeDetail / getStoreState.");
31
-
32
- /** Wire-form sentinel for an oversized `partial` (replace can carry a whole tree). */
33
- const PAYLOAD_ON_DEVICE = exports.PAYLOAD_ON_DEVICE = (0, _sharedUi.onDeviceMarker)("Payload", "Partial stays on the device — fetched on demand via getChangeDetail.");
34
- const isPlainObject = v => !!v && typeof v === "object" && !Array.isArray(v);
35
- /**
36
- * Does this patch write into the list at `path`? Only then is an unchecked-shape
37
- * warning about that list worth saying — a patch that changes `promoCode` should
38
- * not be told about an empty `lines`.
39
- */
40
- function touchesList(patch, path) {
41
- let cur = patch;
42
- for (const seg of path.split(".")) {
43
- if (!cur || typeof cur !== "object" || Array.isArray(cur)) return false;
44
- if (!(seg in cur)) return false;
45
- cur = cur[seg];
46
- }
47
- // An empty list stays empty; there is no new item to be unsure about.
48
- return Array.isArray(cur) ? cur.length > 0 : !!cur && typeof cur === "object";
49
- }
50
-
51
- /** Top-level keys of an object state, for the compact (no-values) view. */
52
- function topLevelKeys(state) {
53
- return state && typeof state === "object" && !Array.isArray(state) ? Object.keys(state) : undefined;
54
- }
55
-
56
- /**
57
- * Per-change wire cache. The store prepends and never mutates a recorded
58
- * change, so keying on identity is correct and self-invalidating — without it
59
- * every `partial` in the list is re-measured on all ~5 snapshots per second.
60
- */
61
- const toWireChange = (0, _sharedUi.memoByIdentity)(change => ({
62
- ...change,
63
- prevState: STATE_ON_DEVICE,
64
- nextState: STATE_ON_DEVICE,
65
- partial: (0, _sharedUi.toWire)(change.partial, PAYLOAD_ON_DEVICE)
66
- }));
67
- const toWireState = value => (0, _sharedUi.toWire)(value, STATE_ON_DEVICE);
68
-
69
- /**
70
- * Sync adapter for the zustand tool, consumed by @buoy-gg/external-sync's
71
- * `useExternalSync`.
72
- *
73
- * State changes are captured by the middleware (watchStores/buoyDevTools),
74
- * independent of whether a dashboard is watching — subscribing here only
75
- * streams what the store already records. The snapshot carries both the
76
- * change timeline and the store registry (with each store's current state)
77
- * so the dashboard can render the store browser.
78
- *
79
- * v2: change-log prevState/nextState are replaced with on-device markers
80
- * (see STATE_ON_DEVICE). Dashboards fetch trees via `getChangeDetail`.
81
- * Oversized / unserializable `stores[].currentState` uses the same marker
82
- * and is fetched via `getStoreState`.
83
- *
84
- * The `setState` action powers remote time-travel/reset from the dashboard.
85
- */
86
- const zustandSyncAdapter = exports.zustandSyncAdapter = (0, _sharedUi.createSyncAdapter)({
87
- version: 2,
88
- getSnapshot: () => ({
89
- changes: _zustandStateStore.zustandStateStore.getStateChanges().map(toWireChange),
90
- stores: _zustandStateStore.zustandStateStore.getStoreSnapshots().map(store => ({
91
- ...store,
92
- currentState: toWireState(store.currentState)
93
- }))
94
- }),
95
- subscribe: [onChange => _zustandStateStore.zustandStateStore.subscribe(onChange), onChange => _zustandStateStore.zustandStateStore.subscribeToStores(onChange)],
96
- actions: {
97
- clearEvents: () => {
98
- _zustandStateStore.zustandStateStore.clearStateChanges();
99
- },
100
- /**
101
- * On-demand detail: one change's real prevState/nextState/partial.
102
- * The per-snapshot stream stays tree-free; this is the explicit,
103
- * size-guarded channel for the detail pane.
104
- */
105
- getChangeDetail: (0, _sharedUi.detailByIdAction)(id => _zustandStateStore.zustandStateStore.getStateChangeById(id), (change, cap) => ({
106
- prevState: cap(change.prevState),
107
- nextState: cap(change.nextState),
108
- partial: cap(change.partial)
109
- })),
110
- /**
111
- * On-demand current state for one store. Wire-form snapshots replace
112
- * oversized / unserializable `currentState` with STATE_ON_DEVICE.
113
- */
114
- getStoreState: params => {
115
- const {
116
- storeName,
117
- path
118
- } = (0, _sharedUi.readParams)(params);
119
- if (!storeName) return {
120
- found: false,
121
- reason: "missing storeName"
122
- };
123
- const store = _zustandStateStore.zustandStateStore.getStore(storeName);
124
- if (!store) return {
125
- found: false,
126
- reason: "unknown storeName"
127
- };
128
- let currentState;
129
- try {
130
- currentState = store.api.getState();
131
- } catch {
132
- currentState = undefined;
133
- }
134
- // One slice instead of the whole store. The reason to want it is the
135
- // engine's 24,000-character result cap: a caller that never saw the field
136
- // it means to edit is left inventing a shape, which is the failure this
137
- // whole surface keeps producing.
138
- if (path) {
139
- const at = (0, _sharedUi.readPath)(currentState, path);
140
- if (!at.ok) return {
141
- found: false,
142
- reason: at.error
143
- };
144
- return {
145
- found: true,
146
- storeName,
147
- path,
148
- shape: (0, _sharedUi.shapeSummary)(at.value),
149
- currentState: at.value
150
- };
151
- }
152
- // The sketch goes BEFORE currentState, deliberately. The engine truncates
153
- // a result by slicing the encoded string at 24,000 characters, so whatever
154
- // is serialised first is what survives — and the reads most in need of a
155
- // shape are exactly the long ones that get cut. It costs ~150 characters
156
- // and does not grow with the data.
157
- const shape = (0, _sharedUi.shapeSummary)(currentState);
158
- if (!(0, _sharedUi.isOverWireBudget)(currentState, _sharedUi.WIRE_DETAIL_LIMIT_BYTES)) {
159
- return {
160
- found: true,
161
- storeName,
162
- ...(shape ? {
163
- shape
164
- } : {}),
165
- currentState
166
- };
167
- }
168
- return {
169
- found: true,
170
- storeName,
171
- ...(shape ? {
172
- shape
173
- } : {}),
174
- currentState: (0, _sharedUi.isJsonSerializable)(currentState) ? (0, _sharedUi.truncatedNote)(_sharedUi.WIRE_DETAIL_LIMIT_BYTES) : STATE_ON_DEVICE
175
- };
176
- },
177
- /**
178
- * Compact current-state reader for a remote driver (MCP/LLM): the registered
179
- * stores with light metadata; each store's full `currentState` object stays
180
- * on the device unless `includeValues` is set (compact view returns just the
181
- * top-level `keys` so the shape is visible cheaply).
182
- */
183
- listStores: params => {
184
- const {
185
- includeValues = false,
186
- limit
187
- } = (0, _sharedUi.readParams)(params);
188
- const all = _zustandStateStore.zustandStateStore.getStoreSnapshots();
189
- const capped = typeof limit === "number" && limit > 0 ? all.slice(0, limit) : all;
190
- const stores = capped.map(s => ({
191
- name: s.name,
192
- changes: s.stateChangeCount,
193
- isPersisted: s.isPersisted,
194
- persistName: s.persistName,
195
- canRehydrate: s.canRehydrate,
196
- ...(includeValues ? {
197
- currentState: s.currentState
198
- } : {
199
- keys: topLevelKeys(s.currentState)
200
- }),
201
- // Cheap enough to always include: this is the compact view a caller
202
- // reaches for precisely because it does not want to pull the data, and
203
- // the item shape of a list is the one thing it cannot infer without it.
204
- ...((0, _sharedUi.shapeSummary)(s.currentState) ? {
205
- shape: (0, _sharedUi.shapeSummary)(s.currentState)
206
- } : {})
207
- }));
208
- return {
209
- stores,
210
- total: all.length,
211
- returned: stores.length,
212
- includedValues: includeValues
213
- };
214
- },
215
- setState: params => {
216
- const {
217
- storeName,
218
- state,
219
- replace,
220
- force,
221
- path,
222
- value
223
- } = (0, _sharedUi.readParams)(params);
224
- let effective = state;
225
- let keyedNotes = [];
226
- let unchecked = [];
227
- if (!storeName) return {
228
- ok: false,
229
- error: "Missing storeName."
230
- };
231
- const store = _zustandStateStore.zustandStateStore.getStore(storeName);
232
- if (!store) return {
233
- ok: false,
234
- error: `No store named "${storeName}".`
235
- };
236
- // `path` is sugar over a merge: it can only ever produce a patch, which
237
- // then goes through the guard below like any other. Its value is that
238
- // there is no nesting depth for the caller to get wrong.
239
- // `state` is no longer schema-required, because `path`+`value` is a valid
240
- // alternative — so the handler has to be the thing that rejects NEITHER.
241
- // Without this, `state` arrives undefined and falls through to
242
- // `setState(undefined, true)`, which is zustand's whole-state replace: the
243
- // store's data AND its action functions, gone, from a call that looks like
244
- // a typo. This is the most destructive thing in this file.
245
- if (state === undefined && path === undefined) {
246
- return {
247
- ok: false,
248
- error: `Refused: no change was described. Send \`state\` with the fields to merge, or \`path\` and \`value\` to set one value.`
249
- };
250
- }
251
- let pathed = false;
252
- if (path !== undefined) {
253
- if (value === undefined) {
254
- return {
255
- ok: false,
256
- error: `Refused: sent \`path\` without \`value\`. Say what to set "${path}" to; if you mean to clear it, send value:null and the field must already be nullable.`
257
- };
258
- }
259
- let currentForPath;
260
- try {
261
- currentForPath = store.api.getState();
262
- } catch {
263
- currentForPath = undefined;
264
- }
265
- const built = (0, _sharedUi.patchFromPath)(currentForPath, path, value);
266
- if (!built.ok) return {
267
- ok: false,
268
- error: `Refused: ${built.error}`
269
- };
270
- effective = built.patch;
271
- pathed = true;
272
- }
273
- // On a MERGE (replace:false), constrain it to a typed edit so a remote
274
- // caller can't hand the store a field of the wrong type or a malformed
275
- // new list item — the same protection the query cache has. A replace
276
- // (whole-store reset) and an explicit `force` skip this.
277
- if (!force && (replace === false || pathed)) {
278
- let current;
279
- try {
280
- current = store.api.getState();
281
- } catch {
282
- current = undefined;
283
- }
284
- // Expand id-addressed list edits BEFORE validating, so the typed-edit
285
- // guard below sees a real array and every existing protection still
286
- // applies to the result.
287
- if (current !== undefined) {
288
- const expanded = (0, _sharedUi.expandKeyedArrays)(current, effective);
289
- // See keyedArrays.ts: an added item whose id disagrees with the key
290
- // it was sent under is ambiguous, and only this layer can say so.
291
- if (expanded.error) {
292
- return {
293
- ok: false,
294
- error: `Refused: ${expanded.error}`
295
- };
296
- }
297
- effective = expanded.patch;
298
- keyedNotes = expanded.notes;
299
- }
300
- // The guard builds its template from `list[0]`, so a list that is EMPTY
301
- // has no template and an added item is written with nothing to check it
302
- // against. That is not a rare corner: it is every "add the first thing"
303
- // flow, and it is where models invent shapes, because on an empty list
304
- // the item shape genuinely exists nowhere in the running app. We cannot
305
- // refuse it — refusing would break adding the first item to anything —
306
- // so we say so instead of letting the guess through unremarked.
307
- if (current !== undefined) {
308
- unchecked = (0, _sharedUi.unshapedLists)(current).filter(path => touchesList(effective, path));
309
- }
310
- if (current !== undefined) {
311
- const violations = (0, _sharedUi.typedEditViolations)(current, effective, {
312
- noun: "store"
313
- });
314
- if (violations.length > 0) {
315
- return {
316
- ok: false,
317
- error: (0, _sharedUi.refusalText)(violations, "store", (0, _sharedUi.suggestedPatch)(effective, violations)),
318
- ...((0, _sharedUi.suggestedPatch)(effective, violations) ? {
319
- suggestedState: (0, _sharedUi.suggestedPatch)(effective, violations)
320
- } : {}),
321
- violations
322
- };
323
- }
324
- }
325
- }
326
- // A pathed write is a merge by construction — it names one value, so it
327
- // must never fall through to zustand's default whole-state replace.
328
- const merging = pathed || replace === false;
329
- if (merging) {
330
- // zustand's own merge is shallow: `setState({ member: { crowns } }, false)`
331
- // swaps the whole `member` object for `{ crowns }`. A path write always
332
- // arrives in that nested form, and so does any merge that edits inside a
333
- // top-level object, so fold each nested object into what the store holds
334
- // now before handing it over. Arrays still replace (keyed edits were
335
- // already expanded to whole arrays above).
336
- let current;
337
- try {
338
- current = store.api.getState();
339
- } catch {
340
- current = undefined;
341
- }
342
- if (isPlainRecord(current) && isPlainRecord(effective)) {
343
- const folded = {};
344
- for (const [k, v] of Object.entries(effective)) folded[k] = k in current ? deepMergeInto(current[k], v) : v;
345
- effective = folded;
346
- }
347
- }
348
- store.api.setState(effective, merging ? false : replace ?? true);
349
- // Say what an addressed edit resolved to. A caller that meant to change one
350
- // line and sees "17 item(s) remain" has caught its own mistake.
351
- return {
352
- ok: true,
353
- ...(path !== undefined ? {
354
- path
355
- } : {}),
356
- ...(keyedNotes.length ? {
357
- keyed: keyedNotes
358
- } : {}),
359
- ...(unchecked.length ? {
360
- unchecked: unchecked.map(path => `\`${path}\` was empty, so nothing in the app knows what its items look like and the shape of what you added was NOT checked. If the app renders a field you left out, it will render undefined — read the store back and compare against how the screen uses it.`)
361
- } : {})
362
- };
363
- },
364
- /**
365
- * Re-read a persisted store's saved value and merge it into the live store.
366
- *
367
- * This is what makes editing a store's storage key mean anything. The app
368
- * reads that key once at startup and then holds the state in memory, so an
369
- * outside write — the Storage tool, a scenario, an agent — changes the disk
370
- * and nothing else, and the next time the store saves it writes its own
371
- * copy straight back over the edit.
372
- *
373
- * `persist.rehydrate()` is plain zustand, not a devtools hook, so unlike
374
- * reloading the app this also works in a release build. It merges the saved
375
- * value OVER current state (zustand's default merge is
376
- * `{...current, ...persisted}`), so the store's action functions survive,
377
- * and it does not write back to storage unless a version migration ran —
378
- * the edit stays exactly as it was typed.
379
- *
380
- * Two honest limits, both inherent to persist rather than to this action:
381
- * a key the store's `partialize` excludes is not in the saved value and so
382
- * cannot be applied, and because the merge is shallow, DELETING a top-level
383
- * key from the saved JSON does not remove it from the live store.
384
- */
385
- rehydrate: async params => {
386
- const {
387
- storeName
388
- } = (0, _sharedUi.readParams)(params);
389
- if (!storeName) return {
390
- ok: false,
391
- error: "Missing storeName."
392
- };
393
- const store = _zustandStateStore.zustandStateStore.getStore(storeName);
394
- if (!store) return {
395
- ok: false,
396
- error: `No store named "${storeName}".`
397
- };
398
- if (!store.isPersisted) {
399
- return {
400
- ok: false,
401
- error: `"${storeName}" is not a persisted store — it has no saved copy to re-read.`
402
- };
403
- }
404
- if (!store.rehydrate) {
405
- return {
406
- ok: false,
407
- error: `"${storeName}" is persisted but Buoy has no rehydrate handle for it. It was probably registered before the app's persist middleware attached.`
408
- };
409
- }
410
- await store.rehydrate();
411
- return {
412
- ok: true,
413
- storeName,
414
- persistName: store.persistName
415
- };
416
- }
417
- }
418
- });
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:true});exports.zustandSyncAdapter=exports.STATE_ON_DEVICE=exports.PAYLOAD_ON_DEVICE=void 0;var _sharedUi=require("@buoy-gg/shared-ui");var _zustandStateStore=require("../utils/zustandStateStore");const isPlainRecord=e=>typeof e==="object"&&e!==null&&!Array.isArray(e)&&Object.getPrototypeOf(e)===Object.prototype;function deepMergeInto(e,r){if(!isPlainRecord(e)||!isPlainRecord(r))return r;const t={...e};for(const[s,i]of Object.entries(r))t[s]=s in e?deepMergeInto(e[s],i):i;return t}const STATE_ON_DEVICE=exports.STATE_ON_DEVICE=(0,_sharedUi.onDeviceMarker)("State","State trees stay on the device \u2014 fetched on demand via getChangeDetail / getStoreState.");const PAYLOAD_ON_DEVICE=exports.PAYLOAD_ON_DEVICE=(0,_sharedUi.onDeviceMarker)("Payload","Partial stays on the device \u2014 fetched on demand via getChangeDetail.");const isPlainObject=e=>!!e&&typeof e==="object"&&!Array.isArray(e);function touchesList(e,r){let t=e;for(const s of r.split(".")){if(!t||typeof t!=="object"||Array.isArray(t))return false;if(!(s in t))return false;t=t[s]}return Array.isArray(t)?t.length>0:!!t&&typeof t==="object"}function topLevelKeys(e){return e&&typeof e==="object"&&!Array.isArray(e)?Object.keys(e):void 0}const toWireChange=(0,_sharedUi.memoByIdentity)(e=>({...e,prevState:STATE_ON_DEVICE,nextState:STATE_ON_DEVICE,partial:(0,_sharedUi.toWire)(e.partial,PAYLOAD_ON_DEVICE)}));const toWireState=e=>(0,_sharedUi.toWire)(e,STATE_ON_DEVICE);const zustandSyncAdapter=exports.zustandSyncAdapter=(0,_sharedUi.createSyncAdapter)({version:2,getSnapshot:()=>({changes:_zustandStateStore.zustandStateStore.getStateChanges().map(toWireChange),stores:_zustandStateStore.zustandStateStore.getStoreSnapshots().map(e=>({...e,currentState:toWireState(e.currentState)}))}),subscribe:[e=>_zustandStateStore.zustandStateStore.subscribe(e),e=>_zustandStateStore.zustandStateStore.subscribeToStores(e)],actions:{clearEvents:()=>{_zustandStateStore.zustandStateStore.clearStateChanges()},getChangeDetail:(0,_sharedUi.detailByIdAction)(e=>_zustandStateStore.zustandStateStore.getStateChangeById(e),(e,r)=>({prevState:r(e.prevState),nextState:r(e.nextState),partial:r(e.partial)})),getStoreState:e=>{const{storeName:r,path:t}=(0,_sharedUi.readParams)(e);if(!r)return{found:false,reason:"missing storeName"};const s=_zustandStateStore.zustandStateStore.getStore(r);if(!s)return{found:false,reason:"unknown storeName"};let i;try{i=s.api.getState()}catch{i=void 0}if(t){const o=(0,_sharedUi.readPath)(i,t);if(!o.ok)return{found:false,reason:o.error};return{found:true,storeName:r,path:t,shape:(0,_sharedUi.shapeSummary)(o.value),currentState:o.value}}const d=(0,_sharedUi.shapeSummary)(i);if(!(0,_sharedUi.isOverWireBudget)(i,_sharedUi.WIRE_DETAIL_LIMIT_BYTES)){return{found:true,storeName:r,...d?{shape:d}:{},currentState:i}}return{found:true,storeName:r,...d?{shape:d}:{},currentState:(0,_sharedUi.isJsonSerializable)(i)?(0,_sharedUi.truncatedNote)(_sharedUi.WIRE_DETAIL_LIMIT_BYTES):STATE_ON_DEVICE}},listStores:e=>{const{includeValues:r=false,limit:t}=(0,_sharedUi.readParams)(e);const s=_zustandStateStore.zustandStateStore.getStoreSnapshots();const i=typeof t==="number"&&t>0?s.slice(0,t):s;const d=i.map(o=>({name:o.name,changes:o.stateChangeCount,isPersisted:o.isPersisted,persistName:o.persistName,canRehydrate:o.canRehydrate,...r?{currentState:o.currentState}:{keys:topLevelKeys(o.currentState)},...(0,_sharedUi.shapeSummary)(o.currentState)?{shape:(0,_sharedUi.shapeSummary)(o.currentState)}:{}}));return{stores:d,total:s.length,returned:d.length,includedValues:r}},setState:e=>{const{storeName:r,state:t,replace:s,force:i,path:d,value:o}=(0,_sharedUi.readParams)(e);let u=t;let f=[];let l=[];if(!r)return{ok:false,error:"Missing storeName."};const c=_zustandStateStore.zustandStateStore.getStore(r);if(!c)return{ok:false,error:`No store named "${r}".`};if(t===void 0&&d===void 0){return{ok:false,error:`Refused: no change was described. Send \`state\` with the fields to merge, or \`path\` and \`value\` to set one value.`}}let S=false;if(d!==void 0){if(o===void 0){return{ok:false,error:`Refused: sent \`path\` without \`value\`. Say what to set "${d}" to; if you mean to clear it, send value:null and the field must already be nullable.`}}let a;try{a=c.api.getState()}catch{a=void 0}const n=(0,_sharedUi.patchFromPath)(a,d,o);if(!n.ok)return{ok:false,error:`Refused: ${n.error}`};u=n.patch;S=true}if(!i&&(s===false||S)){let a;try{a=c.api.getState()}catch{a=void 0}if(a!==void 0){const n=(0,_sharedUi.expandKeyedArrays)(a,u);if(n.error){return{ok:false,error:`Refused: ${n.error}`}}u=n.patch;f=n.notes}if(a!==void 0){l=(0,_sharedUi.unshapedLists)(a).filter(n=>touchesList(u,n))}if(a!==void 0){const n=(0,_sharedUi.typedEditViolations)(a,u,{noun:"store"});if(n.length>0){return{ok:false,error:(0,_sharedUi.refusalText)(n,"store",(0,_sharedUi.suggestedPatch)(u,n)),...(0,_sharedUi.suggestedPatch)(u,n)?{suggestedState:(0,_sharedUi.suggestedPatch)(u,n)}:{},violations:n}}}}const h=S||s===false;if(h){let a;try{a=c.api.getState()}catch{a=void 0}if(isPlainRecord(a)&&isPlainRecord(u)){const n={};for(const[p,y]of Object.entries(u))n[p]=p in a?deepMergeInto(a[p],y):y;u=n}}c.api.setState(u,h?false:s??true);return{ok:true,...d!==void 0?{path:d}:{},...f.length?{keyed:f}:{},...l.length?{unchecked:l.map(a=>`\`${a}\` was empty, so nothing in the app knows what its items look like and the shape of what you added was NOT checked. If the app renders a field you left out, it will render undefined \u2014 read the store back and compare against how the screen uses it.`)}:{}}},rehydrate:async e=>{const{storeName:r}=(0,_sharedUi.readParams)(e);if(!r)return{ok:false,error:"Missing storeName."};const t=_zustandStateStore.zustandStateStore.getStore(r);if(!t)return{ok:false,error:`No store named "${r}".`};if(!t.isPersisted){return{ok:false,error:`"${r}" is not a persisted store \u2014 it has no saved copy to re-read.`}}if(!t.rehydrate){return{ok:false,error:`"${r}" is persisted but Buoy has no rehydrate handle for it. It was probably registered before the app's persist middleware attached.`}}await t.rehydrate();return{ok:true,storeName:r,persistName:t.persistName}}}});
@@ -1 +1 @@
1
- "use strict";
1
+ "use strict";