Skip to content

@chargebee/entitlements and @chargebee/openfeature packages - #37

Open
cb-srinaths wants to merge 11 commits into
mainfrom
openfeature
Open

@chargebee/entitlements and @chargebee/openfeature packages#37
cb-srinaths wants to merge 11 commits into
mainfrom
openfeature

Conversation

@cb-srinaths

@cb-srinaths cb-srinaths commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds two workspace packages for Chargebee entitlements and OpenFeature integration:

  • @chargebee/entitlements is the framework-independent entitlement layer.
  • @chargebee/openfeature provides OpenFeature server and web provider adapters that use @chargebee/entitlements.

The previous description did not reflect the final package split.

@chargebee/entitlements

  • Add shared entitlement types, evaluation helpers, evaluation-context parsing, and versioned entitlement snapshots.
  • Add in-memory and Redis storage adapters with TTL support.
  • Add a server entitlement loader with customer and subscription targets, pagination controls, normalization, and optional customer consolidation.
  • Add snapshot lifecycle operations for read, refresh, write, delete, cache eviction, background refresh, refresh deduplication, and refresh backoff.
  • Add a server relay handler that derives identity on the server and rejects client-supplied billing identity keys.
  • Add a browser entitlement client that loads relay snapshots and handles snapshot lifecycle and context changes.
  • Add Next.js relay support.
  • Add package documentation, changelog, license, build configuration, and unit tests.

@chargebee/openfeature

  • Add ChargebeeEntitlementsProvider for the OpenFeature server SDK.
  • Add ChargebeeEntitlementsWebProvider for the OpenFeature web SDK.
  • Support boolean, string, number, and object entitlement evaluations.
  • Map entitlement evaluation results to OpenFeature resolution details.
  • Export the core package and the /server and /web entry points.
  • Publish as 0.1.0-alpha.1 with Node.js >=22.

Repository updates

  • Register both packages in the pnpm workspace and update the lockfile.
  • Update the root Node.js and pnpm requirements.
  • Update the CI Node.js matrix to test Node.js 22, 24, and 26.
  • Add TODO.md with follow-up work.

Test coverage

  • Add tests for cache behavior, snapshot parsing and evaluation, server loading and relay behavior, refresh behavior, OpenFeature provider behavior, and web client behavior.

Adds @chargebee/entitlements with server, browser, caching, snapshot, relay, evaluation, and Next.js support. Adds @chargebee/openfeature providers for server and web OpenFeature evaluations. Updates exports, documentation, tests, CI, workspace configuration, and Node.js 22+ requirements.

@snyk-io

snyk-io Bot commented Aug 11, 2026

Copy link
Copy Markdown

Snyk checks have passed. No issues have been found so far.

Status Scan Engine Critical High Medium Low Total (0)
Open Source Security 0 0 0 0 0 issues
Licenses 0 0 0 0 0 issues
Code Security 0 0 0 0 0 issues
Secrets 0 0 0 0 0 issues

💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • ✅ Review completed - (🔄 Check again to review again)
ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 1051067b-c0da-4ee0-9923-aad81bf8a922

📥 Commits

Reviewing files that changed from the base of the PR and between 54410e1 and b475596.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (47)
  • .github/workflows/ci.yml
  • TODO.md
  • package.json
  • packages/entitlements/CHANGELOG.md
  • packages/entitlements/LICENSE.md
  • packages/entitlements/README.md
  • packages/entitlements/package.json
  • packages/entitlements/src/cache/index.ts
  • packages/entitlements/src/cache/key.ts
  • packages/entitlements/src/cache/memory.ts
  • packages/entitlements/src/cache/redis.ts
  • packages/entitlements/src/cache/types.ts
  • packages/entitlements/src/index.ts
  • packages/entitlements/src/nextjs.ts
  • packages/entitlements/src/server/entitlements.ts
  • packages/entitlements/src/server/index.ts
  • packages/entitlements/src/server/loader.ts
  • packages/entitlements/src/server/relay.ts
  • packages/entitlements/src/shared/context.ts
  • packages/entitlements/src/shared/evaluation.ts
  • packages/entitlements/src/shared/index.ts
  • packages/entitlements/src/shared/snapshot.ts
  • packages/entitlements/src/shared/types.ts
  • packages/entitlements/src/web/client.ts
  • packages/entitlements/src/web/index.ts
  • packages/entitlements/test/cache.test.ts
  • packages/entitlements/test/server.test.ts
  • packages/entitlements/test/shared.test.ts
  • packages/entitlements/test/web.test.ts
  • packages/entitlements/tsconfig.json
  • packages/entitlements/tsdown.config.ts
  • packages/entitlements/vitest.config.ts
  • packages/openfeature/CHANGELOG.md
  • packages/openfeature/LICENSE.md
  • packages/openfeature/README.md
  • packages/openfeature/package.json
  • packages/openfeature/src/index.ts
  • packages/openfeature/src/server/index.ts
  • packages/openfeature/src/server/provider.ts
  • packages/openfeature/src/web/index.ts
  • packages/openfeature/src/web/provider.ts
  • packages/openfeature/test/server.test.ts
  • packages/openfeature/test/web.test.ts
  • packages/openfeature/tsconfig.json
  • packages/openfeature/tsdown.config.ts
  • packages/openfeature/vitest.config.ts
  • pnpm-workspace.yaml

