Skip to content

Conversation

@ENvironmentSet
Copy link
Collaborator

@ENvironmentSet ENvironmentSet commented Dec 23, 2025

  • An option skipDefaultHistorySetupTransition is added to use in cases where sequential transition entrances are awkward

@changeset-bot
Copy link

changeset-bot bot commented Dec 23, 2025

🦋 Changeset detected

Latest commit: a210e28

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@stackflow/plugin-history-sync Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@coderabbitai
Copy link

coderabbitai bot commented Dec 23, 2025

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added optional skipDefaultHistorySetupTransition configuration option to the history sync plugin, enabling users to control whether the default history setup transition is applied during initialization.

✏️ Tip: You can customize this high-level summary in your review settings.

Walkthrough

A changeset entry documents a minor version bump for @stackflow/plugin-history-sync, introducing a new skipDefaultHistorySetupTransition option. The historySyncPlugin.tsx is refactored to support this option, adding conditional initialization logic, helper functions for history event generation, and expanded state restoration in the onInit handler.

Changes

Cohort / File(s) Summary
Changeset Entry
.changeset/shiny-ears-draw.md
Changeset for minor version bump documenting introduction of skipDefaultHistorySetupTransition option
Plugin History Sync
extensions/plugin-history-sync/src/historySyncPlugin.tsx
Added skipDefaultHistorySetupTransition public option; refactored initial history setup with historyEntryToEvents and createTargetActivityPushEvent helpers; introduced conditional initialization paths with different event sequencing and skipEnterActiveState handling; adjusted event timing calculation; expanded onInit logic for route/step state population and history entry management

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

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 accurately reflects the main change: adding an option to skip default history setup transition in the plugin-history-sync package.
Description check ✅ Passed The description is related to the changeset, explaining the purpose of the new option for cases with awkward sequential transitions.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch default-history-transition-opt-out

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Dec 23, 2025

Deploying stackflow-demo with  Cloudflare Pages  Cloudflare Pages

Latest commit: a210e28
Status: ✅  Deploy successful!
Preview URL: https://18f9ff4e.stackflow-demo.pages.dev
Branch Preview URL: https://default-history-transition-o.stackflow-demo.pages.dev

View logs

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 23, 2025

commit: a210e28

@cloudflare-workers-and-pages
Copy link

cloudflare-workers-and-pages bot commented Dec 23, 2025

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
stackflow-docs a210e28 Commit Preview URL Dec 26 2025, 01:29 PM

@ENvironmentSet ENvironmentSet changed the title feat(plugin-history-sync): Add option to disable default history setup transition feat(plugin-history-sync): Add an option to skip default history setup transition Dec 26, 2025
@ENvironmentSet ENvironmentSet marked this pull request as ready for review December 26, 2025 13:27
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
extensions/plugin-history-sync/src/historySyncPlugin.tsx (2)

346-352: Consider simplifying isFirstPush tracking.

The isFirstPush variable is used to track whether we're processing the first Pushed event, but the logic can be simplified since there's only one Pushed event per historyEntry (at the start of the array returned by historyEntryToEvents).

The condition index === 0 && isFirstPush could be replaced with just index === 0 combined with checking if the event is the first Pushed event in the entry (which it always is, given historyEntryToEvents structure).

