angular-architects / ngrx-toolkit

Various Extensions for the NgRx Signal Store
MIT License
146 stars 22 forks source link

Using `withDevTools` throws an error when the state has `bigint` types #29

Open robmanganelly opened 6 months ago

robmanganelly commented 6 months ago

Hi guys,

I'm using ngrx/toolkit only to make my SignalStore available to Redux Dev Tools. Hence, the only method in use is withDevTools, and I am passing a string.

My project is using:

// excerpt of package.json dependencies 
    "@ngrx/operators": "^17.1.1",
    "@ngrx/signals": "^17.1.1",
    "@ngrx/store": "^17.1.1",
    ...
    "ip-address": "^8.1.0",
     "@angular-architects/module-federation": "^17.0.6",
    "@angular-architects/ngrx-toolkit": "^0.1.2",
    ...

When I started using ip-address to perform operations on IPs, I got the following error:

# Chrome Dev Console Log
ip.component.ts:21 ERROR TypeError: Do not know how to serialize a BigInt
    at JSON.stringify (<anonymous>)
    at ot.stringify (<anonymous>:1:5274)
    at Dh (<anonymous>:4:2215)
    at k (<anonymous>:4:2313)
    at q (<anonymous>:6:311)
    at qe (<anonymous>:6:921)
    at Object.g [as send] (<anonymous>:6:2585)
    at EffectHandle.effectFn (angular-architects-ngrx-toolkit.mjs:26:20)

and this is the offending function in toolkit

function initSynchronization() {
    effect(() => {
        if (!connection) {
            return;
        }
        const stores = storeRegistry();
        const rootState = {};
        for (const name in stores) {
            const store = stores[name];
            rootState[name] = store();
        }
        const names = Array.from(currentActionNames);
        const type = names.length ? names.join(', ') : 'Store Update';
        currentActionNames = new Set();
        connection.send({ type }, rootState);
    });
}

Is it a bug or is there something that can be done from my side to mitigate this before reaching toolkit ? My implementation wraps Address4 or Address6 (from ip-address) and creates instances of them that go into the state. Given my business logic, I do need the actual instance and not a simplified representation of it, so, sadly, this is not a solution.

Thanks for the great job.

robmanganelly commented 6 months ago

UPDATE: I was able to solve the problem by reimplementing the toJSON method in my wrapper, I'm posting this in case anyone else faces the same issue in the future.

export class MyWrapper{

  #nativeIp: Address4 | Address 6; 

  toJSON(){
    // define serialization logic here, 
    // avoiding circular deps, and do not expose bigints to be serialized.
    return this.#nativeIp.correctForm(); 
  }

}

The issue is still valid for the case you have no way to reimplement JSON.stringify

rainerhahnekamp commented 6 months ago

Dear @robmanganelly , thanks for posting this. Would it be possible for you to add a PR, or should some of us do it?

robmanganelly commented 6 months ago

Hello. I have a PR ready. But I think I found another problem. It could be my own mistake though, so, please check the spec file I changed and look for comment on line 137

edit (could not push, don't have enough permissions)

rainerhahnekamp commented 6 months ago

@robmanganelly you need to fork this project and push your branch to the fork. Then GitHub will give you the possibility to create a PR.

robmanganelly commented 5 months ago

done