Cache: Disabled due to Reviews > Disable Cache setting

Disabled knowledge base sources:

  • Jira integration is disabled

You can enable these sources in your CodeRabbit configuration.


Walkthrough

This change extracts framework-agnostic entitlement functionality into @chargebee/entitlements. It adds storage, server, relay, web, and OpenFeature integrations, with tests, documentation, package exports, and updated workspace tooling.

Changes

Entitlements and OpenFeature adapters

Layer / File(s) Summary
Shared contracts and evaluation
packages/entitlements/src/shared/*, packages/entitlements/src/index.ts, packages/entitlements/test/shared.test.ts
Adds shared entitlement types, context targeting, snapshot validation and serialization, expiration checks, and typed resolution.
Entitlement storage adapters
packages/entitlements/src/cache/*, packages/entitlements/test/cache.test.ts
Adds namespaced keys, memory and Redis storage, TTL handling, corrupt-value removal, and storage tests.
Server loading and snapshot lifecycle
packages/entitlements/src/server/entitlements.ts, packages/entitlements/src/server/loader.ts, packages/entitlements/test/server.test.ts
Adds Chargebee loading, cache/store fallback, refresh coordination, persistence, lifecycle operations, and typed evaluations.
Authenticated relay integration
packages/entitlements/src/server/relay.ts, packages/entitlements/src/nextjs.ts, packages/entitlements/test/server.test.ts
Adds a generic GET-only relay handler with server-derived identity, billing-identity protection, private cache headers, and a Next.js adapter.
Browser client and OpenFeature providers
packages/entitlements/src/web/*, packages/openfeature/src/server/*, packages/openfeature/src/web/*, packages/openfeature/test/*
Adds browser snapshot loading and lifecycle handling, then adapts server and web clients to OpenFeature evaluations and provider events.
Package distribution and documentation
packages/entitlements/package.json, packages/openfeature/package.json, packages/*/README.md, packages/*/CHANGELOG.md, packages/*/*config*, pnpm-workspace.yaml, package.json, .github/workflows/ci.yml
Adds package metadata, exports, builds, tests, documentation, licenses, workspace links, Node.js 22 and pnpm 11 requirements, and updated CI versions.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant OpenFeature
  participant ChargebeeEntitlementsProvider
  participant ChargebeeEntitlements
  participant EntitlementsStorage
  participant Chargebee
  OpenFeature->>ChargebeeEntitlementsProvider: resolve typed entitlement
  ChargebeeEntitlementsProvider->>ChargebeeEntitlements: evaluate target and flag
  ChargebeeEntitlements->>EntitlementsStorage: read snapshot
  EntitlementsStorage-->>ChargebeeEntitlements: return snapshot or miss
  ChargebeeEntitlements->>Chargebee: load entitlements on miss
  Chargebee-->>ChargebeeEntitlements: return normalized entitlements
  ChargebeeEntitlements->>EntitlementsStorage: persist snapshot
  ChargebeeEntitlements-->>ChargebeeEntitlementsProvider: return resolution details
  ChargebeeEntitlementsProvider-->>OpenFeature: return typed evaluation
Loading
🚥 Pre-merge checks | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 15.56% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.

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

@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 `@packages/openfeature/src/cache/tiered.ts`:
- Around line 42-52: Separate the memory hydration call from the Redis error
boundary in the cache lookup flow, likely within the surrounding tiered-cache
method. Catch failures from memory.set independently, report them through
onError with the "memory" source, and still return the valid Redis snapshot with
source "redis"; reserve the existing Redis error handling for Redis operation
failures.

