Skip to content

Commit 51f4826

Browse files
http-teapotThomas Potaire
andauthored
feat: refactor subscription backend logic (#2426)
* cleaning up the webhook lifecyle side * Add indexes to optimize count/sum queries and wire frontend to rate limits * Adding rate limit decrement logic * remove console.log * adjusting logic from self-review * fixing suggested comments * great catch from auto-review * adjusting base on comment * small formatting * refactor * update seed and use db from context * decrement of rate limit should only if user has active subscription * Fix for login button loading states (#2481) * Fixes both auth login buttons from showing loading animation when either one is actually loading * Fix decimal input support, add VH units. (#2469) * Fix decimal input support, add VH units. * fix: preserve arrow key behavior * attempt at fixing free/paid increment * Populate schedule data when a subscription is scheduled to be downgraded * Handle downgrade -> upgrade gracefully * add backfill script * count previous day and month for free plan --------- Co-authored-by: Thomas Potaire <[email protected]>
1 parent 26d135e commit 51f4826

File tree

41 files changed

+1213
-443
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1213
-443
lines changed

apps/web/client/messages/en.d.json.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ declare const messages: {
182182
}
183183
},
184184
"footer": {
185-
"unusedMessages": "Unused chat messages don't rollover to the next month"
185+
"unusedMessages": "Unused chat messages will roll over to the next month."
186186
}
187187
},
188188
"editor": {

apps/web/client/messages/en.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@
179179
}
180180
},
181181
"footer": {
182-
"unusedMessages": "Unused chat messages don't rollover to the next month"
182+
"unusedMessages": "Unused chat messages will roll over to the next month."
183183
}
184184
},
185185
"editor": {

apps/web/client/messages/es.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@
179179
}
180180
},
181181
"footer": {
182-
"unusedMessages": "Los mensajes de chat no utilizados no se transfieren al siguiente mes"
182+
"unusedMessages": "Los mensajes de chat no utilizados se transferirán al siguiente mes"
183183
}
184184
},
185185
"editor": {

apps/web/client/messages/ja.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@
7878
}
7979
},
8080
"footer": {
81-
"unusedMessages": "未使用のチャットメッセージは翌月に繰り越されません"
81+
"unusedMessages": "未使用のチャットメッセージは翌月に繰り越されます"
8282
}
8383
},
8484
"editor": {

apps/web/client/messages/ko.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@
179179
}
180180
},
181181
"footer": {
182-
"unusedMessages": "사용하지 않은 채팅 메시지는 다음 달로 이월되지 않습니다."
182+
"unusedMessages": "사용하지 않은 채팅 메시지는 다음 달로 이월됩니다."
183183
}
184184
},
185185
"editor": {

apps/web/client/messages/zh.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -179,7 +179,7 @@
179179
}
180180
},
181181
"footer": {
182-
"unusedMessages": "未使用的聊天消息不会结转到下个月"
182+
"unusedMessages": "未使用的聊天消息会结转到下个月"
183183
}
184184
},
185185
"editor": {

apps/web/client/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
"class-variance-authority": "^0.7.1",
6363
"clsx": "^2.1.1",
6464
"culori": "^4.0.1",
65+
"date-fns": "^4.1.0",
6566
"dayjs": "^1.11.13",
6667
"embla-carousel-react": "^8.6.0",
6768
"flexsearch": "^0.8.160",

apps/web/client/public/onlook-preload-script.js

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

apps/web/client/src/app/api/chat/route.ts

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,24 @@ export const streamResponse = async (req: NextRequest) => {
104104
const { messages, maxSteps, chatType } = await req.json();
105105
const { model, providerOptions, headers } = await initModel(MainModelConfig);
106106

107+
// Updating the usage record and rate limit is done here to avoid
108+
// abuse in the case where a single user sends many concurrent requests.
109+
// If the call below fails, the user will not be penalized.
110+
let usageRecordId: string | undefined;
111+
let rateLimitId: string | undefined;
112+
if (chatType === ChatType.EDIT) {
113+
const user = await getSupabaseUser(req);
114+
if (!user) {
115+
throw new Error('User not found');
116+
}
117+
const { api } = await createTRPCClient(req);
118+
const incrementRes = await api.usage.increment({
119+
type: UsageType.MESSAGE,
120+
});
121+
usageRecordId = incrementRes?.usageRecordId;
122+
rateLimitId = incrementRes?.rateLimitId;
123+
}
124+
107125
let systemPrompt: string;
108126
switch (chatType) {
109127
case ChatType.CREATE:
@@ -160,26 +178,17 @@ export const streamResponse = async (req: NextRequest) => {
160178

161179
return { ...toolCall, args: JSON.stringify(repairedArgs) };
162180
},
163-
onError: (error) => {
181+
onError: async (error) => {
164182
console.error('Error in chat', error);
183+
// if there was an error with the API, do not penalize the user
184+
if (usageRecordId && rateLimitId) {
185+
await createTRPCClient(req)
186+
.then(({ api }) => api.usage.revertIncrement({ usageRecordId, rateLimitId }))
187+
.catch(error => console.error('Error in chat usage decrement', error));
188+
}
165189
throw error;
166190
},
167191
});
168192

169-
try {
170-
if (chatType === ChatType.EDIT) {
171-
const user = await getSupabaseUser(req);
172-
if (!user) {
173-
throw new Error('User not found');
174-
}
175-
const { api } = await createTRPCClient(req);
176-
await api.usage.increment({
177-
type: UsageType.MESSAGE,
178-
});
179-
}
180-
} catch (error) {
181-
console.error('Error in chat usage increment', error);
182-
}
183-
184193
return result.toDataStreamResponse();
185194
}

apps/web/client/src/app/project/[id]/_components/right-panel/chat-tab/chat-messages/error-message.tsx

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,39 @@
11
import { useEditorEngine } from '@/components/store/editor';
22
import { useStateManager } from '@/components/store/state';
3+
import { api } from '@/trpc/react';
34
import { Button } from '@onlook/ui/button';
45
import { Icons } from '@onlook/ui/icons';
56
import { observer } from 'mobx-react-lite';
7+
import { useEffect } from 'react';
68

79
export const ErrorMessage = observer(() => {
810
const editorEngine = useEditorEngine();
911
const stateManager = useStateManager();
1012
const error = editorEngine.chat.error.message;
1113
const usage = editorEngine.chat.error.usage;
14+
const isUsageError = usage && usage.usageCount >= usage.limitCount;
1215

13-
if (usage && usage.usageCount >= usage.limitCount) {
16+
const { data: usageData, refetch: refetchUsage } = api.usage.get.useQuery();
1417

18+
useEffect(() => {
19+
if (isUsageError) {
20+
// Start polling for subscription changes.
21+
const interval = setInterval(() => {
22+
refetchUsage();
23+
}, 3000);
24+
return () => clearInterval(interval);
25+
}
26+
}, [isUsageError]);
27+
28+
// Clear error when usage data shows user is no longer over limit
29+
useEffect(() => {
30+
const isUnderLimit = usageData && usageData.daily.usageCount < usageData.daily.limitCount && usageData.monthly.usageCount < usageData.monthly.limitCount;
31+
if (isUsageError && isUnderLimit) {
32+
editorEngine.chat.error.usage = null;
33+
}
34+
}, [usageData, isUsageError]);
35+
36+
if (isUsageError) {
1537
return (
1638
<div className="flex w-full flex-col items-center justify-center gap-2 text-small px-4 pb-4">
1739
<p className="text-foreground-secondary text-mini my-1 text-blue-300 select-none">

0 commit comments

Comments
 (0)