fusee-framework 2.7.0 → 2.7.1

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 (61) hide show
  1. package/README.md +56 -2
  2. package/bin/create-fusee-linux +0 -0
  3. package/bin/create-fusee-mac-arm64 +0 -0
  4. package/bin/create-fusee-mac-intel +0 -0
  5. package/bin/create-fusee-win.exe +0 -0
  6. package/framework/auto-import-preset.js +20 -12
  7. package/framework/auto-imports.d.ts +68 -39
  8. package/framework/core/compiler.js +310 -310
  9. package/framework/core/component-core.js +445 -0
  10. package/framework/core/component.js +11 -440
  11. package/framework/core/composable.js +29 -29
  12. package/framework/core/h.js +588 -557
  13. package/framework/core/jsx-helpers.js +11 -2
  14. package/framework/core/jsx-runtime.js +73 -73
  15. package/framework/core/rust-compiler/pkg/fusee_compiler_bg.wasm +0 -0
  16. package/framework/core/store.js +333 -333
  17. package/framework/globals.js +42 -0
  18. package/framework/index.js +22 -55
  19. package/framework/router/file-router.js +184 -184
  20. package/framework/server/actions.js +183 -183
  21. package/framework/server/generate-manifest.js +3 -3
  22. package/framework/types/component.d.ts +97 -86
  23. package/framework/types/index.d.ts +118 -117
  24. package/package.json +83 -80
  25. package/framework/core/rust-compiler/Cargo.toml +0 -31
  26. package/framework/core/rust-compiler/README.md +0 -69
  27. package/framework/core/rust-compiler/pkg/README.md +0 -69
  28. package/framework/core/rust-compiler/pkg/fusee_compiler.d.ts +0 -6
  29. package/framework/core/rust-compiler/pkg/fusee_compiler.js +0 -9
  30. package/framework/core/rust-compiler/pkg/fusee_compiler_bg.js +0 -137
  31. package/framework/core/rust-compiler/pkg/fusee_compiler_bg.wasm.d.ts +0 -11
  32. package/framework/core/rust-compiler/pkg/package.json +0 -18
  33. package/framework/core/rust-compiler/src/ast.rs +0 -274
  34. package/framework/core/rust-compiler/src/errors.rs +0 -204
  35. package/framework/core/rust-compiler/src/generator.rs +0 -583
  36. package/framework/core/rust-compiler/src/lexer.rs +0 -414
  37. package/framework/core/rust-compiler/src/lib.rs +0 -87
  38. package/framework/core/rust-compiler/src/main_compiler.rs +0 -165
  39. package/framework/core/rust-compiler/src/parser.rs +0 -516
  40. package/framework/core/rust-compiler/src/ssr_generator.rs +0 -688
  41. package/framework/core/rust-compiler/src/transformer.rs +0 -562
  42. package/framework/core/rust-compiler/src/utils.rs +0 -10
  43. package/framework/engine-go/actions.go +0 -112
  44. package/framework/engine-go/cmd/server/main.go +0 -233
  45. package/framework/engine-go/comet/comet.go +0 -41
  46. package/framework/engine-go/comet/fragment.go +0 -51
  47. package/framework/engine-go/dispatcher.go +0 -120
  48. package/framework/engine-go/elements.go +0 -248
  49. package/framework/engine-go/evalexpr/evalexpr.go +0 -733
  50. package/framework/engine-go/go.mod +0 -3
  51. package/framework/engine-go/hydration.go +0 -43
  52. package/framework/engine-go/load-helpers.go +0 -29
  53. package/framework/engine-go/manifest.go +0 -41
  54. package/framework/engine-go/reactive.go +0 -123
  55. package/framework/engine-go/render.go +0 -635
  56. package/framework/engine-go/reqcontext.go +0 -48
  57. package/framework/engine-go/router.go +0 -85
  58. package/framework/engine-go/rustast/rustast.go +0 -317
  59. package/framework/engine-go/ssr.go +0 -103
  60. package/framework/engine-go/static-assets.go +0 -139
  61. package/framework/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +0 -1
