Conversation
Allow undefined as a valid StructuralKey and as an explicit object property value (so undefined is distinct from a missing property). Add serialization for undefined, relax the previous prohibition on undefined in object properties, and update the error message to mention undefined. Refactor key-id caching to a module-level WeakMap and simplify serialization helpers (remove per-call WeakMap parameter, use Array.from and toSorted). Update tests and the changeset documentation and add an example for StructuralMap usage.
Expose a snapshot API and harden resource lifecycle semantics. - Add SharedResource.snapshot and SharedResourceSnapshot (isIdle + mutex snapshot) for monitoring. - Document that Resource lifecycle ops (acquire/release/set) run to completion once started and should be awaited; import SemaphoreSnapshot type. - Make createSharedResource return a snapshot implementation that uses mutex.snapshot(). - Improve disposal ordering and callbacks: use an AsyncDisposableStack when disposing current resources and invoke onDisposed in a safe, controlled way. - For createSharedResourceByKey, run the onDisposed callback under the key mutex and only delete/dispose the keyed entry when it is still idle and still the same sharedResource, preventing stale callbacks from removing newly reacquired keys. - Update tests to add onDispose hooks, new run snapshot counting helpers, reorganize idleDisposeAfter tests, and adjust expectations to the new unabortable/await semantics and disposal timing. These changes improve observability and make resource cleanup and keyed eviction robust against races and aborted callers.
Refactor SharedEvolu lifecycle management to use createSharedResourceByKey instead of a manual Map+mutex. Initialize sharedEvolusByName via stack.use and run, and use a run.create() wrapper (initSharedWorkerRun) with assertNotAborted when acquiring the resource. addPorts now accepts a releaseSharedEvolu callback and asserts not to be called after disposal; on Evolu Dispose it removes the dbWorkerPort and invokes releaseSharedEvolu. Mark isDisposed in the async disposer to prevent post-disposal usage. Cleanup: remove createMutexByKey usage and related code, import createSharedResourceByKey, drop the unused appOwner parameter, and simplify concurrent acquisition/creation logic.
Source upstream commit: a573d02 Port scope: not-applicable
Source upstream commit: ccb0871 Port scope: not-applicable
Source upstream commit: d8e61d2 Port scope: adapted
Source upstream commit: 4aa57bd Port scope: adapted
Source upstream commit: dfa138c Port scope: adapted
Source upstream commit: 166e798 Port scope: adapted
Source upstream commit: 5a4eced Port scope: adapted
Source upstream commit: 8d35141 Port scope: adapted
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (25)
📝 WalkthroughWalkthroughTato PR kombinuje aktualizace závislostí v mnoha Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Suggested reviewers
Poem
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment Tip CodeRabbit can use TruffleHog to scan for secrets in your code with verification capabilities.Add a TruffleHog config file (e.g. trufflehog-config.yml, trufflehog.yml) to your project to customize detectors and scanning behavior. The tool runs only when a config file is present. |
There was a problem hiding this comment.
Pull request overview
This PR updates dependencies across the monorepo and refactors local-first shared-worker resource management by expanding structural-key support and adding new snapshot/idle-state introspection to concurrency/resource primitives.
Changes:
- Bumped various framework/tooling dependencies (Svelte, Expo, Biome, Turbo, etc.) and refreshed
bun.lock. - Extended
StructuralKey/StructuralMapto supportundefined(including distinguishingundefinedfrom missing object properties) and updated tests/docs accordingly. - Added
isIdletoSemaphoreSnapshot, addedsnapshot()toSharedResource, and refactoredSharedWorkerEvolu instance tracking to usecreateSharedResourceByKey.
Reviewed changes
Copilot reviewed 25 out of 26 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/svelte/package.json | Bump Svelte dependency + peer range. |
| packages/react-native/package.json | Update Expo/RN-related deps. |
| packages/common/test/local-first/Evolu.test.ts | Update integration snapshot expectations. |
| packages/common/test/Task.test.ts | Update semaphore snapshot assertions for new isIdle. |
| packages/common/test/StructuralMap.test.ts | Add coverage for undefined structural keys and object-property distinction. |
| packages/common/test/Resource.test.ts | Add tests for SharedResource.snapshot + keyed idle-eviction disposal behavior. |
| packages/common/src/local-first/Shared.ts | Refactor shared-worker Evolu lifecycle to keyed shared resources and explicit acquire/release. |
| packages/common/src/local-first/Evolu.ts | Remove a TODO comment. |
| packages/common/src/Test.ts | Expand testWaitForMacrotask documentation. |
| packages/common/src/Task.ts | Add isIdle to SemaphoreSnapshot and use it for keyed semaphore cleanup. |
| packages/common/src/StructuralMap.ts | Extend StructuralKey to include undefined, update serialization and error messages. |
| packages/common/src/Resource.ts | Add SharedResource.snapshot, refine lifecycle docs, adjust keyed shared-resource cleanup. |
| packages/common/package.json | Bump kysely. |
| packages/bun/package.json | Bump bun-types. |
| package.json | Bump Biome/Turbo/typedoc-plugin-markdown dev deps. |
| examples/vue-vite-pwa/package.json | Bump vue-tsc. |
| examples/tanstack-start/package.json | Bump @tanstack/react-router. |
| examples/svelte-vite-pwa/package.json | Bump Svelte. |
| examples/react-vite-pwa/package.json | Bump Tailwind deps. |
| examples/react-nextjs/package.json | Bump Next + Tailwind deps. |
| examples/react-expo/package.json | Bump Expo and related deps. |
| examples/astro/package.json | Bump Astro + @astrojs/react. |
| examples/angular-vite-pwa/package.json | Bump Angular + Tailwind deps. |
| bun.lock | Lockfile updates for the above version bumps. |
| biome.json | Update Biome schema URL to match bumped Biome version. |
| .changeset/structural-map-uint8array.md | Refresh StructuralMap changeset narrative and add example. |
| { | ||
| onDispose, | ||
| }: { | ||
| onDispose?: (() => void) | undefined; |
There was a problem hiding this comment.
The option property type onDispose?: (() => void) | undefined is redundant because an optional property already includes undefined. Simplify to onDispose?: () => void to reduce noise and keep types consistent.
| onDispose?: (() => void) | undefined; | |
| onDispose?: () => void; |
| evoluPorts.delete(evoluPortId); | ||
| dbWorkerPorts.delete(dbWorkerPort); | ||
| rowsByQueryByEvoluPortId.delete(evoluPortId); |
There was a problem hiding this comment.
When handling an Evolu port "Dispose", the code removes dbWorkerPort from dbWorkerPorts but does not clear activeDbWorkerPort when it equals that port. This can leave ensureQueueProcessing() posting messages to a closed/removed leader port until the heartbeat timeout fires. Consider explicitly handling if (activeDbWorkerPort === dbWorkerPort) by clearing the leader timeout and setting activeDbWorkerPort = null (and aborting/cancelling any in-flight queue processing) before continuing.
| const initSharedWorkerRun = run.create(); | ||
| const sharedEvolusByNamePromise = run.orThrow( |
There was a problem hiding this comment.
initSharedWorkerRun is created with run.create() but never disposed or registered in the returned AsyncDisposableStack. Since run.create() creates a long-lived daemon Run, this will remain as a child run for the lifetime of the root daemon (and keep any future child fibers reachable). Register it in stack (e.g. stack.use(initSharedWorkerRun)) so it’s disposed when the shared worker stack is disposed.
| const initSharedWorkerRun = run.create(); | |
| const sharedEvolusByNamePromise = run.orThrow( | |
| const initSharedWorkerRun = stack.use(run.create()); | |
| const sharedEvolusByNamePromise = initSharedWorkerRun.orThrow( |
|
|
||
| const getKeyId = (key: K): string => | ||
| serializeStructuralKey(key, keyIdByObject, new Set<object>()); | ||
| const getKeyId = (key: K): string => serializeStructuralKey(key, new Set()); |
There was a problem hiding this comment.
serializeStructuralKey expects a Set<object> for cycle detection, but getKeyId passes new Set() which defaults to Set<any>. Explicitly typing this as new Set<object>() keeps the helper fully type-safe and avoids accidental non-object values being added later.
| const getKeyId = (key: K): string => serializeStructuralKey(key, new Set()); | |
| const getKeyId = (key: K): string => | |
| serializeStructuralKey(key, new Set<object>()); |
Summary
Scope
Verification
bun verifyor repo equivalent)Governance
Linked Issues
Summary by CodeRabbit
Poznámky k vydání
New Features
snapshot()method toSharedResourcefor monitoring idle and mutex states.StructuralMapto supportundefinedas a valid key type alongside JSON-like values and byte arrays.Bug Fixes
Chores