Skip to content

feat(plugin-stack-persistence): add composeStrategies - #734

Merged
ENvironmentSet merged 10 commits into
mainfrom
feature/fep-2611
Jul 22, 2026
Merged

feat(plugin-stack-persistence): add composeStrategies#734
ENvironmentSet merged 10 commits into
mainfrom
feature/fep-2611

Conversation

@ENvironmentSet

@ENvironmentSet ENvironmentSet commented Jul 22, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds composeStrategies, a utility that composes multiple StackSnapshotStrategy instances into one (FEP-2611).

const strategy = composeStrategies({
  historySync: historySyncStrategy,
  deployVersion: deployVersionStrategy,
});
  • Keyed record input — each key namespaces its strategy's metadata.
  • createMetadata persists each strategy's metadata side by side under its key.
  • shouldReuse is AND-composed — a snapshot is reused only when every strategy agrees; each strategy receives only the metadata under its own key and never learns it was composed.
  • Missing-key fail-safe — if any configured key is absent from stored metadata (including legacy non-composed / non-object metadata), reuse is rejected without consulting any strategy.
  • Closed under composition — the result is itself a StackSnapshotStrategy, so composed strategies can be nested; stackPersistencePlugin's single-strategy option API is unchanged.
  • Metadata type is inferred from the input record — no manual type arguments.

🤖 Generated with Claude Code

https://claude.ai/code/session_01TMTNfPxft5WXLjpJbN8etC

@changeset-bot

changeset-bot Bot commented Jul 22, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8c88f65

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-stack-persistence 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

coderabbitai Bot commented Jul 22, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 973c0c0e-0191-494e-a06d-e1bf8b82bc2d

📥 Commits

Reviewing files that changed from the base of the PR and between 1c8aa4e and 8c88f65.

📒 Files selected for processing (1)
  • extensions/plugin-stack-persistence/src/index.ts
💤 Files with no reviewable changes (1)
  • extensions/plugin-stack-persistence/src/index.ts

📝 Walkthrough

Summary by CodeRabbit

  • New Features
    • Added support for composing multiple stack persistence strategies into a single strategy.
    • Combined metadata creation and reuse validation are performed across the composed strategies.
    • Exposed the new composition utility via the public persistence plugin API, including the related exported type.

Walkthrough

Adds a typed composeStrategies factory that combines stack snapshot strategies, aggregates their metadata, delegates reuse checks, exposes the API publicly, and records a minor package release.

Changes

Persistence strategy composition

Layer / File(s) Summary
Implement composite strategy
extensions/plugin-stack-persistence/src/composeStrategies.ts
Adds StrategiesMetadata and composes per-strategy metadata creation and reuse checks keyed by strategy name.
Expose and release the composition API
extensions/plugin-stack-persistence/src/index.ts, .changeset/shaggy-foxes-compose.md
Re-exports the composition API and metadata types, updates error export formatting, and records a minor release.

Estimated code review effort: 2 (Simple) | ~10 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant composeStrategies
  participant FirstStrategy
  participant SecondStrategy
  Caller->>composeStrategies: provide keyed strategies
  composeStrategies->>FirstStrategy: createMetadata(args)
  composeStrategies->>SecondStrategy: createMetadata(args)
  FirstStrategy-->>composeStrategies: return keyed metadata
  SecondStrategy-->>composeStrategies: return keyed metadata
  composeStrategies->>FirstStrategy: shouldReuse(metadata, initialContext)
  composeStrategies->>SecondStrategy: shouldReuse(metadata, initialContext)
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly names the new composeStrategies feature and matches the main change.
Description check ✅ Passed The description directly describes composeStrategies and its behavior, matching the pull request changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/fep-2611

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.

@pkg-pr-new

pkg-pr-new Bot commented Jul 22, 2026

Copy link
Copy Markdown
  • @stackflow/demo

    yarn add https://pkg.pr.new/daangn/stackflow/@stackflow/plugin-stack-persistence@734.tgz
    

commit: 8c88f65

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 22, 2026

Copy link
Copy Markdown

Deploying stackflow-demo with  Cloudflare Pages  Cloudflare Pages

Latest commit: 8c88f65
Status:⚡️  Build in progress...

View logs

@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Jul 22, 2026

Copy link
Copy Markdown

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 8c88f65 Commit Preview URL Jul 22 2026, 09:08 AM

