Closed Zehir closed 1 year ago
Yes, I have just encountered a related problem. This has to do with the serialization of events done by xstate-ninja prior to sending them to the browser extension. There is a sanitizeObject
function which tries to strip the event objects off the unsafe properties, but apparently it fails.
https://github.com/rlaffers/xstate-ninja/blob/master/packages/xstate-ninja-core/src/utils.ts#L145
We need to think about a better strategy.
A hotfix would be always stripping away some properties, e.g. those starting with _
. E.g.:
export function sanitizeObject<T extends Record<string, any>>(obj: T): T {
const result: Record<string, any> = {}
for (const key in obj) {
if (key[0] === '_') {
// skip properties starting with _
result[key] = '<stripped>'
continue
}
I'm not a big fan of doing this, because it requires a change in the machine configuration (prefixing unsafe event props with "_"). What do you think?
Of course, it would be also possible to traverse everything and detect circular references, but this may be costly.
A hotfix would be always stripping away some properties, e.g. those starting with
_
. E.g.:export function sanitizeObject<T extends Record<string, any>>(obj: T): T { const result: Record<string, any> = {} for (const key in obj) { if (key[0] === '_') { // skip properties starting with _ result[key] = '<stripped>' continue }
I'm not a big fan of doing this, because it requires a change in the machine configuration (prefixing unsafe event props with "_"). What do you think?
I can't control the library so it's hard to do, maybe limit the depth of the context or query one level when expending in the extension
Indeed. I will implement a proper function for filtering out circular refs.
Indeed. I will implement a proper function for filtering out circular refs.
Is there any work around that I can use today ?
@Zehir Try upgrading to xstate-ninja@1.3.5
Hello @rlaffers I still have the error;
xstate-ninja.js:114 Uncaught (in promise) TypeError: Converting circular structure to JSON
--> starting at object with constructor 'Client'
| property 'recordServices' -> object with constructor 'Object'
| property 'user' -> object with constructor 'RecordService'
--- property 'client' closes the circle
at JSON.stringify (<anonymous>)
at C (xstate-ninja.js:114:17)
at new ee (xstate-ninja.js:266:19)
at xstate-ninja.js:482:17
at Interpreter2.update (interpreter.js:452:9)
at interpreter.js:106:15
at Scheduler2.process (scheduler.js:65:7)
at Scheduler2.schedule (scheduler.js:44:10)
at Interpreter2.send (interpreter.js:100:23)
at Interpreter2.inspectSend [as send] (browser.js:126:24)
@Zehir Can you perhaps set up a Codesandbox for this? Or else provide what is logged in the JS console? Just set up logging with:
import xstateNinja, { LogLevels } from 'xstate-ninja'
xstateNinja({ logLevel: LogLevels.debug })
The last "actor updated" log should log a state snapshot which should contain an event
. Let's look at it.
In the meantime I will release a hotfix which wraps serialization in a try-catch block, so there are no exceptions.
@Zehir Can you perhaps set up a Codesandbox for this? Or else provide what is logged in the JS console? Just set up logging with:
import xstateNinja, { LogLevels } from 'xstate-ninja' xstateNinja({ logLevel: LogLevels.debug })
The last "actor updated" log should log a state snapshot which should contain an
event
. Let's look at it.
You can use my repo; https://github.com/deconz-community/ddf-tools You will need to start both ;
pnpm dev:store
pnpm dev:toolbox
Enable back xstate ninja here : https://github.com/deconz-community/ddf-tools/blob/5a2e8422ab14499fea967ff333b942e667e60c62/packages/toolbox/src/composables/useAppMachine.ts#L160-L166
Then open the page http://localhost:4000/ddf-tools/sandbox
Hmm, I cannot reproduce this. The connectToPocketBase service fails (the promise is rejected). I guess that's because I have no pocketBaseUrl in my env.
New version with serialization wrapped: https://github.com/rlaffers/xstate-ninja/releases/tag/v1.3.6
Hmm, I cannot reproduce this. The connectToPocketBase service fails (the promise is rejected). I guess that's because I have no pocketBaseUrl in my env.
Sorry my bad, you can edit the .env file ;
VITE_POCKETBASE_URL="http://127.0.0.1:8090"
I will try to do a reproduction url when I have some time soon thanks
Gotcha, I reproduced the problem.
For that specific case I dont need to see the values inside but it's might not be the case each time
So in this case the serialization fails because the context contains some circular data. I will apply the same sanitization function as is used for sanitizing event objects. So most of the data should remain intact, but cirular refs will be replaced with "\
Hey @Zehir xstate-ninja@1.3.7 is out. I strongly believe this will fix your issue.
Sorry but no, I don't understand why but as soon I register with ninja.register(service)
I get errors that don't seems related to xstate ninja;
If I disable the chrome extension I don't have any errors
nav-sidebar-level-one.vue:23
Uncaught (in promise) TypeError: app.state.context.machine.gateways.keys is not a function
at ReactiveEffect.fn (nav-sidebar-level-one.vue:23:5)
at ReactiveEffect.run (reactivity.esm-bundler.js:178:19)
at get value [as value] (reactivity.esm-bundler.js:1147:33)
at unref (reactivity.esm-bundler.js:1026:29)
at Object.get (reactivity.esm-bundler.js:1032:35)
at nav-sidebar-level-one.vue:57:20
at Proxy.renderFnWithContext (runtime-core.esm-bundler.js:766:13)
at Proxy.render (vue3-perfect-scrollbar.esm.js:102:42)
at renderComponentRoot (runtime-core.esm-bundler.js:816:16)
at ReactiveEffect.componentUpdateFn [as fn] (runtime-core.esm-bundler.js:5701:46)
device.ts:52
Uncaught (in promise) TypeError: context.gateway.getDevice is not a function
at fetchData (device.ts:52:43)
at Interpreter2._exec (interpreter.js:265:57)
at Interpreter2.exec (interpreter.js:1022:10)
at Interpreter2.execute (interpreter.js:383:14)
at Interpreter2.update (interpreter.js:411:12)
at interpreter.js:671:13
at Scheduler2.process (scheduler.js:65:7)
at Scheduler2.initialize (scheduler.js:28:12)
at Interpreter2.start (interpreter.js:670:20)
at Interpreter2.spawnMachine (interpreter.js:1109:8)
I added some debug, my function stored in the context was replaced by a string;
services: {
fetchData: (context) => {
console.log('fetchData', typeof context.gateway.getDevice)
console.log('fetchData', context.gateway.getDevice)
return context.gateway.getDevice({
params: {
deviceUniqueID: context.id,
},
})
},
},
device.ts:53 fetchData string
device.ts:54 fetchData <function>: (t) => this.request(…
device.ts:55 Uncaught (in promise) TypeError: context.gateway.getDevice is not a function
at fetchData (device.ts:55:30)
at Interpreter2._exec (interpreter.js:265:57)
at Interpreter2.exec (interpreter.js:1022:10)
at Interpreter2.execute (interpreter.js:383:14)
at Interpreter2.update (interpreter.js:411:12)
at interpreter.js:671:13
at Scheduler2.process (scheduler.js:65:7)
at Scheduler2.initialize (scheduler.js:28:12)
at Interpreter2.start (interpreter.js:670:20)
at Interpreter2.spawnMachine (interpreter.js:1109:8)
@Zehir This issue was caused by incorrect serialization of context data in xstate-ninja (it did some mutation on the original object). Can you please test your code with version 1.3.9?
thanks @rlaffers it's worked :)
Hello,
I have a machine where I store a rest client inside the context but it's seems to have circular structure and this crash the xstate-ninja and then the machine;
Machine used ;
With XStateNinja registred I am stuck in the
connecting
state and without I get to theonline
state