feat(core): add prune API to clear event history
Summary
Adds prune() API to StackflowActions in @stackflow/core to manually clear past events and inactive activities.
Motivation
Stackflow's Event Sourcing pattern causes the event history to grow indefinitely. This leads to increased memory usage and re-calculation costs in long-running sessions. A mechanism to clear old history and release memory was required.
Features
-
actions.prune(): Clears event history while preserving the current stack state. -
State Reconstruction: Reconstructs the stack using only
enter-activeandenter-doneactivities.
β οΈ No Changeset found
Latest commit: 9583f125eb710f0878b0cb2da4c5ebc1ac7e9e14
Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.
This PR includes no changesets
When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types
Click here to learn what changesets are, and how to add one.
Click here if you're a maintainer who wants to add a changeset to this PR
π Walkthrough
Summary by CodeRabbit
-
New Features
- Added a
prune()action that clears historical events while reconstructing and maintaining the current application state, helping optimize memory usage by removing past event data.
- Added a
βοΈ Tip: You can customize this high-level summary in your review settings.
Walkthrough
Adds a new prune() action to the public actions surface and implements it to rebuild a minimal event history from currently active activities, replace stored events, and re-aggregate the stack; a unit test verifying prune behavior was added.
Changes
| Cohort / File(s) | Change Summary |
|---|---|
Interface core/src/interfaces/StackflowActions.ts |
Added public method prune(): void to StackflowActions with JSDoc describing clearing past events and reconstructing state from active activities. |
Core store core/src/makeCoreStore.ts |
Exposed a store object into action construction (getStack, events.value, setStackValue) and surfaced prune() on the actions object. |
Action utilities core/src/utils/makeActions.ts |
Extended makeActions to accept store in ActionCreatorOptions and implemented prune() which: reads current stack, identifies active activities, builds a synthetic sequence of DomainEvents (Initialized, ActivityRegistered*, Pushed/Step events, Popped as applicable), replaces store.events.value, re-aggregates via aggregate(...), and applies the new stack via setStackValue. Added imports for aggregate, DomainEvent, makeEvent, and Stack. |
Tests core/src/makeCoreStore.spec.ts |
Added test "makeCoreStore - pruneμ΄ νΈμΆλλ©΄, κ³Όκ±°μ μ΄λ²€νΈλ₯Ό μ 리νκ³ νμ¬ μνλ₯Ό μ μ§ν©λλ€" that seeds past events, performs pushes/pops, asserts pre-prune stack, calls prune(), then asserts only active activities remain and events trimmed to the minimal synthetic set. |
Sequence Diagram(s)
sequenceDiagram
participant Caller
participant Actions as Actions.prune()
participant Store
participant Events as Events.value
participant Aggregate as aggregate()
Caller->>Actions: prune()
Actions->>Store: getStack()
Store-->>Actions: current Stack
rect rgb(230,245,235)
Note over Actions: Filter active activities\n(build activity metadata list)
Actions->>Actions: Build synthetic events:\n- Initialized\n- ActivityRegistered* (reuse metadata)\n- Pushed / StepPushed / StepReplaced\n- Popped (if needed)
end
Actions->>Events: events.value = [synthetic events]
rect rgb(245,235,235)
Actions->>Aggregate: aggregate(events.value)
Aggregate-->>Actions: new Stack
end
Actions->>Store: setStackValue(new Stack)
Store-->>Caller: stack & events updated
Estimated code review effort
π― 3 (Moderate) | β±οΈ ~20 minutes
- Verify event ordering and flags when building synthetic events (e.g., skipEnterActiveState, activityContext).
- Check transitionState filtering and selection of "active" activities (enter-active vs enter-done).
- Ensure
store.events.valuereplacement is safe (no stale references) and aggregation is deterministic. - Review the new test for edge cases (empty stack, single active activity, mixed states) and timing assumptions for event dates.
Pre-merge checks and finishing touches
β Failed checks (1 warning)
| Check name | Status | Explanation | Resolution |
|---|---|---|---|
| Docstring Coverage | β οΈ Warning | Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. | You can run @coderabbitai generate docstrings to improve docstring coverage. |
β Passed checks (2 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | β Passed | The title 'feat(core): add prune API to clear event history' clearly and accurately summarizes the main change: adding a new prune API to the core module for clearing event history, which aligns with all modified files. |
| Description check | β Passed | The description is well-detailed and directly related to the changeset, explaining the motivation for the prune API, its purpose in clearing event history while preserving stack state, and the features being introduced. |
β¨ Finishing touches
- [ ] π Generate docstrings
π§ͺ Generate unit tests (beta)
- [ ] Create PR with unit tests
- [ ] Post copyable unit tests in a comment
π Recent review details
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Disabled knowledge base sources:
- Jira integration is disabled by default for public repositories
- Linear integration is disabled by default for public repositories
You can enable these sources in your CodeRabbit configuration.
π₯ Commits
Reviewing files that changed from the base of the PR and between 93620891a6ddc289d96742c90b0421477f3ecf88 and 9583f125eb710f0878b0cb2da4c5ebc1ac7e9e14.
π Files selected for processing (1)
-
core/src/utils/makeActions.ts(2 hunks)
π§° Additional context used
π Path-based instructions (1)
**/*.{ts,tsx}
π CodeRabbit inference engine (AGENTS.md)
Write source in TypeScript with strict typing enabled across the codebase
Files:
-
core/src/utils/makeActions.ts
𧬠Code graph analysis (1)
core/src/utils/makeActions.ts (4)
core/src/interfaces/StackflowActions.ts (1)
StackflowActions(15-70)core/src/Stack.ts (1)
Stack(50-57)core/src/event-types/index.ts (1)
DomainEvent(12-22)core/src/aggregate.ts (1)
aggregate(7-113)
π Additional comments (8)
core/src/utils/makeActions.ts (8)
1-5: LGTM!The new imports for
aggregate,DomainEvent,makeEvent, andStackare properly typed and necessary for theprune()implementation.
12-16: LGTM!The
storeparameter is properly typed and provides the necessary access to stack state, events, and mutation capability for theprune()implementation.Also applies to: 23-23
138-143: LGTM!The guard against pruning a paused stack is appropriate and prevents loss of
pausedEvents.
145-150: LGTM!Including
"exit-active"activities in the filter correctly preserves activities that are currently transitioning out, addressing the previous review concern.
152-158: LGTM!The event date calculation ensures monotonic time progression, and preserving the original
Initializedevent'seventDatemaintains temporal consistency.
160-202: LGTM!The logic correctly preserves ALL activity registrations (not just active ones) including their
paramsSchemametadata, addressing the previous concern about dropping inactive registrations.
204-229: LGTM!The reconstruction logic correctly:
- Preserves original entry semantics (
PushedvsReplaced) to maintainisRootcomputation- Includes all activity metadata (
activityContext)- Reconstructs steps with proper event types and metadata (
hasZIndex)- Skips the first step appropriately (root step is represented in activity params)
This addresses previous concerns about entry semantics and step preservation.
231-240: LGTM!Correctly extracts and preserves
Poppedevents forexit-activeactivities, maintaining temporal ordering.
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 @coderabbitai help to get the list of available commands and usage tips.