In `@packages/openfeature/src/web/provider.ts`:
- Around line 149-170: Update getUsableSnapshot to trigger a background refresh
when isSnapshotExpired detects an expired snapshot, reusing the provider’s
existing refreshSnapshot mechanism. Preserve the current stale fallback and
single ProviderEvents.Stale emission, while preventing concurrent refreshes from
starting on repeated expired-snapshot reads.
🪄 Autofix

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 356b1eea-daf6-4f58-9c82-76a16c9aa9f7

📥 Commits

Reviewing files that changed from the base of the PR and between 54410e1 and f124d7a.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (31)
  • packages/openfeature/CHANGELOG.md
  • packages/openfeature/LICENSE.md
  • packages/openfeature/README.md
  • packages/openfeature/package.json
  • packages/openfeature/src/cache.ts
  • packages/openfeature/src/cache/key.ts
  • packages/openfeature/src/cache/memory.ts
  • packages/openfeature/src/cache/redis.ts
  • packages/openfeature/src/cache/tiered.ts
  • packages/openfeature/src/cache/types.ts
  • packages/openfeature/src/index.ts
  • packages/openfeature/src/nextjs.ts
  • packages/openfeature/src/server.ts
  • packages/openfeature/src/server/loader.ts
  • packages/openfeature/src/server/provider.ts
  • packages/openfeature/src/server/relay.ts
  • packages/openfeature/src/shared.ts
  • packages/openfeature/src/shared/context.ts
  • packages/openfeature/src/shared/evaluation.ts
  • packages/openfeature/src/shared/snapshot.ts
  • packages/openfeature/src/shared/types.ts
  • packages/openfeature/src/web.ts
  • packages/openfeature/src/web/provider.ts
  • packages/openfeature/test/cache.test.ts
  • packages/openfeature/test/server.test.ts
  • packages/openfeature/test/shared.test.ts
  • packages/openfeature/test/web.test.ts
  • packages/openfeature/tsconfig.json
  • packages/openfeature/tsdown.config.ts
  • packages/openfeature/vitest.config.ts
  • pnpm-workspace.yaml

Comment thread packages/openfeature/src/cache/tiered-cache.ts Outdated
Comment thread packages/openfeature/src/web/provider.ts Outdated
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Fixes Applied Successfully

Fixed 2 file(s) based on 2 unresolved review comments.

Files modified:

  • packages/openfeature/src/cache/tiered.ts
  • packages/openfeature/src/web/provider.ts

Commit: d1550ec54e7909f74f4c22aaef2d4a5fdc9808cf

The changes have been pushed to the openfeature branch.

Time taken: 3m 10s

coderabbitai Bot and others added 2 commits August 11, 2026 07:09
Fixed 2 file(s) based on 2 unresolved review comments.

Co-authored-by: CodeRabbit <noreply@coderabbit.ai>

@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: 1

🤖 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 `@package.json`:
- Line 10: Update the root package.json engines.node declaration to require
Node.js >=22, aligning it with the declared pnpm@11.21.0 packageManager and
existing CI/release runtime versions.
🪄 Autofix

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: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 0e38dfb4-5b6d-453b-8f78-aa98df7e3dbc

📥 Commits

Reviewing files that changed from the base of the PR and between fd25a99 and 1011a98.

📒 Files selected for processing (3)
  • package.json
  • packages/openfeature/src/web/provider.ts
  • pnpm-workspace.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/openfeature/src/web/provider.ts

Comment thread package.json

@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 `@packages/openfeature/CHANGELOG.md`:
- Around line 5-6: Update the changelog entry describing the server provider’s
cache and store slots by replacing the removed EntitlementsCache type name with
EntitlementsStorage, matching the documented public API rename while preserving
the rest of the entry.

In `@packages/openfeature/src/server/provider.ts`:
- Around line 423-450: Update scheduleRefresh to expire stale failedAt entries
when read: if a recorded failure is older than refreshBackoffMs, delete failedAt
for the key before proceeding with the refresh. Preserve the existing early
return while the backoff window is active, and continue calling
fetchAndPersistSnapshot for expired or missing entries.
🪄 Autofix

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: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: d6d5126e-473b-450c-98c1-71ba10384520

📥 Commits

Reviewing files that changed from the base of the PR and between b43d86f and 79a1b9b.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (22)
  • package.json
  • packages/openfeature/CHANGELOG.md
  • packages/openfeature/README.md
  • packages/openfeature/package.json
  • packages/openfeature/src/cache/index.ts
  • packages/openfeature/src/cache/memory.ts
  • packages/openfeature/src/cache/redis.ts
  • packages/openfeature/src/cache/types.ts
  • packages/openfeature/src/index.ts
  • packages/openfeature/src/nextjs.ts
  • packages/openfeature/src/server/index.ts
  • packages/openfeature/src/server/provider.ts
  • packages/openfeature/src/server/relay.ts
  • packages/openfeature/src/shared/evaluation.ts
  • packages/openfeature/src/shared/index.ts
  • packages/openfeature/src/shared/types.ts
  • packages/openfeature/src/web/index.ts
  • packages/openfeature/src/web/provider.ts
  • packages/openfeature/test/cache.test.ts
  • packages/openfeature/test/server.test.ts
  • packages/openfeature/test/shared.test.ts
  • packages/openfeature/tsdown.config.ts
🚧 Files skipped from review as they are similar to previous changes (7)
  • package.json
  • packages/openfeature/src/index.ts
  • packages/openfeature/tsdown.config.ts
  • packages/openfeature/README.md
  • packages/openfeature/package.json
  • packages/openfeature/src/web/provider.ts
  • packages/openfeature/test/shared.test.ts

Comment thread packages/openfeature/CHANGELOG.md
Comment thread packages/openfeature/src/server/provider.ts Outdated
@cb-srinaths cb-srinaths changed the title @chargebee/openfeature package @chargebee/entitlements and @chargebee/openfeature packages Aug 12, 2026
@cb-srinaths

Copy link
Copy Markdown
Contributor Author

@coderabbitai update the PR description and the walkthrough since contents have changed considerably.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Pull request metadata and current body ---'
gh pr view 37 --repo chargebee/js-framework-adapters \
  --json title,body,baseRefName,headRefName,commits,files \
  --jq '{title, baseRefName, headRefName, body, commits: [.commits[] | {oid, messageHeadline}], files: [.files[] | {path, additions, deletions}] }'

printf '%s\n' '--- Change summary against main ---'
git diff --stat origin/main...HEAD

printf '%s\n' '--- Public module outlines ---'
for f in \
  packages/openfeature/src/server/provider.ts \
  packages/openfeature/src/server/relay.ts \
  packages/openfeature/src/web/provider.ts \
  packages/openfeature/src/cache/tiered.ts \
  packages/openfeature/src/cache/index.ts \
  packages/openfeature/src/index.ts \
  packages/openfeature/src/nextjs.ts
do
  if [ -f "$f" ]; then
    printf '\n--- %s ---\n' "$f"
    ast-grep outline "$f" --items all || true
  fi
done

printf '%s\n' '--- Current package scripts and exports ---'
jq '{name, version, engines, exports, scripts, dependencies, peerDependencies}' packages/openfeature/package.json

Length of output: 11948


🏁 Script executed:

#!/bin/bash
set -euo pipefail

body_file="$(mktemp)"
trap 'rm -f "$body_file"' EXIT

cat >"$body_file" <<'EOF'
## Summary

This PR adds two workspace packages for Chargebee entitlements and OpenFeature integration:

- `@chargebee/entitlements` is the framework-independent entitlement layer.
- `@chargebee/openfeature` provides OpenFeature server and web provider adapters that use `@chargebee/entitlements`.

The previous description did not reflect the final package split.

## `@chargebee/entitlements`

- Add shared entitlement types, evaluation helpers, evaluation-context parsing, and versioned entitlement snapshots.
- Add in-memory and Redis storage adapters with TTL support.
- Add a server entitlement loader with customer and subscription targets, pagination controls, normalization, and optional customer consolidation.
- Add snapshot lifecycle operations for read, refresh, write, delete, cache eviction, background refresh, refresh deduplication, and refresh backoff.
- Add a server relay handler that derives identity on the server and rejects client-supplied billing identity keys.
- Add a browser entitlement client that loads relay snapshots and handles snapshot lifecycle and context changes.
- Add Next.js relay support.
- Add package documentation, changelog, license, build configuration, and unit tests.

## `@chargebee/openfeature`

- Add `ChargebeeEntitlementsProvider` for the OpenFeature server SDK.
- Add `ChargebeeEntitlementsWebProvider` for the OpenFeature web SDK.
- Support boolean, string, number, and object entitlement evaluations.
- Map entitlement evaluation results to OpenFeature resolution details.
- Export the core package and the `/server` and `/web` entry points.
- Publish as `0.1.0-alpha.1` with Node.js `>=22`.

## Repository updates

- Register both packages in the pnpm workspace and update the lockfile.
- Update the root Node.js and pnpm requirements.
- Update the CI Node.js matrix to test Node.js 22, 24, and 26.
- Add `TODO.md` with follow-up work.

## Test coverage

- Add tests for cache behavior, snapshot parsing and evaluation, server loading and relay behavior, refresh behavior, OpenFeature provider behavior, and web client behavior.
EOF

gh pr edit 37 \
  --repo chargebee/js-framework-adapters \
  --body-file "$body_file"

Length of output: 2891


🏁 Script executed:

#!/bin/bash
set -euo pipefail

body_file="$(mktemp)"
saved_body_file="$(mktemp)"
trap 'rm -f "$body_file" "$saved_body_file"' EXIT

cat >"$body_file" <<'EOF'
## Summary

This PR adds two workspace packages for Chargebee entitlements and OpenFeature integration:

- `@chargebee/entitlements` is the framework-independent entitlement layer.
- `@chargebee/openfeature` provides OpenFeature server and web provider adapters that use `@chargebee/entitlements`.

The previous description did not reflect the final package split.

## `@chargebee/entitlements`

- Add shared entitlement types, evaluation helpers, evaluation-context parsing, and versioned entitlement snapshots.
- Add in-memory and Redis storage adapters with TTL support.
- Add a server entitlement loader with customer and subscription targets, pagination controls, normalization, and optional customer consolidation.
- Add snapshot lifecycle operations for read, refresh, write, delete, cache eviction, background refresh, refresh deduplication, and refresh backoff.
- Add a server relay handler that derives identity on the server and rejects client-supplied billing identity keys.
- Add a browser entitlement client that loads relay snapshots and handles snapshot lifecycle and context changes.
- Add Next.js relay support.
- Add package documentation, changelog, license, build configuration, and unit tests.

## `@chargebee/openfeature`

- Add `ChargebeeEntitlementsProvider` for the OpenFeature server SDK.
- Add `ChargebeeEntitlementsWebProvider` for the OpenFeature web SDK.
- Support boolean, string, number, and object entitlement evaluations.
- Map entitlement evaluation results to OpenFeature resolution details.
- Export the core package and the `/server` and `/web` entry points.
- Publish as `0.1.0-alpha.1` with Node.js `>=22`.

## Repository updates

- Register both packages in the pnpm workspace and update the lockfile.
- Update the root Node.js and pnpm requirements.
- Update the CI Node.js matrix to test Node.js 22, 24, and 26.
- Add `TODO.md` with follow-up work.

## Test coverage

- Add tests for cache behavior, snapshot parsing and evaluation, server loading and relay behavior, refresh behavior, OpenFeature provider behavior, and web client behavior.
EOF

gh api \
  --method PATCH \
  "repos/chargebee/js-framework-adapters/pulls/37" \
  --input "$body_file" \
  --header "Content-Type: application/json" \
  >/dev/null

gh api "repos/chargebee/js-framework-adapters/pulls/37" --jq '.body' >"$saved_body_file"
diff -u "$body_file" "$saved_body_file"
printf '%s\n' 'PR description updated and verified.'

Length of output: 2941


🏁 Script executed:

#!/bin/bash
set -euo pipefail

body_file="$(mktemp)"
saved_body_file="$(mktemp)"
payload_file="$(mktemp)"
trap 'rm -f "$body_file" "$saved_body_file" "$payload_file"' EXIT

cat >"$body_file" <<'EOF'
## Summary

This PR adds two workspace packages for Chargebee entitlements and OpenFeature integration:

- `@chargebee/entitlements` is the framework-independent entitlement layer.
- `@chargebee/openfeature` provides OpenFeature server and web provider adapters that use `@chargebee/entitlements`.

The previous description did not reflect the final package split.

## `@chargebee/entitlements`

- Add shared entitlement types, evaluation helpers, evaluation-context parsing, and versioned entitlement snapshots.
- Add in-memory and Redis storage adapters with TTL support.
- Add a server entitlement loader with customer and subscription targets, pagination controls, normalization, and optional customer consolidation.
- Add snapshot lifecycle operations for read, refresh, write, delete, cache eviction, background refresh, refresh deduplication, and refresh backoff.
- Add a server relay handler that derives identity on the server and rejects client-supplied billing identity keys.
- Add a browser entitlement client that loads relay snapshots and handles snapshot lifecycle and context changes.
- Add Next.js relay support.
- Add package documentation, changelog, license, build configuration, and unit tests.

## `@chargebee/openfeature`

- Add `ChargebeeEntitlementsProvider` for the OpenFeature server SDK.
- Add `ChargebeeEntitlementsWebProvider` for the OpenFeature web SDK.
- Support boolean, string, number, and object entitlement evaluations.
- Map entitlement evaluation results to OpenFeature resolution details.
- Export the core package and the `/server` and `/web` entry points.
- Publish as `0.1.0-alpha.1` with Node.js `>=22`.

## Repository updates

- Register both packages in the pnpm workspace and update the lockfile.
- Update the root Node.js and pnpm requirements.
- Update the CI Node.js matrix to test Node.js 22, 24, and 26.
- Add `TODO.md` with follow-up work.

## Test coverage

- Add tests for cache behavior, snapshot parsing and evaluation, server loading and relay behavior, refresh behavior, OpenFeature provider behavior, and web client behavior.
EOF

jq -Rs '{body: .}' "$body_file" >"$payload_file"

gh api \
  --method PATCH \
  "repos/chargebee/js-framework-adapters/pulls/37" \
  --input "$payload_file" \
  >/dev/null

gh api "repos/chargebee/js-framework-adapters/pulls/37" --jq '.body' >"$saved_body_file"
diff -u "$body_file" "$saved_body_file"
printf '%s\n' 'PR description updated and verified.'

Length of output: 3287


@cb-srinaths, I updated the PR description. Verification shows that GitHub added only a trailing newline. The walkthrough regeneration is requested for the current diff.

✅ Action performed

Summary regeneration triggered.

@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: 4

♻️ Duplicate comments (1)
packages/openfeature/CHANGELOG.md (1)

27-28: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Replace the removed EntitlementsCache name.

EntitlementsCache was renamed to EntitlementsStorage at Lines 44-45. Keeping it here directs users to implement a removed public type. Change this entry to EntitlementsStorage.

As per path instructions, this is a functionality-breaking documentation error.

🤖 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 `@packages/openfeature/CHANGELOG.md` around lines 27 - 28, Update the changelog
entry describing the server provider’s cache and store slots to replace the
removed EntitlementsCache name with EntitlementsStorage, matching the renamed
public type referenced elsewhere in the changelog.

Source: Path instructions

🤖 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 `@packages/entitlements/README.md`:
- Around line 195-197: Update the onError logging example to stop including the
identifying target object; remove target from the logger.error context or
replace it with a non-identifying redacted value while preserving the error and
operation details.

In `@packages/entitlements/src/shared/evaluation.ts`:
- Around line 199-210: Update resolveObjectEntitlement so it never casts the
ChargebeeEntitlement envelope directly to arbitrary T. Decode and validate a
concrete object payload before returning value, preserving the expected object
shape; if object payloads are not modeled, return the existing TYPE_MISMATCH
resolution instead.

In `@packages/entitlements/src/web/client.ts`:
- Around line 177-197: Update loadSnapshot to re-check this.closed immediately
after fetchImplementation resolves and before parsing or assigning the snapshot.
If the client was closed during the request, abort the update and preserve
close()’s cleared state; retain the existing behavior for requests completed
while the client remains open.
- Around line 156-175: Update the expired-snapshot refresh flow around
refreshInProgress and refreshSnapshot to record the timestamp of the last
refresh attempt and skip starting another refresh until the configured minimum
backoff interval has elapsed. Preserve the existing stale return and event
behavior while ensuring repeated evaluations do not issue more than one refresh
request within that interval.

---

Duplicate comments:
In `@packages/openfeature/CHANGELOG.md`:
- Around line 27-28: Update the changelog entry describing the server provider’s
cache and store slots to replace the removed EntitlementsCache name with
EntitlementsStorage, matching the renamed public type referenced elsewhere in
the changelog.
🪄 Autofix

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: Organization UI

Review profile: CHILL

Plan: Enterprise

Run ID: 9af351b5-7583-4893-95ec-23ad5c934a85

📥 Commits

