updated sdk version to v0.16.2#14
Conversation
📝 WalkthroughWalkthroughThe pull request updates example projects to use Flowglad SDK v0.16.2 by removing local Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Client UI
participant SDK as useBilling SDK
participant Flowglad as Flowglad API
Client->>SDK: billing.createUsageEvent({usageMeterSlug, amount})
SDK->>Flowglad: Create usage event request (auth handled by SDK)
Flowglad-->>SDK: Result (success | error payload)
SDK-->>Client: { error? , data? }
Client->>Client: handle result (reload billing / show error)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~28 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
00c3e21 to
7bb0152
Compare
There was a problem hiding this comment.
Actionable comments posted: 4
🤖 Fix all issues with AI agents
In @nextjs/generation-based-subscription/src/app/home-client.tsx:
- Around line 221-231: The call to billing.createUsageEvent in this handler
lacks the same undefined guard used in handleGenerateFastImage; before invoking
billing.createUsageEvent (and before using amount/transactionId), check that
billing.createUsageEvent is a function and return or throw early if it's
undefined, mirroring the guard in handleGenerateFastImage so you avoid runtime
errors when createUsageEvent is not provided.
In @tanstack-start/generation-based-subscription/src/routes/index.tsx:
- Around line 178-194: The fast image generation path calls
billing.createUsageEvent without a transactionId, risking duplicate usage events
on retries; update the fast generation handler (where billing.createUsageEvent
is invoked) to generate a unique transactionId (e.g., crypto.randomUUID() or
existing helper used by the HD video handler) and include transactionId in the
createUsageEvent payload, ensuring types align with the billing.createUsageEvent
signature and matching the approach used in the HD video handler to guarantee
idempotency.
- Around line 231-242: Add the same defensive guard used in the fast image
handler before calling billing.createUsageEvent: check that
billing.createUsageEvent is defined (e.g., if (billing?.createUsageEvent)) and
only call it when present; if it's absent, skip the call or handle the fallback
accordingly, then keep the existing result/error handling logic for the response
variable (result) once the call is made.
- Around line 189-194: The error handling currently reads the wrong field from
the Flowglad API error object; update the thrown message construction to use the
nested message field instead of the top-level error object. Specifically,
replace uses of result.error.json?.error (cast to string) with
result.error.json?.error?.message (cast to string) in both error branches
handling the API response so the thrown Error uses
(result.error.json?.error?.message as string) || 'Failed to create usage event'.
🧹 Nitpick comments (1)
nextjs/tiered-usage-gated-subscription/src/app/home-client.tsx (1)
201-233: Consider removing unused parameters from the function signature.The
priceSlugandtransactionIdPrefixparameters are defined but never used in the function body after migrating tobilling.createUsageEvent. These appear to be leftovers from the previous fetch-based implementation.🧹 Suggested cleanup
const handleUsageEvent = async ({ - priceSlug, usageMeterSlug, hasFeatureAccess, hasUsageMeterAccess, isUnlimited, remaining, setIsLoading, setMessageError, billing, - transactionIdPrefix, userMessage, assistantMessage, modelName, errorMessage = 'Failed to send message. Please try again.', alwaysCreateUsageEvent = false, }: { - priceSlug: string; usageMeterSlug: string; hasFeatureAccess: boolean; hasUsageMeterAccess: boolean; isUnlimited: boolean; remaining: number; setIsLoading: (loading: boolean) => void; setMessageError: (error: string | null) => void; billing: ReturnType<typeof useBilling>; - transactionIdPrefix: string; userMessage: string; assistantMessage: string; modelName: string; errorMessage?: string; alwaysCreateUsageEvent?: boolean; }) => {Then update all call sites (lines 287-401) to remove the
priceSlugandtransactionIdPrefixarguments.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (5)
nextjs/generation-based-subscription/bun.lockis excluded by!**/*.locknextjs/pay-as-you-go/bun.lockis excluded by!**/*.locknextjs/tiered-usage-gated-subscription/bun.lockis excluded by!**/*.locknextjs/usage-limit-subscription/bun.lockis excluded by!**/*.locktanstack-start/generation-based-subscription/bun.lockis excluded by!**/*.lock
📒 Files selected for processing (22)
nextjs/generation-based-subscription/drizzle/0000_open_maria_hill.sqlnextjs/generation-based-subscription/drizzle/meta/0000_snapshot.jsonnextjs/generation-based-subscription/drizzle/meta/_journal.jsonnextjs/generation-based-subscription/package.jsonnextjs/generation-based-subscription/src/app/api/usage-events/route.tsnextjs/generation-based-subscription/src/app/home-client.tsxnextjs/pay-as-you-go/package.jsonnextjs/pay-as-you-go/src/app/api/usage-events/route.tsnextjs/pay-as-you-go/src/app/home-client.tsxnextjs/tiered-usage-gated-subscription/drizzle/0000_pale_starhawk.sqlnextjs/tiered-usage-gated-subscription/drizzle/meta/0000_snapshot.jsonnextjs/tiered-usage-gated-subscription/drizzle/meta/_journal.jsonnextjs/tiered-usage-gated-subscription/package.jsonnextjs/tiered-usage-gated-subscription/src/app/api/usage-events/route.tsnextjs/tiered-usage-gated-subscription/src/app/home-client.tsxnextjs/usage-limit-subscription/package.jsonnextjs/usage-limit-subscription/src/app/api/usage-events/route.tsnextjs/usage-limit-subscription/src/app/home-client.tsxtanstack-start/generation-based-subscription/package.jsontanstack-start/generation-based-subscription/src/routeTree.gen.tstanstack-start/generation-based-subscription/src/routes/api/usage-events.tstanstack-start/generation-based-subscription/src/routes/index.tsx
💤 Files with no reviewable changes (6)
- nextjs/pay-as-you-go/src/app/api/usage-events/route.ts
- nextjs/generation-based-subscription/src/app/api/usage-events/route.ts
- tanstack-start/generation-based-subscription/src/routeTree.gen.ts
- nextjs/usage-limit-subscription/src/app/api/usage-events/route.ts
- nextjs/tiered-usage-gated-subscription/src/app/api/usage-events/route.ts
- tanstack-start/generation-based-subscription/src/routes/api/usage-events.ts
🔇 Additional comments (14)
nextjs/generation-based-subscription/package.json (1)
23-23: LGTM!The SDK version bump to
0.16.2aligns with the PR objectives to adopt the newcreateUsageEventmethod. The pinned version (without^or~) ensures reproducible builds for this example project.nextjs/usage-limit-subscription/package.json (1)
25-25: LGTM!Consistent SDK version update to
0.16.2matching the other example projects.nextjs/pay-as-you-go/package.json (1)
23-23: LGTM!SDK version update to
0.16.2is consistent with the PR objectives.nextjs/tiered-usage-gated-subscription/package.json (1)
23-23: LGTM!SDK version update to
0.16.2completes the consistent upgrade across all Next.js example projects.nextjs/tiered-usage-gated-subscription/src/app/home-client.tsx (1)
248-261: LGTM on the SDK migration pattern.The runtime guard and error handling are correctly implemented for the new
billing.createUsageEventAPI. The'error' in resultcheck properly handles the SDK's result-based error signaling.nextjs/pay-as-you-go/src/app/home-client.tsx (1)
112-126: SDK migration looks correct; note inconsistent error property access.The migration to
billing.createUsageEventis properly implemented with theamountparameter. However, the error message extraction usesresult.error.json?.message(Line 123), while the other files in this PR useresult.error.json?.error. This inconsistency may cause different error messages to display depending on which property the SDK actually returns.Verify which property the SDK returns and align all files to use the same pattern.
nextjs/usage-limit-subscription/src/app/home-client.tsx (1)
147-158: LGTM on the SDK migration.The migration to
billing.createUsageEventis correctly implemented. The error handling pattern usingresult.error.json?.erroris consistent with the tiered-usage example.nextjs/generation-based-subscription/drizzle/meta/_journal.json (1)
8-9: LGTM!Migration journal metadata updated with regenerated timestamp and tag, consistent with schema changes in this PR.
nextjs/generation-based-subscription/src/app/home-client.tsx (2)
168-184: LGTM!The runtime guard for
createUsageEventis good defensive programming, and the new SDK-based usage event creation aligns with the v0.16.2 migration objectives.
36-70: LGTM!Good use of
useRefto track previous user ID and trigger billing reload only when the user changes, preventing unnecessary refetches.nextjs/tiered-usage-gated-subscription/drizzle/meta/_journal.json (1)
8-9: This review comment is based on a false premise and should be dismissed.The
tiered-usage-gated-subscriptionexample is newly added in this commit. The migration file0000_pale_starhawk.sqlis not a regenerated entry but rather the initial migration for a fresh example. The assumed prior migration tag0000_dizzy_micromaxdoes not exist in this example's history. Since this example has no prior migration history, there is no risk of migration conflicts across environments or re-application of migrations.Likely an incorrect or invalid review comment.
tanstack-start/generation-based-subscription/package.json (1)
20-22: LGTM! Version bumps are consistent and published.The Flowglad SDK packages are correctly updated to v0.16.2 across all three dependencies. All packages are published on npm and properly maintain version consistency—@flowglad/react and @flowglad/server both depend on @flowglad/shared@0.16.2, matching the versions specified here.
nextjs/tiered-usage-gated-subscription/drizzle/meta/0000_snapshot.json (1)
107-107: Same unique constraint removal as in generation-based-subscription.This mirrors the constraint removal in the other example project. If the removal in
generation-based-subscriptionis confirmed intentional, this change is consistent.nextjs/generation-based-subscription/drizzle/meta/0000_snapshot.json (1)
107-107: The unique constraint is not present in the current schema definition. Theaccountstable insrc/server/db/schema.tsdefinesproviderIdandaccountIdasnotNullfields but does not include a unique constraint on their combination. The snapshot at line 107 correctly reflects this with an emptyuniqueConstraintsobject. No constraint was removed; the schema simply does not enforce uniqueness on(providerId, accountId).Likely an incorrect or invalid review comment.
| const result = await billing.createUsageEvent({ | ||
| usageMeterSlug: 'hd_video_minutes', | ||
| amount, | ||
| transactionId, | ||
| }); | ||
|
|
||
| if (!response.ok) { | ||
| const errorData = await response.json(); | ||
| throw new Error(errorData.error || 'Failed to create usage event'); | ||
| if ('error' in result) { | ||
| throw new Error( | ||
| (result.error.json?.error as string) || 'Failed to create usage event' | ||
| ); | ||
| } |
There was a problem hiding this comment.
Missing guard for createUsageEvent availability.
handleGenerateFastImage guards against billing.createUsageEvent being undefined (lines 168-170), but this handler does not. For consistency and to prevent potential runtime errors, add the same guard here.
Proposed fix
const handleGenerateHDVideo = async () => {
if (!hasHDVideoMinutesAccess || hdVideoMinutesRemaining === 0) {
return;
}
setIsGeneratingHDVideo(true);
setHdVideoError(null);
try {
+ if (!billing.createUsageEvent) {
+ throw new Error('createUsageEvent is not available');
+ }
+
// Generate a unique transaction ID for idempotency
const transactionId = `hd_video_${Date.now()}_${Math.random().toString(36).substring(7)}`;📝 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.
| const result = await billing.createUsageEvent({ | |
| usageMeterSlug: 'hd_video_minutes', | |
| amount, | |
| transactionId, | |
| }); | |
| if (!response.ok) { | |
| const errorData = await response.json(); | |
| throw new Error(errorData.error || 'Failed to create usage event'); | |
| if ('error' in result) { | |
| throw new Error( | |
| (result.error.json?.error as string) || 'Failed to create usage event' | |
| ); | |
| } | |
| const handleGenerateHDVideo = async () => { | |
| if (!hasHDVideoMinutesAccess || hdVideoMinutesRemaining === 0) { | |
| return; | |
| } | |
| setIsGeneratingHDVideo(true); | |
| setHdVideoError(null); | |
| try { | |
| if (!billing.createUsageEvent) { | |
| throw new Error('createUsageEvent is not available'); | |
| } | |
| // Generate a unique transaction ID for idempotency | |
| const transactionId = `hd_video_${Date.now()}_${Math.random().toString(36).substring(7)}`; | |
| const result = await billing.createUsageEvent({ | |
| usageMeterSlug: 'hd_video_minutes', | |
| amount, | |
| transactionId, | |
| }); | |
| if ('error' in result) { | |
| throw new Error( | |
| (result.error.json?.error as string) || 'Failed to create usage event' | |
| ); | |
| } |
🤖 Prompt for AI Agents
In @nextjs/generation-based-subscription/src/app/home-client.tsx around lines
221 - 231, The call to billing.createUsageEvent in this handler lacks the same
undefined guard used in handleGenerateFastImage; before invoking
billing.createUsageEvent (and before using amount/transactionId), check that
billing.createUsageEvent is a function and return or throw early if it's
undefined, mirroring the guard in handleGenerateFastImage so you avoid runtime
errors when createUsageEvent is not provided.
| if (!billing.createUsageEvent) { | ||
| throw new Error('createUsageEvent is not available') | ||
| } | ||
| // Random amount between 3-5 | ||
| const amount = Math.floor(Math.random() * 3) + 3 | ||
|
|
||
| const response = await fetch('/api/usage-events', { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| body: JSON.stringify({ | ||
| usageMeterSlug: 'fast_generations', | ||
| amount, | ||
| transactionId, | ||
| }), | ||
| const result = await billing.createUsageEvent({ | ||
| usageMeterSlug: 'fast_generations', | ||
| amount, | ||
| }) | ||
|
|
||
| if (!response.ok) { | ||
| const errorData = await response.json() | ||
| throw new Error(errorData.error || 'Failed to create usage event') | ||
| if ('error' in result) { | ||
| throw new Error( | ||
| (result.error.json?.error as string) || | ||
| 'Failed to create usage event', | ||
| ) | ||
| } |
There was a problem hiding this comment.
Missing transactionId for idempotency in fast image generation.
The HD video handler (line 227-234) generates a transactionId to ensure idempotent usage event creation, but this handler does not. If the network fails after the event is created server-side but before the client receives the response, a retry would create a duplicate usage event and incorrectly decrement the user's balance twice.
Proposed fix to add transactionId
try {
if (!billing.createUsageEvent) {
throw new Error('createUsageEvent is not available')
}
+ // Generate a unique transaction ID for idempotency
+ const transactionId = `fast_image_${Date.now()}_${Math.random().toString(36).substring(7)}`
// Random amount between 3-5
const amount = Math.floor(Math.random() * 3) + 3
const result = await billing.createUsageEvent({
usageMeterSlug: 'fast_generations',
amount,
+ transactionId,
})🤖 Prompt for AI Agents
In @tanstack-start/generation-based-subscription/src/routes/index.tsx around
lines 178 - 194, The fast image generation path calls billing.createUsageEvent
without a transactionId, risking duplicate usage events on retries; update the
fast generation handler (where billing.createUsageEvent is invoked) to generate
a unique transactionId (e.g., crypto.randomUUID() or existing helper used by the
HD video handler) and include transactionId in the createUsageEvent payload,
ensuring types align with the billing.createUsageEvent signature and matching
the approach used in the HD video handler to guarantee idempotency.
| if ('error' in result) { | ||
| throw new Error( | ||
| (result.error.json?.error as string) || | ||
| 'Failed to create usage event', | ||
| ) | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
@flowglad/react createUsageEvent error response structure v0.16.2
💡 Result:
Short answer: The @flowglad/react docs for v0.16.2 do not document a specific JSON error payload for createUsageEvent. The createUsageEvent API/SDK docs only show the successful response (usageEvent object) and list possible HTTP error statuses (400/401/403/500) but no canonical error body. [1][2]
What I found:
- Create Usage Event (request + successful response shown; errors only by HTTP status codes). [1]
- @flowglad/react / server SDK docs reference that usage events must be created from the server and show examples but do not define an error JSON schema. [2][3]
- The Express SDK example shows how Flowglad routes return errors to your app and a suggested custom error handler shape (example returning { error: 'Internal server error', message: ... }), but this is an example for your server, not the Flowglad API error contract. [4]
Sources:
- Create Usage Event API docs (request + success schema; HTTP 400/401/403/500 listed). [Create Usage Event]. [3]
- Usage-based billing / createUsageEvent usage examples in SDK docs. [Features: Usage]. [2]
- @flowglad/react & @flowglad/server SDK pages (notes that createUsageEvent should be called from server). [@flowglad/react]. [2]
- Express SDK error-handling example (shows how server-side errors might be returned from your express app). [Express SDK — Error Handling]. [4]
If you need the exact error JSON returned by the live Flowglad API for a particular error case (validation, auth, idempotency, etc.), I can:
- make a sample curl request to the Create Usage Event endpoint and show the exact error body for a failing example, or
- you can paste a real error response you received and I’ll explain its fields. Which would you prefer?
🌐 Web query:
flowglad React SDK v0.16.2 API documentation
💡 Result:
I found the @flowglad/react SDK API docs (components, hooks, and examples). See the SDK reference and API pages here: (docs.flowglad.com)
If you specifically need the v0.16.2 release notes or the package at that exact version (npm tarball or changelog), I can fetch the npm/GitHub release page—would you like me to do that?
Citations:
🌐 Web query:
@flowglad/react npm package error handling
💡 Result:
Short answer: @flowglad/react surfaces errors via the provider/hook and expects you to handle them in UI; server-side SDKs provide their own error middleware. Key points:
- useBilling() returns an errors field (Error[] | null), plus loaded and reload helpers — you should check errors and show fallback UI or call reload. [1]
- FlowgladProvider accepts loadBilling to opt-out of loading billing data; when loadBilling is true the hook’s loaded/errors indicate lifecycle and failure state. [1]
- Server-side endpoints (e.g., createFlowgladExpressRouter) include built-in error handling; docs show adding a custom Express error handler to log and return safe messages. Handle server errors there and return appropriate status/messages to the frontend. [2]
- For implementation examples and full API, see the Flowglad React SDK docs and the flowglad repo/examples. [1][3]
If you want, I can paste the exact useBilling example and a small React pattern for rendering error UI (with reload) based on the SDK.
🌐 Web query:
@flowglad/react v0.16.2 npm package source code GitHub
💡 Result:
The source for @flowglad/react is in the Flowglad monorepo on GitHub: https://github.com/flowglad/flowglad (see packages/react). [1][2]
If you need the exact v0.16.2 commit/files, open the repository, go to packages/react and switch to the tag or commit for v0.16.2 in the GitHub UI (Releases/Tags). [1][2]
Sources:
- Flowglad GitHub repo (packages folder). [1]
- Flowglad SDK docs (package @flowglad/react). [2]
🌐 Web query:
flowglad createUsageEvent server SDK implementation error shape
💡 Result:
Short answer — The server SDK throws/propagates Flowglad API errors (not a custom SDK-only shape). Expect the REST API error JSON of the form:
{
"error": {
"code": "SOME_ERROR_CODE",
"message": "Human readable message",
"details": { /* optional object with field-level info */ },
"request_id": "req_…",
"timestamp": "2024-01-15T10:30:00Z"
}
}
So when calling flowglad(...).createUsageEvent(...) catch the exception and inspect the HTTP/axios error payload (e.g. error.response.data.error) or error.message. The docs also describe createUsageEvent params, idempotency via transactionId, and SDK/Express built-in error handling. [1][2][3]
Sources:
- Flowglad Server SDK — createUsageEvent & params. [1]
- Feature Access & Usage / Usage-based billing (createUsageEvent details, transactionId idempotency). [2]
- Flow-style REST API error response format (error.code, message, details, request_id, timestamp). [3]
Fix error response path to access the message field from the error object.
The Flowglad API error response structure is { "error": { "code": "...", "message": "...", ... } }. The current code accesses result.error.json?.error and casts it to a string, but this returns the entire error object, not a message string.
Update both locations (lines 189-194 and 237-242) to use result.error.json?.error?.message:
(result.error.json?.error?.message as string) || 'Failed to create usage event'
🤖 Prompt for AI Agents
In @tanstack-start/generation-based-subscription/src/routes/index.tsx around
lines 189 - 194, The error handling currently reads the wrong field from the
Flowglad API error object; update the thrown message construction to use the
nested message field instead of the top-level error object. Specifically,
replace uses of result.error.json?.error (cast to string) with
result.error.json?.error?.message (cast to string) in both error branches
handling the API response so the thrown Error uses
(result.error.json?.error?.message as string) || 'Failed to create usage event'.
| const result = await billing.createUsageEvent({ | ||
| usageMeterSlug: 'hd_video_minutes', | ||
| amount, | ||
| transactionId, | ||
| }) | ||
|
|
||
| if (!response.ok) { | ||
| const errorData = await response.json() | ||
| throw new Error(errorData.error || 'Failed to create usage event') | ||
| if ('error' in result) { | ||
| throw new Error( | ||
| (result.error.json?.error as string) || | ||
| 'Failed to create usage event', | ||
| ) | ||
| } |
There was a problem hiding this comment.
Missing guard check for billing.createUsageEvent availability.
The fast image handler (lines 178-180) defensively checks if billing.createUsageEvent exists before calling it, but this handler calls it directly without the guard. For consistency and to avoid a potential runtime error if the method is unavailable, add the same check here.
Proposed fix to add guard check
try {
+ if (!billing.createUsageEvent) {
+ throw new Error('createUsageEvent is not available')
+ }
// Generate a unique transaction ID for idempotency
const transactionId = `hd_video_${Date.now()}_${Math.random().toString(36).substring(7)}`🤖 Prompt for AI Agents
In @tanstack-start/generation-based-subscription/src/routes/index.tsx around
lines 231 - 242, Add the same defensive guard used in the fast image handler
before calling billing.createUsageEvent: check that billing.createUsageEvent is
defined (e.g., if (billing?.createUsageEvent)) and only call it when present; if
it's absent, skip the call or handle the fallback accordingly, then keep the
existing result/error handling logic for the response variable (result) once the
call is made.
Code Review - PR #14: SDK Upgrade to v0.16.2Issues by SeverityIssue #1: Multiple FilesSeverity: Low Affected locations:
Recommendation: Consider either removing all explicit transactionId generation (since SDK handles it) or adding it consistently with a comment explaining when manual IDs are useful (e.g., correlating with external systems). Issue #2: Multiple FilesSeverity: Low Question for author: Which property is the correct one to check per the SDK's error response schema? Affected locations:
Current code (pay-as-you-go using if ('error' in result) {
throw new Error(
(result.error.json?.message as string) ||
'Failed to create usage event'
);
}Current code (others using if ('error' in result) {
throw new Error(
(result.error.json?.error as string) || 'Failed to create usage event'
);
}Issue #3: Multiple FilesSeverity: Low Affected locations:
Current code: if ('error' in result) {
throw new Error(
(result.error.json?.error as string) || 'Failed to create usage event'
);
}Fix: if ('error' in result) {
const errorMsg = result.error.json?.error ?? result.error.json?.message;
throw new Error(
(typeof errorMsg === 'string' ? errorMsg : null) ||
'Failed to create usage event'
);
}Issue #4:
|
| Severity | Count |
|---|---|
| Critical | 0 |
| High | 0 |
| Medium | 0 |
| Low | 4 |
Quality Gate: PASS - No blocking issues. The PR represents a clean SDK upgrade with good simplification of the example code. The issues noted are minor consistency improvements.
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Fix all issues with AI agents
In @tanstack-start/generation-based-subscription/src/routes/index.tsx:
- Around line 226-241: The code calls billing.createUsageEvent without checking
it exists; add the same defensive guard used in handleGenerateFastImage by
verifying billing.createUsageEvent is a function before awaiting it, and if
missing either skip usage tracking or throw a clear error (e.g.,
“billing.createUsageEvent not available”), updating the try block around
billing.createUsageEvent to mirror the guard in handleGenerateFastImage and keep
the existing error-handling logic intact.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
nextjs/generation-based-subscription/src/app/home-client.tsxnextjs/pay-as-you-go/src/app/home-client.tsxnextjs/tiered-usage-gated-subscription/src/app/home-client.tsxnextjs/usage-limit-subscription/src/app/home-client.tsxtanstack-start/generation-based-subscription/src/routes/index.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
- nextjs/generation-based-subscription/src/app/home-client.tsx
- nextjs/pay-as-you-go/src/app/home-client.tsx
- nextjs/tiered-usage-gated-subscription/src/app/home-client.tsx
🔇 Additional comments (5)
nextjs/usage-limit-subscription/src/app/home-client.tsx (2)
147-152: LGTM! Clean migration to SDK-managed usage events.The runtime guard ensures
createUsageEventis available before invocation, and omittingtransactionIdcorrectly delegates idempotency key generation to the SDK as intended by the v0.16.2 upgrade.
154-160: Well-handled error normalization.This correctly addresses the previous review feedback:
- Checks both
result.error.json?.errorandresult.error.json?.messagefor SDK schema flexibility- Uses
typeof === 'string'validation instead of unsafe type assertion- Provides a sensible fallback message
Clean implementation.
tanstack-start/generation-based-subscription/src/routes/index.tsx (3)
17-22: LGTM!The trailing comma is a good practice for cleaner git diffs.
66-81: LGTM!The optional chaining
session?.user?.idcorrectly guards againstundefinedaccess whensessionexists butuserdoes not. Dependency array is consistent with the accessed property.
178-195: LGTM! Clean migration to SDK method with proper error handling.The implementation correctly:
- Guards against
createUsageEventunavailability before use- Uses nullish coalescing to check both
errorandmessageproperties- Validates error message type before using it
- Falls back to a descriptive default message
This aligns well with the PR objective to replace manual fetch calls with
billing.createUsageEvent().
| try { | ||
| // Generate a unique transaction ID for idempotency | ||
| const transactionId = `hd_video_${Date.now()}_${Math.random().toString(36).substring(7)}` | ||
| // Random amount between 1-3 minutes | ||
| const amount = Math.floor(Math.random() * 3) + 1 | ||
|
|
||
| const response = await fetch('/api/usage-events', { | ||
| method: 'POST', | ||
| headers: { | ||
| 'Content-Type': 'application/json', | ||
| }, | ||
| body: JSON.stringify({ | ||
| usageMeterSlug: 'hd_video_minutes', | ||
| amount, | ||
| transactionId, | ||
| }), | ||
| const result = await billing.createUsageEvent({ | ||
| usageMeterSlug: 'hd_video_minutes', | ||
| amount, | ||
| }) | ||
|
|
||
| if (!response.ok) { | ||
| const errorData = await response.json() | ||
| throw new Error(errorData.error || 'Failed to create usage event') | ||
| if ('error' in result) { | ||
| const errorMsg = result.error.json?.error ?? result.error.json?.message | ||
| throw new Error( | ||
| (typeof errorMsg === 'string' ? errorMsg : null) || | ||
| 'Failed to create usage event', | ||
| ) | ||
| } |
There was a problem hiding this comment.
Add guard for createUsageEvent availability for consistency.
handleGenerateFastImage checks billing.createUsageEvent existence before use (lines 178-180), but this handler does not. For consistency and defensive coding, add the same guard.
Proposed fix
try {
+ if (!billing.createUsageEvent) {
+ throw new Error('createUsageEvent is not available')
+ }
// Random amount between 1-3 minutes
const amount = Math.floor(Math.random() * 3) + 1
const result = await billing.createUsageEvent({📝 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.
| try { | |
| // Generate a unique transaction ID for idempotency | |
| const transactionId = `hd_video_${Date.now()}_${Math.random().toString(36).substring(7)}` | |
| // Random amount between 1-3 minutes | |
| const amount = Math.floor(Math.random() * 3) + 1 | |
| const response = await fetch('/api/usage-events', { | |
| method: 'POST', | |
| headers: { | |
| 'Content-Type': 'application/json', | |
| }, | |
| body: JSON.stringify({ | |
| usageMeterSlug: 'hd_video_minutes', | |
| amount, | |
| transactionId, | |
| }), | |
| const result = await billing.createUsageEvent({ | |
| usageMeterSlug: 'hd_video_minutes', | |
| amount, | |
| }) | |
| if (!response.ok) { | |
| const errorData = await response.json() | |
| throw new Error(errorData.error || 'Failed to create usage event') | |
| if ('error' in result) { | |
| const errorMsg = result.error.json?.error ?? result.error.json?.message | |
| throw new Error( | |
| (typeof errorMsg === 'string' ? errorMsg : null) || | |
| 'Failed to create usage event', | |
| ) | |
| } | |
| try { | |
| if (!billing.createUsageEvent) { | |
| throw new Error('createUsageEvent is not available') | |
| } | |
| // Random amount between 1-3 minutes | |
| const amount = Math.floor(Math.random() * 3) + 1 | |
| const result = await billing.createUsageEvent({ | |
| usageMeterSlug: 'hd_video_minutes', | |
| amount, | |
| }) | |
| if ('error' in result) { | |
| const errorMsg = result.error.json?.error ?? result.error.json?.message | |
| throw new Error( | |
| (typeof errorMsg === 'string' ? errorMsg : null) || | |
| 'Failed to create usage event', | |
| ) | |
| } |
🤖 Prompt for AI Agents
In @tanstack-start/generation-based-subscription/src/routes/index.tsx around
lines 226 - 241, The code calls billing.createUsageEvent without checking it
exists; add the same defensive guard used in handleGenerateFastImage by
verifying billing.createUsageEvent is a function before awaiting it, and if
missing either skip usage tracking or throw a clear error (e.g.,
“billing.createUsageEvent not available”), updating the try block around
billing.createUsageEvent to mirror the guard in handleGenerateFastImage and keep
the existing error-handling logic intact.
closes #13
Summary by CodeRabbit
Dependencies
Improvements
Maintenance
✏️ Tip: You can customize this high-level summary in your review settings.