@@ -22,6 +22,7 @@ import {
2222 reloadAll ,
2323 loadAll ,
2424 rebounce ,
25+ getAll ,
2526} from '../utils/index.js' ;
2627import { flagStoreCreated , getStoreTestingMode , logError } from '../config.js' ;
2728
@@ -66,7 +67,9 @@ export const asyncWritable = <S extends Stores, T>(
6667 options : AsyncStoreOptions < T > = { }
6768) : WritableLoadable < T > => {
6869 flagStoreCreated ( ) ;
69- const { reloadable, trackState, initial } = options ;
70+ const { reloadable, initial, debug } = options ;
71+
72+ const debuggy = debug ? console . log : undefined ;
7073
7174 const rebouncedMappingLoad = rebounce ( mappingLoadFunction ) ;
7275
@@ -95,16 +98,22 @@ export const asyncWritable = <S extends Stores, T>(
9598 const mappingLoadThenSet = async ( setStoreValue ) => {
9699 if ( get ( loadState ) . isSettled ) {
97100 setCurrentLoadPromise ( ) ;
101+ debuggy ?.( 'setting RELOADING' ) ;
98102 setState ( 'RELOADING' ) ;
99103 }
100104
101105 try {
102106 const finalValue = await rebouncedMappingLoad ( parentValues ) ;
107+ debuggy ?.( 'setting value' ) ;
103108 setStoreValue ( finalValue ) ;
109+ if ( ! get ( loadState ) . isWriting ) {
110+ debuggy ?.( 'setting LOADED' ) ;
111+ setState ( 'LOADED' ) ;
112+ }
104113 resolveCurrentLoad ( finalValue ) ;
105- setState ( 'LOADED' ) ;
106114 } catch ( e ) {
107115 if ( e . name !== 'AbortError' ) {
116+ logError ( e ) ;
108117 setState ( 'ERROR' ) ;
109118 rejectCurrentLoad ( e ) ;
110119 }
@@ -113,28 +122,34 @@ export const asyncWritable = <S extends Stores, T>(
113122
114123 const onFirstSubscription : StartStopNotifier < T > = ( setStoreValue ) => {
115124 setCurrentLoadPromise ( ) ;
125+ parentValues = getAll ( stores ) ;
116126
117127 const initialLoad = async ( ) => {
128+ debuggy ?.( 'initial load called' ) ;
118129 try {
119130 parentValues = await loadAll ( stores ) ;
131+ debuggy ?.( 'setting ready' ) ;
120132 ready = true ;
121133 changeReceived = false ;
122134 mappingLoadThenSet ( setStoreValue ) ;
123135 } catch ( error ) {
136+ console . log ( 'wtf is happening' , error ) ;
124137 rejectCurrentLoad ( error ) ;
125138 }
126139 } ;
127140 initialLoad ( ) ;
128141
129142 const parentUnsubscribers = getStoresArray ( stores ) . map ( ( store , i ) =>
130143 store . subscribe ( ( value ) => {
144+ debuggy ?.( 'received value' , value ) ;
131145 changeReceived = true ;
132146 if ( Array . isArray ( stores ) ) {
133147 parentValues [ i ] = value ;
134148 } else {
135- parentValues = value as any ;
149+ parentValues = value as StoresValues < S > ;
136150 }
137151 if ( ready ) {
152+ debuggy ?.( 'proceeding because ready' ) ;
138153 mappingLoadThenSet ( setStoreValue ) ;
139154 }
140155 } )
@@ -143,41 +158,93 @@ export const asyncWritable = <S extends Stores, T>(
143158 // called on losing last subscriber
144159 return ( ) => {
145160 parentUnsubscribers . map ( ( unsubscriber ) => unsubscriber ( ) ) ;
161+ ready = false ;
146162 } ;
147163 } ;
148164
149165 const thisStore = writable ( initial , onFirstSubscription ) ;
150166
167+ const setStoreValueThenWrite = async (
168+ updater : Updater < T > ,
169+ persist ?: boolean
170+ ) => {
171+ setState ( 'WRITING' ) ;
172+ let oldValue : T ;
173+ try {
174+ oldValue = await currentLoadPromise ;
175+ } catch {
176+ oldValue = get ( thisStore ) ;
177+ }
178+
179+ setCurrentLoadPromise ( ) ;
180+ let newValue = updater ( oldValue ) ;
181+ thisStore . set ( newValue ) ;
182+
183+ if ( mappingWriteFunction && persist ) {
184+ try {
185+ const writeResponse = ( await mappingWriteFunction (
186+ newValue ,
187+ parentValues ,
188+ oldValue
189+ ) ) as T ;
190+
191+ if ( writeResponse !== undefined ) {
192+ thisStore . set ( writeResponse ) ;
193+ newValue = writeResponse ;
194+ }
195+ } catch ( error ) {
196+ logError ( error ) ;
197+ debuggy ?.( 'setting ERROR' ) ;
198+ setState ( 'ERROR' ) ;
199+ rejectCurrentLoad ( error ) ;
200+ throw error ;
201+ }
202+ }
203+ setState ( 'LOADED' ) ;
204+ resolveCurrentLoad ( newValue ) ;
205+ } ;
206+
207+ // required properties
151208 const subscribe = thisStore . subscribe ;
152- const load = async ( ) => {
209+ const load = ( ) => {
153210 const dummyUnsubscribe = thisStore . subscribe ( ( ) => {
154211 /* no-op */
155212 } ) ;
156- try {
157- const result = await currentLoadPromise ;
158- dummyUnsubscribe ( ) ;
159- return result ;
160- } catch ( error ) {
161- dummyUnsubscribe ( ) ;
162- throw error ;
163- }
213+ currentLoadPromise
214+ . catch ( ( ) => {
215+ /* no-op */
216+ } )
217+ . finally ( dummyUnsubscribe ) ;
218+ return currentLoadPromise ;
164219 } ;
165220 const reload = async ( visitedMap ?: VisitedMap ) => {
166221 ready = false ;
167222 changeReceived = false ;
168223 setCurrentLoadPromise ( ) ;
224+ debuggy ?.( 'setting RELOADING from reload' ) ;
169225 setState ( 'RELOADING' ) ;
170226
171227 const visitMap = visitedMap ?? new WeakMap ( ) ;
172- await reloadAll ( stores , visitMap ) ;
173- ready = true ;
174- if ( changeReceived || reloadable ) {
175- mappingLoadThenSet ( thisStore . set ) ;
176- } else {
177- resolveCurrentLoad ( get ( thisStore ) ) ;
228+ try {
229+ await reloadAll ( stores , visitMap ) ;
230+ ready = true ;
231+ if ( changeReceived || reloadable ) {
232+ mappingLoadThenSet ( thisStore . set ) ;
233+ } else {
234+ resolveCurrentLoad ( get ( thisStore ) ) ;
235+ setState ( 'LOADED' ) ;
236+ }
237+ } catch ( error ) {
238+ debuggy ?.( 'caught error during reload' ) ;
239+ setState ( 'ERROR' ) ;
240+ rejectCurrentLoad ( error ) ;
178241 }
179242 return currentLoadPromise ;
180243 } ;
244+ const set = ( newValue : T , persist = true ) =>
245+ setStoreValueThenWrite ( ( ) => newValue , persist ) ;
246+ const update = ( updater : Updater < T > , persist = true ) =>
247+ setStoreValueThenWrite ( updater , persist ) ;
181248
182249 return {
183250 get store ( ) {
@@ -186,10 +253,12 @@ export const asyncWritable = <S extends Stores, T>(
186253 subscribe,
187254 load,
188255 reload,
189- set : ( ) => Promise . resolve ( ) ,
190- update : ( ) => Promise . resolve ( ) ,
256+ set,
257+ update,
258+ state : { subscribe : loadState . subscribe } ,
191259 } ;
192260} ;
261+
193262/**
194263 * Generate a Loadable store that is considered 'loaded' after resolving asynchronous behavior.
195264 * This asynchronous behavior may be derived from the value of parent Loadable or non Loadable stores.
0 commit comments