@chargebee/entitlements and @chargebee/openfeature packages - #37
@chargebee/entitlements and @chargebee/openfeature packages#37cb-srinaths wants to merge 11 commits into
@chargebee/entitlements and @chargebee/openfeature packages#37Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Enterprise Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (47)
Cache: Disabled due to Reviews > Disable Cache setting Disabled knowledge base sources:
WalkthroughThis change extracts framework-agnostic entitlement functionality into ChangesEntitlements and OpenFeature adapters
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
🚥 Pre-merge checks | ❌ 1❌ Failed checks (1 warning)
Comment |
There was a problem hiding this comment.
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
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (31)
packages/openfeature/CHANGELOG.mdpackages/openfeature/LICENSE.mdpackages/openfeature/README.mdpackages/openfeature/package.jsonpackages/openfeature/src/cache.tspackages/openfeature/src/cache/key.tspackages/openfeature/src/cache/memory.tspackages/openfeature/src/cache/redis.tspackages/openfeature/src/cache/tiered.tspackages/openfeature/src/cache/types.tspackages/openfeature/src/index.tspackages/openfeature/src/nextjs.tspackages/openfeature/src/server.tspackages/openfeature/src/server/loader.tspackages/openfeature/src/server/provider.tspackages/openfeature/src/server/relay.tspackages/openfeature/src/shared.tspackages/openfeature/src/shared/context.tspackages/openfeature/src/shared/evaluation.tspackages/openfeature/src/shared/snapshot.tspackages/openfeature/src/shared/types.tspackages/openfeature/src/web.tspackages/openfeature/src/web/provider.tspackages/openfeature/test/cache.test.tspackages/openfeature/test/server.test.tspackages/openfeature/test/shared.test.tspackages/openfeature/test/web.test.tspackages/openfeature/tsconfig.jsonpackages/openfeature/tsdown.config.tspackages/openfeature/vitest.config.tspnpm-workspace.yaml
Fixes Applied SuccessfullyFixed 2 file(s) based on 2 unresolved review comments. Files modified:
Commit: The changes have been pushed to the Time taken: |
Fixed 2 file(s) based on 2 unresolved review comments. Co-authored-by: CodeRabbit <noreply@coderabbit.ai>
There was a problem hiding this comment.
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
📒 Files selected for processing (3)
package.jsonpackages/openfeature/src/web/provider.tspnpm-workspace.yaml
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/openfeature/src/web/provider.ts
There was a problem hiding this comment.
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
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (22)
package.jsonpackages/openfeature/CHANGELOG.mdpackages/openfeature/README.mdpackages/openfeature/package.jsonpackages/openfeature/src/cache/index.tspackages/openfeature/src/cache/memory.tspackages/openfeature/src/cache/redis.tspackages/openfeature/src/cache/types.tspackages/openfeature/src/index.tspackages/openfeature/src/nextjs.tspackages/openfeature/src/server/index.tspackages/openfeature/src/server/provider.tspackages/openfeature/src/server/relay.tspackages/openfeature/src/shared/evaluation.tspackages/openfeature/src/shared/index.tspackages/openfeature/src/shared/types.tspackages/openfeature/src/web/index.tspackages/openfeature/src/web/provider.tspackages/openfeature/test/cache.test.tspackages/openfeature/test/server.test.tspackages/openfeature/test/shared.test.tspackages/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
@chargebee/openfeature package@chargebee/entitlements and @chargebee/openfeature packages
|
@coderabbitai update the PR description and the walkthrough since contents have changed considerably. |
🧩 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.jsonLength 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
✅ Action performedSummary regeneration triggered. |
There was a problem hiding this comment.
Actionable comments posted: 4
♻️ Duplicate comments (1)
packages/openfeature/CHANGELOG.md (1)
27-28: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick winReplace the removed
EntitlementsCachename.
EntitlementsCachewas renamed toEntitlementsStorageat Lines 44-45. Keeping it here directs users to implement a removed public type. Change this entry toEntitlementsStorage.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
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (43)
TODO.mdpackages/entitlements/CHANGELOG.mdpackages/entitlements/LICENSE.mdpackages/entitlements/README.mdpackages/entitlements/package.jsonpackages/entitlements/src/cache/index.tspackages/entitlements/src/cache/key.tspackages/entitlements/src/cache/memory.tspackages/entitlements/src/cache/redis.tspackages/entitlements/src/cache/types.tspackages/entitlements/src/index.tspackages/entitlements/src/nextjs.tspackages/entitlements/src/server/entitlements.tspackages/entitlements/src/server/index.tspackages/entitlements/src/server/loader.tspackages/entitlements/src/server/relay.tspackages/entitlements/src/shared/context.tspackages/entitlements/src/shared/evaluation.tspackages/entitlements/src/shared/index.tspackages/entitlements/src/shared/snapshot.tspackages/entitlements/src/shared/types.tspackages/entitlements/src/web/client.tspackages/entitlements/src/web/index.tspackages/entitlements/test/cache.test.tspackages/entitlements/test/server.test.tspackages/entitlements/test/shared.test.tspackages/entitlements/test/web.test.tspackages/entitlements/tsconfig.jsonpackages/entitlements/tsdown.config.tspackages/entitlements/vitest.config.tspackages/openfeature/CHANGELOG.mdpackages/openfeature/README.mdpackages/openfeature/package.jsonpackages/openfeature/src/index.tspackages/openfeature/src/server/index.tspackages/openfeature/src/server/provider.tspackages/openfeature/src/web/provider.tspackages/openfeature/test/server.test.tspackages/openfeature/test/web.test.tspackages/openfeature/tsconfig.jsonpackages/openfeature/tsdown.config.tspackages/openfeature/vitest.config.tspnpm-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
| onError: (error, { operation, target }) => { | ||
| logger.error({ error, operation, target }, "entitlement snapshot"); | ||
| }, |
There was a problem hiding this comment.
🔒 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
| 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", |
There was a problem hiding this comment.
🎯 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
| 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" }; | ||
| } |
There was a problem hiding this comment.
🩺 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.
| 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; |
There was a problem hiding this comment.
🩺 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.
| 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.
Summary
This PR adds two workspace packages for Chargebee entitlements and OpenFeature integration:
@chargebee/entitlementsis the framework-independent entitlement layer.@chargebee/openfeatureprovides OpenFeature server and web provider adapters that use@chargebee/entitlements.The previous description did not reflect the final package split.
@chargebee/entitlements@chargebee/openfeatureChargebeeEntitlementsProviderfor the OpenFeature server SDK.ChargebeeEntitlementsWebProviderfor the OpenFeature web SDK./serverand/webentry points.0.1.0-alpha.1with Node.js>=22.Repository updates
TODO.mdwith follow-up work.Test coverage
Adds
@chargebee/entitlementswith server, browser, caching, snapshot, relay, evaluation, and Next.js support. Adds@chargebee/openfeatureproviders for server and web OpenFeature evaluations. Updates exports, documentation, tests, CI, workspace configuration, and Node.js 22+ requirements.