🔎 Proposed simplification
-            ...defaultHistory.map((historyEntry, index) => () => {
-              let isFirstPush = true;
-
-              return historyEntryToEvents(historyEntry).map((event) => {
-                if (event.name !== "Pushed") return event;
-                const skipEnterActiveState = index === 0 && isFirstPush;
-
-                isFirstPush = false;
+            ...defaultHistory.map((historyEntry, index) => () => {
+              let pushedEventProcessed = false;
+
+              return historyEntryToEvents(historyEntry).map((event) => {
+                if (event.name !== "Pushed") return event;
+                const skipEnterActiveState = index === 0 && !pushedEventProcessed;
+
+                pushedEventProcessed = true;

413-425: Consider handling StepReplaced steps differently.

Steps entered via StepReplaced are currently pushed to history using pushState. This could result in additional history entries for what were semantically replace operations. Consider using replaceState for steps where step.enteredBy.name === "StepReplaced".

🔎 Proposed differentiation
               for (const step of activity.steps) {
                 if (!step.exitedBy && step.enteredBy.name !== "Pushed") {
-                  pushState({
-                    history,
-                    pathname: template.fill(step.params),
-                    state: {
-                      activity: activity,
-                      step: step,
-                    },
-                    useHash: options.useHash,
-                  });
+                  const statePayload = {
+                    history,
+                    pathname: template.fill(step.params),
+                    state: {
+                      activity: activity,
+                      step: step,
+                    },
+                    useHash: options.useHash,
+                  };
+                  if (step.enteredBy.name === "StepReplaced") {
+                    replaceState(statePayload);
+                  } else {
+                    pushState(statePayload);
+                  }
                 }
               }
📜 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 57fd2da and a210e28.

📒 Files selected for processing (2)
  • .changeset/shiny-ears-draw.md
  • extensions/plugin-history-sync/src/historySyncPlugin.tsx
🧰 Additional context used
📓 Path-based instructions (3)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Write source in TypeScript with strict typing enabled across the codebase

Files:

  • extensions/plugin-history-sync/src/historySyncPlugin.tsx
extensions/plugin-*/**/*.{ts,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

Plugins must implement only the documented lifecycle hooks (onInit, onBeforePush/onPushed, onBeforePop/onPopped, onBeforeReplace/onReplaced, onBeforeStepPush/onStepPushed, onBeforeStepPop/onStepPopped, onBeforeStepReplace/onStepReplaced, onChanged)

Files:

  • extensions/plugin-history-sync/src/historySyncPlugin.tsx
.changeset/*.md

📄 CodeRabbit inference engine (AGENTS.md)

Include a Changeset entry for any user-facing package change

Files:

  • .changeset/shiny-ears-draw.md
🧬 Code graph analysis (1)
extensions/plugin-history-sync/src/historySyncPlugin.tsx (6)
extensions/plugin-history-sync/src/RouteLike.ts (1)
  • HistoryEntry (15-24)
core/src/event-types/PushedEvent.ts (1)
  • PushedEvent (3-14)
core/src/event-types/StepPushedEvent.ts (1)
  • StepPushedEvent (3-13)
extensions/plugin-history-sync/src/makeTemplate.ts (3)
  • makeTemplate (48-110)
  • urlSearchParamsToMap (9-17)
  • pathToUrl (5-7)
extensions/plugin-history-sync/src/ActivityActivationMonitor/DefaultHistoryActivityActivationMonitor.ts (1)
  • DefaultHistoryActivityActivationMonitor (12-61)
extensions/plugin-history-sync/src/historyState.ts (3)
  • parseState (39-45)
  • replaceState (65-81)
  • pushState (47-63)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Workers Builds: stackflow-docs
  • GitHub Check: Cloudflare Pages
🔇 Additional comments (6)
.changeset/shiny-ears-draw.md (1)

1-5: LGTM!

The changeset entry correctly documents a minor version bump for the new skipDefaultHistorySetupTransition option. As per coding guidelines, user-facing package changes include a changeset entry.

extensions/plugin-history-sync/src/historySyncPlugin.tsx (5)

31-31: LGTM!

The HistoryEntry type import is appropriately added to support the new helper function's type signature.


67-67: LGTM!

The new optional skipDefaultHistorySetupTransition property is well-named and properly typed.


297-315: LGTM!

The createTargetActivityPushEvent helper cleanly encapsulates target activity event creation with appropriate fallback handling for parameter parsing.


370-377: LGTM!

The event timing calculation correctly assigns ascending timestamps, ensuring proper event ordering with consistent relative offsets from a single captured timestamp.


284-295: Consider explicitly setting targetActivityId on StepPushed events to improve code clarity.

The StepPushed events generated for additionalSteps don't include targetActivityId. While optional per the type definition and handled by fallback to the latest active activity, explicitly setting this field would make the association clearer and more robust, especially in scenarios involving multiple simultaneous activity initializations. The Pushed event's activityId should be captured and reused for the corresponding StepPushed events.

Comment on lines +388 to +390
const match = activityRoutes.find(
(r) => r.activityName === activity.name,
)!;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add defensive handling for missing route match.

The non-null assertion on activityRoutes.find() could throw if an activity's name doesn't match any configured route. While this is unlikely in normal operation, it could cause initialization failures for edge cases or misconfigured activities.

🔎 Proposed defensive handling
-              const match = activityRoutes.find(
-                (r) => r.activityName === activity.name,
-              )!;
+              const match = activityRoutes.find(
+                (r) => r.activityName === activity.name,
+              );
+              if (!match) continue;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const match = activityRoutes.find(
(r) => r.activityName === activity.name,
)!;
const match = activityRoutes.find(
(r) => r.activityName === activity.name,
);
if (!match) continue;
🤖 Prompt for AI Agents
In extensions/plugin-history-sync/src/historySyncPlugin.tsx around lines 388 to
390, the code uses a non-null assertion on activityRoutes.find(...) which will
throw if no route matches an activity name; replace the assertion with a safe
lookup: check the result of find, if it's undefined log a warning (including
activity.name for debugging) and skip or provide a sensible fallback handler so
initialization doesn't crash; ensure subsequent code branches handle the absent
route case gracefully.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants