11import { isAsyncFunction } from '@plexusjs/utils'
22import { PlexusInstance , instance } from './instance/instance'
3- import { PlexusError } from './error'
3+ import { PlexusError , handlePlexusError } from './error'
44type ErrorHandler = ( error : any ) => unknown
55
66export interface PlexusActionHooks {
7+ /**
8+ * Add a new error handler for this action. This will catch any errors that occur during the execution of this action and prevent a crash.
9+ * @param handler? A function that will be called when an error occurs; omit to fail silently.
10+ * @param {boolean }useGlobal Should the global error handler be used? (default: true)
11+ *
12+ */
713 onCatch ( handler ?: ErrorHandler , useGlobal ?: boolean ) : void
814 /**
915 * Ignore the default hault preActions
1016 */
1117 ignoreInit ( ) : void
18+ /**
19+ * Run a function. During that function's execution, any state changes will be batched and only applied once the function has finished.
20+ * @param fn The function to run in a batch
21+ */
1222 batch < ReturnType = any > ( fn : ( ) => ReturnType ) : ReturnType
1323}
1424export type ActionFunction <
@@ -89,21 +99,12 @@ class PlexusActionHelpers {
8999 */
90100 get hooks ( ) : PlexusActionHooks {
91101 return {
92- /**
93- * Add a new error handler for this action. This will catch any errors that occur during the execution of this action and prevent a crash.
94- * @param handler? A function that will be called when an error occurs; omit to fail silently.
95- *
96- */
97102 onCatch : ( handler ?: ErrorHandler , useGlobal = true ) : void => {
98103 return this . onCatch ( handler , useGlobal )
99104 } ,
100105 ignoreInit : ( ) : void => {
101106 return this . ignoreInit ( )
102107 } ,
103- /**
104- * Run a function. During that function's execution, any state changes will be batched and only applied once the function has finished.
105- * @param fn The function to run in a batch
106- */
107108 batch : < BatchResponse > ( batchFn : ( ) => BatchResponse ) : BatchResponse => {
108109 return this . instance ( ) . runtime . batch < any > ( batchFn )
109110 } ,
@@ -118,8 +119,6 @@ export function _action<Returns, Fn extends ActionFunction>(
118119) : InnerFunction < Fn > {
119120 const helpers = new PlexusActionHelpers ( instance )
120121
121- console . log ( 'function constructor' , fn . constructor . name , isAsyncFunction ( fn ) )
122-
123122 if ( typeof fn !== 'function' ) {
124123 console . warn (
125124 '%cPlexus WARN:%c An action must be of type Function.' ,
@@ -128,80 +127,66 @@ export function _action<Returns, Fn extends ActionFunction>(
128127 )
129128 throw new Error ( 'An action must be of type Function.' )
130129 }
131-
130+ /**
131+ * if the instance is not ready, wait for it to be
132+ * */
133+ const runInit = ( ) => {
134+ if ( ! instance ( ) . ready && ! helpers . _skipInit ) {
135+ if ( isAsyncFunction ( fn ) ) {
136+ // async call; just return the promise
137+ return instance ( ) . runtime . runInit ( )
138+ }
139+ // sync call
140+ let hold = true
141+ while ( hold ) {
142+ instance ( ) . runtime . runInit ( ( ) => {
143+ hold = false
144+ } )
145+ }
146+ }
147+ }
148+ // we NEED this conditional. I tried to make this fit into one function definition instead of two, but it didn't work; async error catching flops for some reason.
149+ if ( isAsyncFunction ( fn ) ) {
150+ return async function newAction ( ...args ) {
151+ try {
152+ await runInit ( )
153+ // if the action is batched, run it in a batch
154+ return batched
155+ ? await instance ( ) . runtime . batch (
156+ async ( ) => await fn ( helpers . hooks , ...args )
157+ )
158+ : await fn ( helpers . hooks , ...args )
159+ } catch ( e ) {
160+ // only return the error if there is no handler
161+ if ( ! helpers . catchError && ! instance ( ) . _globalCatch ) {
162+ throw handlePlexusError ( e )
163+ }
164+ helpers . runErrorHandlers ( e )
165+ // otherwise run the handler
166+ return handlePlexusError ( e )
167+ }
168+ } as InnerFunction < Fn >
169+ }
132170 function newAction ( ...args ) {
133171 try {
134172 // if the instance is not ready, wait for it to be
135- // !NOTE: this is probably not a good way to do this, but it works for now
136- if ( ! instance ( ) . ready && ! helpers . _skipInit ) {
137- let hold = true
138- while ( hold ) {
139- instance ( ) . runtime . runInit ( ( ) => {
140- hold = false
141- } )
142- }
143- }
144- // if the action is batched, run it in a batch
145- if ( batched ) {
146- return instance ( ) . runtime . batch ( ( ) => fn ( helpers . hooks , ...args ) )
147- }
148- // run the function
149- return fn ( helpers . hooks , ...args )
173+ runInit ( )
174+ // if the action is batched, run it in a batch; otherwise run it normally
175+ return batched
176+ ? instance ( ) . runtime . batch ( ( ) => fn ( helpers . hooks , ...args ) )
177+ : fn ( helpers . hooks , ...args )
150178 } catch ( e ) {
151179 // only return the error if there is no handler
152-
153180 if ( ! helpers . catchError && ! instance ( ) . _globalCatch ) {
154- console . log ( 'error caught but returning' , e )
155- if ( e instanceof PlexusError ) throw e
156- if ( e instanceof Error ) {
157- throw new PlexusError (
158- `An error occurred during the execution of an action (${ e . message } )` ,
159- { origin : 'action' , stack : e . stack }
160- )
161- }
181+ throw handlePlexusError ( e )
162182 }
163- console . log ( 'error caught' , e )
164183 helpers . runErrorHandlers ( e )
165-
166- // otherwise run the handler and return null
167- // TODO: return a PlexusError; needs to be a package wide change
168- return new PlexusError (
169- 'An error occurred during the execution of an action' ,
170- { origin : 'action' }
171- )
184+ // otherwise run the handler
185+ return handlePlexusError ( e )
172186 }
173187 }
174188 // return the proxy function
175189 return newAction as InnerFunction < Fn >
176-
177- // const newAction = async (...args) => {
178- // try {
179- // // if the instance is not ready, wait for it to be
180- // if (!instance().ready && !helpers._skipInit) {
181- // await instance().runtime.runInit()
182- // }
183- // // if the action is batched, run it in a batch
184- // console.log('(async)hewhewhewhewhewh', batched, 'hewhewhewhewhewh')
185- // if (batched) {
186- // console.log('using a batch in an async action...')
187- // return instance().runtime.batch(async () => {
188- // console.log('running the async action in a batch')
189- // return await fn(helpers.hooks, ...args)
190- // })
191- // }
192- // // run the function
193- // return await fn(helpers.hooks, ...args)
194- // } catch (e) {
195- // // only return the error if there is no handler
196- // if (!helpers.catchError && !instance()._globalCatch) throw e
197- // helpers.runErrorHandlers(e)
198- // // otherwise run the handler and return null
199- // return null
200- // }
201- // }
202- // // return the proxy function
203- // return newAction as InnerFunction<Fn>
204- // // return proxyFn as InnerFunction<Fn>
205190}
206191
207192/**
@@ -210,7 +195,7 @@ export function _action<Returns, Fn extends ActionFunction>(
210195 * @returns The intended return value of fn, or null if an error is caught
211196 */
212197export function action < Fn extends ActionFunction > ( fn : Fn ) : InnerFunction < Fn > {
213- return _action ( ( ) => instance ( ) , fn ) as InnerFunction < Fn >
198+ return _action ( ( ) => instance ( ) , fn )
214199}
215200
216201/**
0 commit comments