@ENvironmentSet
ENvironmentSet marked this pull request as ready for review July 22, 2026 08:53
@ENvironmentSet
ENvironmentSet enabled auto-merge (squash) July 22, 2026 08:53

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@extensions/plugin-stack-persistence/src/composeStrategies.ts`:
- Around line 27-29: Update the metadata validation condition in the
record-matching logic to first verify that record.metadata is a non-null object
before calling Object.hasOwn; return false for nullish or non-object metadata,
while preserving the existing keys.every validation for valid metadata.

In `@extensions/plugin-stack-persistence/src/index.ts`:
- Around line 1-5: Remove the stale ComposedStrategyMetadata re-export from the
barrel export in index.ts, while preserving composeStrategies and
StrategiesMetadata exports. Do not add the missing type to composeStrategies.ts.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: b58e6a6a-9645-4322-b73b-f77b3ba13353

📥 Commits

Reviewing files that changed from the base of the PR and between bf5daae and 1c8aa4e.

📒 Files selected for processing (3)
  • .changeset/shaggy-foxes-compose.md
  • extensions/plugin-stack-persistence/src/composeStrategies.ts
  • extensions/plugin-stack-persistence/src/index.ts

Comment on lines +27 to +29
if (!keys.every((key) => Object.hasOwn(record.metadata, key))) {
return false;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline extensions/plugin-stack-persistence/src/composeStrategies.ts --view expanded || true
echo '---'
wc -l extensions/plugin-stack-persistence/src/composeStrategies.ts
echo '---'
cat -n extensions/plugin-stack-persistence/src/composeStrategies.ts

Repository: daangn/stackflow

Length of output: 1805


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' extensions/plugin-stack-persistence/src/StackSnapshotStrategy.ts
echo '---'
rg -n "metadata" extensions/plugin-stack-persistence/src -g '*.ts'

Repository: daangn/stackflow

Length of output: 1080


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,220p' extensions/plugin-stack-persistence/src/StackSnapshotRecord.ts
echo '---'
sed -n '1,260p' extensions/plugin-stack-persistence/src/stackPersistencePlugin.ts

Repository: daangn/stackflow

Length of output: 2457


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "composeStrategies" -g '*.ts' -g '*.tsx' .
echo '---'
sed -n '1,220p' extensions/plugin-stack-persistence/src/StackSnapshotStorage.ts

Repository: daangn/stackflow

Length of output: 645


🏁 Script executed:

#!/bin/bash
set -euo pipefail

node - <<'JS'
try {
  console.log(Object.hasOwn(null, 'a'));
} catch (e) {
  console.log(e.name + ': ' + e.message);
}
try {
  console.log(Object.hasOwn(undefined, 'a'));
} catch (e) {
  console.log(e.name + ': ' + e.message);
}
console.log(Object.hasOwn('abc', 'length'));
JS

echo '---'
rg -n "implements StackSnapshotStorage|StackSnapshotStorage<|load\(\): StackSnapshotRecord" extensions/plugin-stack-persistence -g '*.ts'

Repository: daangn/stackflow

Length of output: 613


🏁 Script executed:

#!/bin/bash
set -euo pipefail

fd -a -t f 'StackSnapshotStorage' extensions/plugin-stack-persistence src . || true
echo '---'
rg -n "save\(|load\(" extensions/plugin-stack-persistence -g '*.ts'
echo '---'
rg -n "localStorage|sessionStorage|JSON.stringify|JSON.parse|StackSnapshotRecord" extensions/plugin-stack-persistence -g '*.ts'

Repository: daangn/stackflow

Length of output: 2957


Guard nullish metadata before Object.hasOwn.
Legacy records with null or undefined metadata will throw here instead of returning false, turning a bad record into a load error. Add a null/object check before the key loop.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@extensions/plugin-stack-persistence/src/composeStrategies.ts` around lines 27
- 29, Update the metadata validation condition in the record-matching logic to
first verify that record.metadata is a non-null object before calling
Object.hasOwn; return false for nullish or non-object metadata, while preserving
the existing keys.every validation for valid metadata.

Comment thread extensions/plugin-stack-persistence/src/index.ts
Removed ComposedStrategyMetadata export from index.ts
@ENvironmentSet
ENvironmentSet merged commit 42639c0 into main Jul 22, 2026
7 of 9 checks passed
@ENvironmentSet
ENvironmentSet deleted the feature/fep-2611 branch July 22, 2026 09:06
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.

1 participant