@@ -1,333 +1,333 @@
1
- import { getCurrentInstance, setCurrentInstance } from './component.js'
2
- import { batch, effect } from './signal.js'
3
-
4
-
5
- const storesRegistry = new Map()
6
- const storePlugins = []
7
- const initializationStack = new Set()
8
-
9
- export const MutationType = {
10
- DIRECT: 'direct',
11
- PATCH_OBJECT: 'patch object',
12
- PATCH_FUNCTION: 'patch function'
13
- }
14
-
15
- /** Registers a plugin that receives each newly initialized store. */
16
- export function registerStorePlugin(plugin) {
17
- if (typeof plugin === 'function') {
18
- storePlugins.push(plugin)
19
- }
20
- }
21
-
22
- /** Resolves a nested store hook while detecting circular initialization. */
23
- export function useNestedStore(useStoreFn) {
24
- if (typeof useStoreFn !== 'function' || !useStoreFn.$id) {
25
- console.error('[framework] useNestedStore requires a valid store hook (defineStore result)')
26
- throw new Error('Invalid store hook provided to useNestedStore')
27
- }
28
-
29
- const targetId = useStoreFn.$id
30
-
31
- if (initializationStack.has(targetId)) {
32
- const chain = Array.from(initializationStack).concat(targetId).join(' -> ')
33
- console.error(`[framework] Circular dependency detected: ${chain}`)
34
- throw new Error(`Circular store dependency detected: ${chain}`)
35
- }
36
-
37
- return useStoreFn()
38
- }
39
-
40
- const isDev = typeof import.meta.env !== 'undefined' ? !!import.meta.env.DEV : true
41
- if (isDev && typeof window !== 'undefined') {
42
- window.__FRAMEWORK_STORES__ = storesRegistry
43
- }
44
-
45
- export function defineStore(id, setup) {
46
- if (typeof id !== 'string' || !id.trim()) {
47
- console.error('[framework] defineStore requires a valid string ID.')
48
- }
49
-
50
- /** Creates the store once, then returns the cached store instance. */
51
- function useStore() {
52
- let store = storesRegistry.get(id)
53
-
54
- if (!store) {
55
- const prevInstance = getCurrentInstance()
56
-
57
- setCurrentInstance(null)
58
- initializationStack.add(id)
59
-
60
- try {
61
- store = setup()
62
-
63
- if (store instanceof Promise) {
64
- console.error(`[framework] Store "${id}" cannot be async.`)
65
- throw new Error(`Async store "${id}" is not supported.`)
66
- }
67
-
68
- } catch (err) {
69
- console.error(`[framework] Error initializing store "${id}":`, err)
70
- throw err
71
- } finally {
72
- initializationStack.delete(id)
73
- setCurrentInstance(prevInstance)
74
- }
75
-
76
- const initialState = {}
77
- const signalKeys = []
78
- const getterKeys = []
79
- for (const key in store) {
80
- if (typeof store[key] === 'function' && store[key].isSignal) {
81
- if (store[key].readonly) {
82
- getterKeys.push(key)
83
- } else {
84
- initialState[key] = store[key]()
85
- signalKeys.push(key)
86
- }
87
- }
88
- }
89
-
90
- // Subscription management
91
- const subscriptions = new Map()
92
- let subscriptionId = 0
93
- let currentMutation = null
94
-
95
- /** Publishes the pending mutation to synchronous and queued subscribers. */
96
- function notifySubscribers() {
97
- if (!currentMutation) return
98
- const mutation = currentMutation
99
- currentMutation = null
100
-
101
- const state = {}
102
- for (const key of signalKeys) {
103
- state[key] = store[key]()
104
- }
105
-
106
- for (const [subId, sub] of subscriptions) {
107
- if (sub.flush === 'sync') {
108
- sub.callback(mutation, state)
109
- } else {
110
- // Default: post (after all batched updates)
111
- queueMicrotask(() => {
112
- if (subscriptions.has(subId)) {
113
- sub.callback(mutation, state)
114
- }
115
- })
116
- }
117
- }
118
- }
119
-
120
- /** Wraps a writable signal so direct writes produce store mutations. */
121
- function wrapSignal(key, originalSignal) {
122
- const wrapped = function(newValue) {
123
- if (arguments.length === 0) {
124
- return originalSignal()
125
- } else {
126
- const result = originalSignal(newValue)
127
- if (!currentMutation) {
128
- currentMutation = {
129
- type: MutationType.DIRECT,
130
- storeId: id,
131
- payload: { [key]: newValue }
132
- }
133
- notifySubscribers()
134
- }
135
- return result
136
- }
137
- }
138
- wrapped.isSignal = true
139
- for (const method of ['map', 'filter', 'slice', 'concat', 'flat', 'flatMap',
140
- 'find', 'findLast', 'findIndex', 'findLastIndex',
141
- 'indexOf', 'lastIndexOf', 'includes', 'every', 'some',
142
- 'reduce', 'at', 'join', 'push', 'pop', 'shift', 'unshift',
143
- 'splice', 'remove', 'clear', 'sort', 'reverse']) {
144
- if (originalSignal[method]) {
145
- wrapped[method] = originalSignal[method]
146
- }
147
- }
148
- return wrapped
149
- }
150
-
151
- /** Wraps a computed signal as a read-only store getter. */
152
- function wrapGetter(key, originalGetter) {
153
- const wrapped = function(newValue) {
154
- if (arguments.length === 0) {
155
- return originalGetter()
156
- } else {
157
- console.warn(`[framework] Getter "${key}" is read-only`)
158
- return originalGetter()
159
- }
160
- }
161
- wrapped.isSignal = true
162
- wrapped.readonly = true
163
- for (const method of ['map', 'filter', 'slice', 'concat', 'flat', 'flatMap',
164
- 'find', 'findLast', 'findIndex', 'findLastIndex',
165
- 'indexOf', 'lastIndexOf', 'includes', 'every', 'some',
166
- 'reduce', 'at', 'join']) {
167
- if (originalGetter[method]) {
168
- wrapped[method] = originalGetter[method]
169
- }
170
- }
171
- return wrapped
172
- }
173
-
174
- const wrappedSignals = {}
175
- for (const key of signalKeys) {
176
- wrappedSignals[key] = wrapSignal(key, store[key])
177
- store[key] = wrappedSignals[key]
178
- }
179
-
180
- for (const key of getterKeys) {
181
- store[key] = wrapGetter(key, store[key])
182
- }
183
-
184
- Object.defineProperties(store, {
185
- id: {
186
- value: id,
187
- enumerable: false
188
- },
189
- type: {
190
- value: 'store',
191
- enumerable: false
192
- },
193
- patch: {
194
- value: (arg) => {
195
- const isObjectPatch = arg && typeof arg === 'object'
196
- currentMutation = {
197
- type: isObjectPatch ? MutationType.PATCH_OBJECT : MutationType.PATCH_FUNCTION,
198
- storeId: id,
199
- payload: isObjectPatch ? { ...arg } : undefined
200
- }
201
-
202
- batch(() => {
203
- if (typeof arg === 'function') {
204
- arg(store)
205
- } else if (isObjectPatch) {
206
- for (const key in arg) {
207
- if (typeof store[key] === 'function' && store[key].isSignal && !store[key].readonly) {
208
- const originalSignal = wrappedSignals[key]
209
- originalSignal(arg[key])
210
- }
211
- }
212
- }
213
- })
214
-
215
- notifySubscribers()
216
- },
217
- enumerable: false
218
- },
219
- reset: {
220
- value: () => {
221
- currentMutation = {
222
- type: MutationType.PATCH_FUNCTION,
223
- storeId: id,
224
- payload: undefined
225
- }
226
-
227
- batch(() => {
228
- for (const key in initialState) {
229
- const originalSignal = wrappedSignals[key]
230
- originalSignal(initialState[key])
231
- }
232
- })
233
-
234
- notifySubscribers()
235
- },
236
- enumerable: false
237
- },
238
- subscribe: {
239
- value: (callback, options = {}) => {
240
- if (typeof callback !== 'function') {
241
- console.warn('[framework] subscribe callback must be a function')
242
- return () => {}
243
- }
244
-
245
- const subId = ++subscriptionId
246
- const sub = {
247
- callback,
248
- flush: options.flush || 'post',
249
- detached: options.detached || false
250
- }
251
- subscriptions.set(subId, sub)
252
-
253
- if (!sub.detached) {
254
- const instance = getCurrentInstance()
255
- if (instance && instance._unmountHooks) {
256
- instance._unmountHooks.push(() => {
257
- subscriptions.delete(subId)
258
- })
259
- }
260
- }
261
-
262
- return () => {
263
- subscriptions.delete(subId)
264
- }
265
- },
266
- enumerable: false
267
- }
268
- })
269
-
270
- for (const plugin of storePlugins) {
271
- try {
272
- plugin(store, id)
273
- } catch (e) {
274
- console.warn(`[framework] Store plugin error for "${id}":`, e)
275
- }
276
- }
277
-
278
- storesRegistry.set(id, store)
279
- }
280
-
281
- return store
282
- }
283
-
284
- useStore.$id = id
285
-
286
- return useStore
287
- }
288
-
289
- /** Drops one cached store so its setup function runs again on next use. */
290
- export function resetStore(id) {
291
- storesRegistry.delete(id)
292
- }
293
-
294
- /** Removes every registered store instance. */
295
- export function clearStores() {
296
- storesRegistry.clear()
297
- }
298
-
299
- /** Returns all signal-backed properties from a store. */
300
- export function storeToRefs(store) {
301
- const refs = {}
302
- for (const key in store) {
303
- const value = store[key]
304
- if (typeof value === 'function' && value.isSignal) {
305
- refs[key] = value
306
- }
307
- }
308
- return refs
309
- }
310
-
311
- /** Returns only writable signal-backed state from a store. */
312
- export function storeToState(store) {
313
- const state = {}
314
- for (const key in store) {
315
- const value = store[key]
316
- if (typeof value === 'function' && value.isSignal && !value.readonly) {
317
- state[key] = value
318
- }
319
- }
320
- return state
321
- }
322
-
323
- /** Returns only read-only signal-backed getters from a store. */
324
- export function storeToGetters(store) {
325
- const getters = {}
326
- for (const key in store) {
327
- const value = store[key]
328
- if (typeof value === 'function' && value.isSignal && value.readonly) {
329
- getters[key] = value
330
- }
331
- }
332
- return getters
333
- }
1
+ import { getCurrentInstance, setCurrentInstance } from './component-core.js'
2
+ import { batch, effect } from './signal.js'
3
+
4
+
5
+ const storesRegistry = new Map()
6
+ const storePlugins = []
7
+ const initializationStack = new Set()
8
+
9
+ export const MutationType = {
10
+ DIRECT: 'direct',
11
+ PATCH_OBJECT: 'patch object',
12
+ PATCH_FUNCTION: 'patch function'
13
+ }
14
+
15
+ /** Registers a plugin that receives each newly initialized store. */
16
+ export function registerStorePlugin(plugin) {
17
+ if (typeof plugin === 'function') {
18
+ storePlugins.push(plugin)
19
+ }
20
+ }
21
+
22
+ /** Resolves a nested store hook while detecting circular initialization. */
23
+ export function useNestedStore(useStoreFn) {
24
+ if (typeof useStoreFn !== 'function' || !useStoreFn.$id) {
25
+ console.error('[framework] useNestedStore requires a valid store hook (defineStore result)')
26
+ throw new Error('Invalid store hook provided to useNestedStore')
27
+ }
28
+
29
+ const targetId = useStoreFn.$id
30
+
31
+ if (initializationStack.has(targetId)) {
32
+ const chain = Array.from(initializationStack).concat(targetId).join(' -> ')
33
+ console.error(`[framework] Circular dependency detected: ${chain}`)
34
+ throw new Error(`Circular store dependency detected: ${chain}`)
35
+ }
36
+
37
+ return useStoreFn()
38
+ }
39
+
40
+ const isDev = typeof import.meta.env !== 'undefined' ? !!import.meta.env.DEV : true
41
+ if (isDev && typeof window !== 'undefined') {
42
+ window.__FRAMEWORK_STORES__ = storesRegistry
43
+ }
44
+
45
+ export function defineStore(id, setup) {
46
+ if (typeof id !== 'string' || !id.trim()) {
47
+ console.error('[framework] defineStore requires a valid string ID.')
48
+ }
49
+
50
+ /** Creates the store once, then returns the cached store instance. */
51
+ function useStore() {
52
+ let store = storesRegistry.get(id)
53
+
54
+ if (!store) {
55
+ const prevInstance = getCurrentInstance()
56
+
57
+ setCurrentInstance(null)
58
+ initializationStack.add(id)
59
+
60
+ try {
61
+ store = setup()
62
+
63
+ if (store instanceof Promise) {
64
+ console.error(`[framework] Store "${id}" cannot be async.`)
65
+ throw new Error(`Async store "${id}" is not supported.`)
66
+ }
67
+
68
+ } catch (err) {
69
+ console.error(`[framework] Error initializing store "${id}":`, err)
70
+ throw err
71
+ } finally {
72
+ initializationStack.delete(id)
73
+ setCurrentInstance(prevInstance)
74
+ }
75
+
76
+ const initialState = {}
77
+ const signalKeys = []
78
+ const getterKeys = []
79
+ for (const key in store) {
80
+ if (typeof store[key] === 'function' && store[key].isSignal) {
81
+ if (store[key].readonly) {
82
+ getterKeys.push(key)
83
+ } else {
84
+ initialState[key] = store[key]()
85
+ signalKeys.push(key)
86
+ }
87
+ }
88
+ }
89
+
90
+ // Subscription management
91
+ const subscriptions = new Map()
92
+ let subscriptionId = 0
93
+ let currentMutation = null
94
+
95
+ /** Publishes the pending mutation to synchronous and queued subscribers. */
96
+ function notifySubscribers() {
97
+ if (!currentMutation) return
98
+ const mutation = currentMutation
99
+ currentMutation = null
100
+
101
+ const state = {}
102
+ for (const key of signalKeys) {
103
+ state[key] = store[key]()
104
+ }
105
+
106
+ for (const [subId, sub] of subscriptions) {
107
+ if (sub.flush === 'sync') {
108
+ sub.callback(mutation, state)
109
+ } else {
110
+ // Default: post (after all batched updates)
111
+ queueMicrotask(() => {
112
+ if (subscriptions.has(subId)) {
113
+ sub.callback(mutation, state)
114
+ }
115
+ })
116
+ }
117
+ }
118
+ }
119
+
120
+ /** Wraps a writable signal so direct writes produce store mutations. */
121
+ function wrapSignal(key, originalSignal) {
122
+ const wrapped = function(newValue) {
123
+ if (arguments.length === 0) {
124
+ return originalSignal()
125
+ } else {
126
+ const result = originalSignal(newValue)
127
+ if (!currentMutation) {
128
+ currentMutation = {
129
+ type: MutationType.DIRECT,
130
+ storeId: id,
131
+ payload: { [key]: newValue }
132
+ }
133
+ notifySubscribers()
134
+ }
135
+ return result
136
+ }
137
+ }
138
+ wrapped.isSignal = true
139
+ for (const method of ['map', 'filter', 'slice', 'concat', 'flat', 'flatMap',
140
+ 'find', 'findLast', 'findIndex', 'findLastIndex',
141
+ 'indexOf', 'lastIndexOf', 'includes', 'every', 'some',
142
+ 'reduce', 'at', 'join', 'push', 'pop', 'shift', 'unshift',
143
+ 'splice', 'remove', 'clear', 'sort', 'reverse']) {
144
+ if (originalSignal[method]) {
145
+ wrapped[method] = originalSignal[method]
146
+ }
147
+ }
148
+ return wrapped
149
+ }
150
+
151
+ /** Wraps a computed signal as a read-only store getter. */
152
+ function wrapGetter(key, originalGetter) {
153
+ const wrapped = function(newValue) {
154
+ if (arguments.length === 0) {
155
+ return originalGetter()
156
+ } else {
157
+ console.warn(`[framework] Getter "${key}" is read-only`)
158
+ return originalGetter()
159
+ }
160
+ }
161
+ wrapped.isSignal = true
162
+ wrapped.readonly = true
163
+ for (const method of ['map', 'filter', 'slice', 'concat', 'flat', 'flatMap',
164
+ 'find', 'findLast', 'findIndex', 'findLastIndex',
165
+ 'indexOf', 'lastIndexOf', 'includes', 'every', 'some',
166
+ 'reduce', 'at', 'join']) {
167
+ if (originalGetter[method]) {
168
+ wrapped[method] = originalGetter[method]
169
+ }
170
+ }
171
+ return wrapped
172
+ }
173
+
174
+ const wrappedSignals = {}
175
+ for (const key of signalKeys) {
176
+ wrappedSignals[key] = wrapSignal(key, store[key])
177
+ store[key] = wrappedSignals[key]
178
+ }
179
+
180
+ for (const key of getterKeys) {
181
+ store[key] = wrapGetter(key, store[key])
182
+ }
183
+
184
+ Object.defineProperties(store, {
185
+ id: {
186
+ value: id,
187
+ enumerable: false
188
+ },
189
+ type: {
190
+ value: 'store',
191
+ enumerable: false
192
+ },
193
+ patch: {
194
+ value: (arg) => {
195
+ const isObjectPatch = arg && typeof arg === 'object'
196
+ currentMutation = {
197
+ type: isObjectPatch ? MutationType.PATCH_OBJECT : MutationType.PATCH_FUNCTION,
198
+ storeId: id,
199
+ payload: isObjectPatch ? { ...arg } : undefined
200
+ }
201
+
202
+ batch(() => {
203
+ if (typeof arg === 'function') {
204
+ arg(store)
205
+ } else if (isObjectPatch) {
206
+ for (const key in arg) {
207
+ if (typeof store[key] === 'function' && store[key].isSignal && !store[key].readonly) {
208
+ const originalSignal = wrappedSignals[key]
209
+ originalSignal(arg[key])
210
+ }
211
+ }
212
+ }
213
+ })
214
+
215
+ notifySubscribers()
216
+ },
217
+ enumerable: false
218
+ },
219
+ reset: {
220
+ value: () => {
221
+ currentMutation = {
222
+ type: MutationType.PATCH_FUNCTION,
223
+ storeId: id,
224
+ payload: undefined
225
+ }
226
+
227
+ batch(() => {
228
+ for (const key in initialState) {
229
+ const originalSignal = wrappedSignals[key]
230
+ originalSignal(initialState[key])
231
+ }
232
+ })
233
+
234
+ notifySubscribers()
235
+ },
236
+ enumerable: false
237
+ },
238
+ subscribe: {
239
+ value: (callback, options = {}) => {
240
+ if (typeof callback !== 'function') {
241
+ console.warn('[framework] subscribe callback must be a function')
242
+ return () => {}
243
+ }
244
+
245
+ const subId = ++subscriptionId
246
+ const sub = {
247
+ callback,
248
+ flush: options.flush || 'post',
249
+ detached: options.detached || false
250
+ }
251
+ subscriptions.set(subId, sub)
252
+
253
+ if (!sub.detached) {
254
+ const instance = getCurrentInstance()
255
+ if (instance && instance._unmountHooks) {
256
+ instance._unmountHooks.push(() => {
257
+ subscriptions.delete(subId)
258
+ })
259
+ }
260
+ }
261
+
262
+ return () => {
263
+ subscriptions.delete(subId)
264
+ }
265
+ },
266
+ enumerable: false
267
+ }
268
+ })
269
+
270
+ for (const plugin of storePlugins) {
271
+ try {
272
+ plugin(store, id)
273
+ } catch (e) {
274
+ console.warn(`[framework] Store plugin error for "${id}":`, e)
275
+ }
276
+ }
277
+
278
+ storesRegistry.set(id, store)
279
+ }
280
+
281
+ return store
282
+ }
283
+
284
+ useStore.$id = id
285
+
286
+ return useStore
287
+ }
288
+
289
+ /** Drops one cached store so its setup function runs again on next use. */
290
+ export function resetStore(id) {
291
+ storesRegistry.delete(id)
292
+ }
293
+
294
+ /** Removes every registered store instance. */
295
+ export function clearStores() {
296
+ storesRegistry.clear()
297
+ }
298
+
299
+ /** Returns all signal-backed properties from a store. */
300
+ export function storeToRefs(store) {
301
+ const refs = {}
302
+ for (const key in store) {
303
+ const value = store[key]
304
+ if (typeof value === 'function' && value.isSignal) {
305
+ refs[key] = value
306
+ }
307
+ }
308
+ return refs
309
+ }
310
+
311
+ /** Returns only writable signal-backed state from a store. */
312
+ export function storeToState(store) {
313
+ const state = {}
314
+ for (const key in store) {
315
+ const value = store[key]
316
+ if (typeof value === 'function' && value.isSignal && !value.readonly) {
317
+ state[key] = value
318
+ }
319
+ }
320
+ return state
321
+ }
322
+
323
+ /** Returns only read-only signal-backed getters from a store. */
324
+ export function storeToGetters(store) {
325
+ const getters = {}
326
+ for (const key in store) {
327
+ const value = store[key]
328
+ if (typeof value === 'function' && value.isSignal && value.readonly) {
329
+ getters[key] = value
330
+ }
331
+ }
332
+ return getters
333
+ }