Reviewing files that changed from the base of the PR and between 79a1b9b and b475596.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (43)
  • TODO.md
  • packages/entitlements/CHANGELOG.md
  • packages/entitlements/LICENSE.md
  • packages/entitlements/README.md
  • packages/entitlements/package.json
  • packages/entitlements/src/cache/index.ts
  • packages/entitlements/src/cache/key.ts
  • packages/entitlements/src/cache/memory.ts
  • packages/entitlements/src/cache/redis.ts
  • packages/entitlements/src/cache/types.ts
  • packages/entitlements/src/index.ts
  • packages/entitlements/src/nextjs.ts
  • packages/entitlements/src/server/entitlements.ts
  • packages/entitlements/src/server/index.ts
  • packages/entitlements/src/server/loader.ts
  • packages/entitlements/src/server/relay.ts
  • packages/entitlements/src/shared/context.ts
  • packages/entitlements/src/shared/evaluation.ts
  • packages/entitlements/src/shared/index.ts
  • packages/entitlements/src/shared/snapshot.ts
  • packages/entitlements/src/shared/types.ts
  • packages/entitlements/src/web/client.ts
  • packages/entitlements/src/web/index.ts
  • packages/entitlements/test/cache.test.ts
  • packages/entitlements/test/server.test.ts
  • packages/entitlements/test/shared.test.ts
  • packages/entitlements/test/web.test.ts
  • packages/entitlements/tsconfig.json
  • packages/entitlements/tsdown.config.ts
  • packages/entitlements/vitest.config.ts
  • packages/openfeature/CHANGELOG.md
  • packages/openfeature/README.md
  • packages/openfeature/package.json
  • packages/openfeature/src/index.ts
  • packages/openfeature/src/server/index.ts
  • packages/openfeature/src/server/provider.ts
  • packages/openfeature/src/web/provider.ts
  • packages/openfeature/test/server.test.ts
  • packages/openfeature/test/web.test.ts
  • packages/openfeature/tsconfig.json
  • packages/openfeature/tsdown.config.ts
  • packages/openfeature/vitest.config.ts
  • pnpm-workspace.yaml
💤 Files with no reviewable changes (1)
  • packages/openfeature/src/server/index.ts
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/openfeature/tsconfig.json
  • packages/openfeature/test/web.test.ts
  • packages/openfeature/vitest.config.ts

Comment on lines +195 to +197
onError: (error, { operation, target }) => {
logger.error({ error, operation, target }, "entitlement snapshot");
},

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

Redact target before logging.

target can contain chargebeeCustomerId or subscriptionId. This example logs it for every onError event and can expose billing identifiers in application logs. Remove target or log a redacted, non-identifying value.

As per path instructions, this comment flags a security or privacy risk that must be resolved before merge.

🤖 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 `@packages/entitlements/README.md` around lines 195 - 197, Update the onError
logging example to stop including the identifying target object; remove target
from the logger.error context or replace it with a non-identifying redacted
value while preserving the error and operation details.

Source: Path instructions

