@pyreon/storage 0.11.5 → 0.11.7

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.
@@ -1,7 +1,7 @@
1
- import { afterEach, beforeEach, describe, expect, it } from "vitest"
2
- import { _resetDBCache, _resetRegistry, useIndexedDB } from "../index"
1
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest'
2
+ import { _resetDBCache, _resetRegistry, useIndexedDB } from '../index'
3
3
 
4
- describe("useIndexedDB", () => {
4
+ describe('useIndexedDB', () => {
5
5
  beforeEach(() => {
6
6
  _resetRegistry()
7
7
  _resetDBCache()
@@ -12,63 +12,63 @@ describe("useIndexedDB", () => {
12
12
  _resetDBCache()
13
13
  })
14
14
 
15
- it("returns default value initially", () => {
16
- const draft = useIndexedDB("draft", { title: "", body: "" })
15
+ it('returns default value initially', () => {
16
+ const draft = useIndexedDB('draft', { title: '', body: '' })
17
17
  // Initially returns default (IDB load is async)
18
- expect(draft()).toEqual({ title: "", body: "" })
18
+ expect(draft()).toEqual({ title: '', body: '' })
19
19
  })
20
20
 
21
- it(".set() updates signal immediately", () => {
22
- const draft = useIndexedDB("draft", { title: "", body: "" })
23
- draft.set({ title: "Hello", body: "World" })
24
- expect(draft()).toEqual({ title: "Hello", body: "World" })
21
+ it('.set() updates signal immediately', () => {
22
+ const draft = useIndexedDB('draft', { title: '', body: '' })
23
+ draft.set({ title: 'Hello', body: 'World' })
24
+ expect(draft()).toEqual({ title: 'Hello', body: 'World' })
25
25
  })
26
26
 
27
- it(".update() updates signal", () => {
28
- const count = useIndexedDB("count", 0)
27
+ it('.update() updates signal', () => {
28
+ const count = useIndexedDB('count', 0)
29
29
  count.update((n) => n + 1)
30
30
  expect(count()).toBe(1)
31
31
  })
32
32
 
33
- it(".peek() reads without subscribing", () => {
34
- const draft = useIndexedDB("draft", "default")
35
- expect(draft.peek()).toBe("default")
33
+ it('.peek() reads without subscribing', () => {
34
+ const draft = useIndexedDB('draft', 'default')
35
+ expect(draft.peek()).toBe('default')
36
36
  })
37
37
 
38
- it(".remove() resets to default", () => {
39
- const draft = useIndexedDB("draft", "default")
40
- draft.set("modified")
38
+ it('.remove() resets to default', () => {
39
+ const draft = useIndexedDB('draft', 'default')
40
+ draft.set('modified')
41
41
  draft.remove()
42
- expect(draft()).toBe("default")
42
+ expect(draft()).toBe('default')
43
43
  })
44
44
 
45
- it("returns same signal for same key", () => {
46
- const a = useIndexedDB("key", "value")
47
- const b = useIndexedDB("key", "value")
45
+ it('returns same signal for same key', () => {
46
+ const a = useIndexedDB('key', 'value')
47
+ const b = useIndexedDB('key', 'value')
48
48
  expect(a).toBe(b)
49
49
  })
50
50
 
51
- it("returns different signals for different keys", () => {
52
- const a = useIndexedDB("key1", "a")
53
- const b = useIndexedDB("key2", "b")
51
+ it('returns different signals for different keys', () => {
52
+ const a = useIndexedDB('key1', 'a')
53
+ const b = useIndexedDB('key2', 'b')
54
54
  expect(a).not.toBe(b)
55
55
  })
56
56
 
57
- it(".debug() returns debug info", () => {
58
- const draft = useIndexedDB("draft", "test")
59
- expect(draft.debug().value).toBe("test")
57
+ it('.debug() returns debug info', () => {
58
+ const draft = useIndexedDB('draft', 'test')
59
+ expect(draft.debug().value).toBe('test')
60
60
  })
61
61
 
62
- it(".label can be set", () => {
63
- const draft = useIndexedDB("draft", "")
64
- draft.label = "draft-signal"
65
- expect(draft.label).toBe("draft-signal")
62
+ it('.label can be set', () => {
63
+ const draft = useIndexedDB('draft', '')
64
+ draft.label = 'draft-signal'
65
+ expect(draft.label).toBe('draft-signal')
66
66
  })
67
67
 
68
- it("set updates signal synchronously even though IDB write is async", () => {
69
- const draft = useIndexedDB("sync-test", "default", { debounceMs: 10 })
70
- draft.set("immediate")
68
+ it('set updates signal synchronously even though IDB write is async', () => {
69
+ const draft = useIndexedDB('sync-test', 'default', { debounceMs: 10 })
70
+ draft.set('immediate')
71
71
  // Signal updates immediately — no need to wait for IDB
72
- expect(draft()).toBe("immediate")
72
+ expect(draft()).toBe('immediate')
73
73
  })
74
74
  })
@@ -1,8 +1,8 @@
1
- import { effect } from "@pyreon/reactivity"
2
- import { afterEach, beforeEach, describe, expect, it } from "vitest"
3
- import { _resetRegistry, useStorage } from "../index"
1
+ import { effect } from '@pyreon/reactivity'
2
+ import { afterEach, beforeEach, describe, expect, it } from 'vitest'
3
+ import { _resetRegistry, useStorage } from '../index'
4
4
 
5
- describe("useStorage (localStorage)", () => {
5
+ describe('useStorage (localStorage)', () => {
6
6
  beforeEach(() => {
7
7
  localStorage.clear()
8
8
  _resetRegistry()
@@ -13,203 +13,203 @@ describe("useStorage (localStorage)", () => {
13
13
  _resetRegistry()
14
14
  })
15
15
 
16
- it("returns default value when key is not in storage", () => {
17
- const theme = useStorage("theme", "light")
18
- expect(theme()).toBe("light")
16
+ it('returns default value when key is not in storage', () => {
17
+ const theme = useStorage('theme', 'light')
18
+ expect(theme()).toBe('light')
19
19
  })
20
20
 
21
- it("reads existing value from localStorage", () => {
22
- localStorage.setItem("theme", JSON.stringify("dark"))
23
- const theme = useStorage("theme", "light")
24
- expect(theme()).toBe("dark")
21
+ it('reads existing value from localStorage', () => {
22
+ localStorage.setItem('theme', JSON.stringify('dark'))
23
+ const theme = useStorage('theme', 'light')
24
+ expect(theme()).toBe('dark')
25
25
  })
26
26
 
27
- it(".set() updates signal and localStorage", () => {
28
- const theme = useStorage("theme", "light")
29
- theme.set("dark")
30
- expect(theme()).toBe("dark")
31
- expect(JSON.parse(localStorage.getItem("theme")!)).toBe("dark")
27
+ it('.set() updates signal and localStorage', () => {
28
+ const theme = useStorage('theme', 'light')
29
+ theme.set('dark')
30
+ expect(theme()).toBe('dark')
31
+ expect(JSON.parse(localStorage.getItem('theme')!)).toBe('dark')
32
32
  })
33
33
 
34
- it(".update() updates signal and localStorage", () => {
35
- const count = useStorage("count", 0)
34
+ it('.update() updates signal and localStorage', () => {
35
+ const count = useStorage('count', 0)
36
36
  count.update((n) => n + 1)
37
37
  expect(count()).toBe(1)
38
- expect(JSON.parse(localStorage.getItem("count")!)).toBe(1)
38
+ expect(JSON.parse(localStorage.getItem('count')!)).toBe(1)
39
39
  })
40
40
 
41
- it(".peek() reads without subscribing", () => {
42
- const theme = useStorage("theme", "light")
43
- expect(theme.peek()).toBe("light")
41
+ it('.peek() reads without subscribing', () => {
42
+ const theme = useStorage('theme', 'light')
43
+ expect(theme.peek()).toBe('light')
44
44
  })
45
45
 
46
- it(".remove() clears from storage and resets to default", () => {
47
- const theme = useStorage("theme", "light")
48
- theme.set("dark")
49
- expect(theme()).toBe("dark")
46
+ it('.remove() clears from storage and resets to default', () => {
47
+ const theme = useStorage('theme', 'light')
48
+ theme.set('dark')
49
+ expect(theme()).toBe('dark')
50
50
 
51
51
  theme.remove()
52
- expect(theme()).toBe("light")
53
- expect(localStorage.getItem("theme")).toBeNull()
52
+ expect(theme()).toBe('light')
53
+ expect(localStorage.getItem('theme')).toBeNull()
54
54
  })
55
55
 
56
- it("returns same signal instance for same key (deduplication)", () => {
57
- const a = useStorage("theme", "light")
58
- const b = useStorage("theme", "light")
56
+ it('returns same signal instance for same key (deduplication)', () => {
57
+ const a = useStorage('theme', 'light')
58
+ const b = useStorage('theme', 'light')
59
59
  expect(a).toBe(b)
60
60
  })
61
61
 
62
- it("returns different signals for different keys", () => {
63
- const a = useStorage("theme", "light")
64
- const b = useStorage("lang", "en")
62
+ it('returns different signals for different keys', () => {
63
+ const a = useStorage('theme', 'light')
64
+ const b = useStorage('lang', 'en')
65
65
  expect(a).not.toBe(b)
66
66
  })
67
67
 
68
- it("works with objects", () => {
69
- const prefs = useStorage("prefs", { sidebar: true, density: "comfortable" })
70
- expect(prefs()).toEqual({ sidebar: true, density: "comfortable" })
68
+ it('works with objects', () => {
69
+ const prefs = useStorage('prefs', { sidebar: true, density: 'comfortable' })
70
+ expect(prefs()).toEqual({ sidebar: true, density: 'comfortable' })
71
71
 
72
- prefs.set({ sidebar: false, density: "compact" })
73
- expect(prefs()).toEqual({ sidebar: false, density: "compact" })
74
- expect(JSON.parse(localStorage.getItem("prefs")!)).toEqual({
72
+ prefs.set({ sidebar: false, density: 'compact' })
73
+ expect(prefs()).toEqual({ sidebar: false, density: 'compact' })
74
+ expect(JSON.parse(localStorage.getItem('prefs')!)).toEqual({
75
75
  sidebar: false,
76
- density: "compact",
76
+ density: 'compact',
77
77
  })
78
78
  })
79
79
 
80
- it("works with arrays", () => {
81
- const items = useStorage("items", [1, 2, 3])
80
+ it('works with arrays', () => {
81
+ const items = useStorage('items', [1, 2, 3])
82
82
  expect(items()).toEqual([1, 2, 3])
83
83
 
84
84
  items.set([4, 5])
85
85
  expect(items()).toEqual([4, 5])
86
86
  })
87
87
 
88
- it("works with booleans", () => {
89
- const flag = useStorage("flag", false)
88
+ it('works with booleans', () => {
89
+ const flag = useStorage('flag', false)
90
90
  flag.set(true)
91
91
  expect(flag()).toBe(true)
92
- expect(JSON.parse(localStorage.getItem("flag")!)).toBe(true)
92
+ expect(JSON.parse(localStorage.getItem('flag')!)).toBe(true)
93
93
  })
94
94
 
95
- it("works with numbers", () => {
96
- const count = useStorage("count", 42)
95
+ it('works with numbers', () => {
96
+ const count = useStorage('count', 42)
97
97
  expect(count()).toBe(42)
98
98
  })
99
99
 
100
- it("handles corrupt storage values gracefully", () => {
101
- localStorage.setItem("broken", "not valid json{{{")
102
- const value = useStorage("broken", "fallback")
103
- expect(value()).toBe("fallback")
100
+ it('handles corrupt storage values gracefully', () => {
101
+ localStorage.setItem('broken', 'not valid json{{{')
102
+ const value = useStorage('broken', 'fallback')
103
+ expect(value()).toBe('fallback')
104
104
  })
105
105
 
106
- it("calls onError when deserialization fails", () => {
107
- localStorage.setItem("broken", "{invalid")
106
+ it('calls onError when deserialization fails', () => {
107
+ localStorage.setItem('broken', '{invalid')
108
108
  const errors: Error[] = []
109
- const value = useStorage("broken", "default", {
109
+ const value = useStorage('broken', 'default', {
110
110
  onError: (e) => {
111
111
  errors.push(e)
112
112
  return undefined
113
113
  },
114
114
  })
115
- expect(value()).toBe("default")
115
+ expect(value()).toBe('default')
116
116
  expect(errors).toHaveLength(1)
117
117
  })
118
118
 
119
- it("onError can return a custom fallback", () => {
120
- localStorage.setItem("broken", "{invalid")
121
- const value = useStorage("broken", "default", {
122
- onError: () => "custom-fallback",
119
+ it('onError can return a custom fallback', () => {
120
+ localStorage.setItem('broken', '{invalid')
121
+ const value = useStorage('broken', 'default', {
122
+ onError: () => 'custom-fallback',
123
123
  })
124
- expect(value()).toBe("custom-fallback")
124
+ expect(value()).toBe('custom-fallback')
125
125
  })
126
126
 
127
- it("custom serializer/deserializer work", () => {
128
- const date = useStorage("date", new Date("2025-01-01"), {
127
+ it('custom serializer/deserializer work', () => {
128
+ const date = useStorage('date', new Date('2025-01-01'), {
129
129
  serializer: (d) => d.toISOString(),
130
130
  deserializer: (s) => new Date(s),
131
131
  })
132
132
 
133
- expect(date()).toEqual(new Date("2025-01-01"))
133
+ expect(date()).toEqual(new Date('2025-01-01'))
134
134
 
135
- const newDate = new Date("2025-06-15")
135
+ const newDate = new Date('2025-06-15')
136
136
  date.set(newDate)
137
- expect(localStorage.getItem("date")).toBe("2025-06-15T00:00:00.000Z")
137
+ expect(localStorage.getItem('date')).toBe('2025-06-15T00:00:00.000Z')
138
138
  })
139
139
 
140
- it("is reactive — works in effects", () => {
141
- const theme = useStorage("theme", "light")
140
+ it('is reactive — works in effects', () => {
141
+ const theme = useStorage('theme', 'light')
142
142
  const values: string[] = []
143
143
 
144
144
  effect(() => {
145
145
  values.push(theme())
146
146
  })
147
147
 
148
- expect(values).toEqual(["light"])
148
+ expect(values).toEqual(['light'])
149
149
 
150
- theme.set("dark")
151
- expect(values).toEqual(["light", "dark"])
150
+ theme.set('dark')
151
+ expect(values).toEqual(['light', 'dark'])
152
152
  })
153
153
 
154
- it(".subscribe() works", () => {
155
- const theme = useStorage("theme", "light")
154
+ it('.subscribe() works', () => {
155
+ const theme = useStorage('theme', 'light')
156
156
  let callCount = 0
157
157
  const unsub = theme.subscribe(() => {
158
158
  callCount++
159
159
  })
160
160
 
161
- theme.set("dark")
161
+ theme.set('dark')
162
162
  expect(callCount).toBeGreaterThanOrEqual(1)
163
163
  unsub()
164
164
  })
165
165
 
166
- it(".debug() returns debug info", () => {
167
- const theme = useStorage("theme", "light")
166
+ it('.debug() returns debug info', () => {
167
+ const theme = useStorage('theme', 'light')
168
168
  const info = theme.debug()
169
- expect(info.value).toBe("light")
169
+ expect(info.value).toBe('light')
170
170
  })
171
171
 
172
- it(".label can be set and read", () => {
173
- const theme = useStorage("theme", "light")
174
- theme.label = "theme-signal"
175
- expect(theme.label).toBe("theme-signal")
172
+ it('.label can be set and read', () => {
173
+ const theme = useStorage('theme', 'light')
174
+ theme.label = 'theme-signal'
175
+ expect(theme.label).toBe('theme-signal')
176
176
  })
177
177
 
178
- it("cross-tab sync via storage event", () => {
179
- const theme = useStorage("theme", "light")
178
+ it('cross-tab sync via storage event', () => {
179
+ const theme = useStorage('theme', 'light')
180
180
 
181
181
  // Simulate storage event from another tab
182
- const event = Object.assign(new Event("storage"), {
183
- key: "theme",
184
- newValue: JSON.stringify("dark"),
182
+ const event = Object.assign(new Event('storage'), {
183
+ key: 'theme',
184
+ newValue: JSON.stringify('dark'),
185
185
  storageArea: localStorage,
186
186
  })
187
187
  window.dispatchEvent(event)
188
188
 
189
- expect(theme()).toBe("dark")
189
+ expect(theme()).toBe('dark')
190
190
  })
191
191
 
192
- it("cross-tab sync with null newValue resets to default", () => {
193
- const theme = useStorage("theme", "light")
194
- theme.set("dark")
192
+ it('cross-tab sync with null newValue resets to default', () => {
193
+ const theme = useStorage('theme', 'light')
194
+ theme.set('dark')
195
195
 
196
- const event = Object.assign(new Event("storage"), {
197
- key: "theme",
196
+ const event = Object.assign(new Event('storage'), {
197
+ key: 'theme',
198
198
  newValue: null,
199
199
  storageArea: localStorage,
200
200
  })
201
201
  window.dispatchEvent(event)
202
202
 
203
- expect(theme()).toBe("light")
203
+ expect(theme()).toBe('light')
204
204
  })
205
205
 
206
- it("after remove(), a new useStorage call creates a fresh signal", () => {
207
- const a = useStorage("temp", "first")
208
- a.set("modified")
206
+ it('after remove(), a new useStorage call creates a fresh signal', () => {
207
+ const a = useStorage('temp', 'first')
208
+ a.set('modified')
209
209
  a.remove()
210
210
 
211
- const b = useStorage("temp", "second")
212
- expect(b()).toBe("second")
211
+ const b = useStorage('temp', 'second')
212
+ expect(b()).toBe('second')
213
213
  expect(a).not.toBe(b)
214
214
  })
215
215
  })