Repository navigation
fix(core): hash Map, Set and RegExp options in deep-hash tokens - #17945
Merged
kamilmysliwiec merged 3 commits intoSep 30, 2026
Merged
Conversation
With `moduleIdGeneratorAlgorithm: 'deep-hash'`, a dynamic module's
token is the hash of its serialized metadata. `fast-safe-stringify`
follows JSON semantics, so a `Map`, `Set` or `RegExp` in the options
became `{}`, and two imports of the same dynamic module that differed
only there got one token. The container kept the first module and
silently dropped the second import's providers.
Serialize them by their entries, values and source, tagged so they do
not collide with plain values that hold the same data.
4 of 12 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
PR Checklist
Please check if your PR fulfills the following requirements:
PR Type
What kind of change does this PR introduce?
What is the current behavior?
With
moduleIdGeneratorAlgorithm: 'deep-hash',DeepHashedModuleOpaqueKeyFactory.createForDynamic()hashes the serialized dynamic metadata. The serializer,fast-safe-stringify, followsJSON.stringifysemantics, so aMap,SetorRegExpanywhere in the metadata becomes{}. Two imports of the same dynamic module whose options differ only there get the same token, for example options holdingnew Map([['a', 1]])andnew Map([['b', 2]]),new Set(['x'])andnew Set(['y']), or/^\/api/and/^\/admin/.NestContainer.addModule()then finds the token, returns the first module withinserted: false, and the second import's providers are dropped, so its consumers get the first import's options. The option's JSDoc says the id "is generated based on the serialized module definition", and nothing in the specs pins the collisions.The new spec against the current factory:
Issue Number: N/A
What is the new behavior?
replacerserializes aMapas{ Map: [...entries] }, aSetas{ Set: [...values] }and aRegExpas{ RegExp: value.toString() }. The tag keeps them apart from a plain array or string with the same content; a plain object literally shaped{ Map: [...] },{ Set: [...] }or{ RegExp: '...' }still gets the same token as the real value. Every other value serializes as before, so tokens of modules without these values do not change, and identical options still share one module. The defaultreferencealgorithm is not affected.One limit:
fast-safe-stringifydoes not look inside aMaporSetwhen it removes circular references, so metadata with a cycle through one of them now serializes to its fallback string ([unable to serialize, circular reference is too complex to analyze]) instead of{}. That string carries no module id or name, so every dynamic module with such metadata gets the same token.BigIntvalues already reach the same fallback.Does this PR introduce a breaking change?
Other information
npx vitest run packages/core: 1395 passed.