Comment on lines +199 to +210
export function resolveObjectEntitlement<T>(
snapshot: ChargebeeEntitlementsSnapshot,
flagKey: string,
defaultValue: T,
source: SnapshotSource,
): EntitlementResolution<T> {
const found = getEnabled(snapshot, flagKey, defaultValue, source);
if (!("entitlement" in found)) return found;

return {
value: found.entitlement as unknown as T,
variant: found.entitlement.value ?? "enabled",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Return a valid object value or reject object evaluation.

Line 209 casts a ChargebeeEntitlement to arbitrary T. A call such as getObjectValue<{ limit: number }>() returns the entitlement envelope, not an object with limit. Decode and validate an object payload, or return TYPE_MISMATCH until object payloads are modeled.

🤖 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 `@packages/entitlements/src/shared/evaluation.ts` around lines 199 - 210,
Update resolveObjectEntitlement so it never casts the ChargebeeEntitlement
envelope directly to arbitrary T. Decode and validate a concrete object payload
before returning value, preserving the expected object shape; if object payloads
are not modeled, return the existing TYPE_MISMATCH resolution instead.

Source: Path instructions

Comment on lines +156 to +175
if (!isSnapshotExpired(this.snapshot)) return this.snapshot;

if (!this.staleEventEmitted) {
this.onStale?.();
this.staleEventEmitted = true;
}

if (!this.refreshInProgress && !this.closed) {
this.refreshInProgress = true;
this.refreshSnapshot()
.catch(() => {
// Errors are already handled in loadSnapshot
})
.finally(() => {
this.refreshInProgress = false;
});
}

return { value: defaultValue, reason: "STALE" };
}

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 | 🟠 Major | ⚡ Quick win

Add a backoff for expired-snapshot refreshes.

If the relay keeps returning an already-expired snapshot, every evaluation starts a new fetch. loadSnapshot also resets staleEventEmitted to false on success, so onStale fires again on the next evaluation. The result is one relay request and one stale event per flag read, with no upper bound. The server provider guards this with refreshBackoffMs; the web client has no equivalent.

Record the last refresh attempt and skip refreshes inside a minimum interval.

🧯 Proposed fix: minimum refresh interval
 	private refreshInProgress = false;
+	private lastRefreshAt = 0;
@@
-		if (!this.refreshInProgress && !this.closed) {
+		if (
+			!this.refreshInProgress &&
+			!this.closed &&
+			Date.now() - this.lastRefreshAt >= this.refreshBackoffMs
+		) {
 			this.refreshInProgress = true;
+			this.lastRefreshAt = Date.now();
 			this.refreshSnapshot()
🤖 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 `@packages/entitlements/src/web/client.ts` around lines 156 - 175, Update the
expired-snapshot refresh flow around refreshInProgress and refreshSnapshot to
record the timestamp of the last refresh attempt and skip starting another
refresh until the configured minimum backoff interval has elapsed. Preserve the
existing stale return and event behavior while ensuring repeated evaluations do
not issue more than one refresh request within that interval.

Comment on lines +177 to +197
private async loadSnapshot(emitChange: boolean): Promise<void> {
if (this.closed) throw new Error("Chargebee web client is closed");

try {
const headers = new Headers(this.requestHeaders);
if (!headers.has("Accept")) headers.set("Accept", "application/json");
const response = await this.fetchImplementation(this.relayUrl, {
method: "GET",
cache: "no-store",
credentials: this.credentials,
headers,
});
if (!response.ok) {
throw new Error(
`Chargebee entitlement relay returned HTTP ${response.status}`,
);
}

const nextSnapshot = parseEntitlementsSnapshot(await response.json());
const flagsChanged = changedFlags(this.snapshot, nextSnapshot);
this.snapshot = nextSnapshot;

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 | 🟠 Major | ⚡ Quick win

Re-check closed after the fetch resolves.

loadSnapshot tests this.closed only before the request. If close() runs while the request is in flight, the resolved snapshot is still assigned, so a closed client serves entitlements again and close() no longer clears state.

🔒 Proposed fix
 			const nextSnapshot = parseEntitlementsSnapshot(await response.json());
+			if (this.closed) return;
 			const flagsChanged = changedFlags(this.snapshot, nextSnapshot);
📝 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
private async loadSnapshot(emitChange: boolean): Promise<void> {
if (this.closed) throw new Error("Chargebee web client is closed");
try {
const headers = new Headers(this.requestHeaders);
if (!headers.has("Accept")) headers.set("Accept", "application/json");
const response = await this.fetchImplementation(this.relayUrl, {
method: "GET",
cache: "no-store",
credentials: this.credentials,
headers,
});
if (!response.ok) {
throw new Error(
`Chargebee entitlement relay returned HTTP ${response.status}`,
);
}
const nextSnapshot = parseEntitlementsSnapshot(await response.json());
const flagsChanged = changedFlags(this.snapshot, nextSnapshot);
this.snapshot = nextSnapshot;
private async loadSnapshot(emitChange: boolean): Promise<void> {
if (this.closed) throw new Error("Chargebee web client is closed");
try {
const headers = new Headers(this.requestHeaders);
if (!headers.has("Accept")) headers.set("Accept", "application/json");
const response = await this.fetchImplementation(this.relayUrl, {
method: "GET",
cache: "no-store",
credentials: this.credentials,
headers,
});
if (!response.ok) {
throw new Error(
`Chargebee entitlement relay returned HTTP ${response.status}`,
);
}
const nextSnapshot = parseEntitlementsSnapshot(await response.json());
if (this.closed) return;
const flagsChanged = changedFlags(this.snapshot, nextSnapshot);
this.snapshot = nextSnapshot;
🤖 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 `@packages/entitlements/src/web/client.ts` around lines 177 - 197, Update
loadSnapshot to re-check this.closed immediately after fetchImplementation
resolves and before parsing or assigning the snapshot. If the client was closed
during the request, abort the update and preserve close()’s cleared state;
retain the existing behavior for requests completed while the client remains
open.

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