|
1 | 1 | import { |
2 | 2 | type CoreServiceConfig, |
3 | 3 | fetchTeamAndProject, |
| 4 | + type ReasonCode, |
4 | 5 | type TeamAndProjectResponse, |
5 | 6 | type TeamResponse, |
6 | 7 | } from "../api.js"; |
@@ -139,20 +140,55 @@ export async function authorize( |
139 | 140 | }; |
140 | 141 | } |
141 | 142 | // check if the service is maybe disabled for the team (usually due to a billing issue / exceeding the free plan limit) |
142 | | - if ( |
143 | | - !isServiceEnabledForTeam( |
144 | | - serviceConfig.serviceScope, |
145 | | - teamAndProjectResponse.team.capabilities, |
146 | | - ) |
147 | | - ) { |
148 | | - return { |
149 | | - authorized: false, |
150 | | - errorCode: "SERVICE_TEMPORARILY_DISABLED", |
151 | | - errorMessage: |
152 | | - "You currently do not have access to this service. Please check if your subscription includes this service and is active.", |
153 | | - status: 403, |
154 | | - }; |
| 143 | + const disabledReason = getServiceDisabledReason( |
| 144 | + serviceConfig.serviceScope, |
| 145 | + teamAndProjectResponse.team.capabilities, |
| 146 | + ); |
| 147 | + if (disabledReason) { |
| 148 | + switch (disabledReason) { |
| 149 | + case "enterprise_plan_required": { |
| 150 | + return { |
| 151 | + authorized: false, |
| 152 | + errorCode: "ENTERPRISE_PLAN_REQUIRED", |
| 153 | + errorMessage: `You currently do not have access to this feature. Please reach out to us to upgrade your plan to enable this feature: https://thirdweb.com/team/${teamAndProjectResponse.team.slug}/~/support`, |
| 154 | + status: 402, |
| 155 | + }; |
| 156 | + } |
| 157 | + case "free_limit_exceeded": { |
| 158 | + return { |
| 159 | + authorized: false, |
| 160 | + errorCode: "FREE_LIMIT_EXCEEDED", |
| 161 | + errorMessage: `You have exceeded the free limit for this service. Find a plan that suits your needs to continue using this feature: https://thirdweb.com/team/${teamAndProjectResponse.team.slug}/~/billing?showPlans=true&highlight=growth`, |
| 162 | + status: 402, |
| 163 | + }; |
| 164 | + } |
| 165 | + case "subscription_required": { |
| 166 | + return { |
| 167 | + authorized: false, |
| 168 | + errorCode: "SUBSCRIPTION_REQUIRED", |
| 169 | + errorMessage: `You need a subscription to use this feature. Find a plan that suits your needs to continue using this feature: https://thirdweb.com/team/${teamAndProjectResponse.team.slug}/~/billing?showPlans=true&highlight=growth`, |
| 170 | + status: 402, |
| 171 | + }; |
| 172 | + } |
| 173 | + case "invoice_past_due": { |
| 174 | + return { |
| 175 | + authorized: false, |
| 176 | + errorCode: "INVOICE_PAST_DUE", |
| 177 | + errorMessage: `Please pay any outstanding invoices to continue using this feature: https://thirdweb.com/team/${teamAndProjectResponse.team.slug}/~/billing/invoices`, |
| 178 | + status: 402, |
| 179 | + }; |
| 180 | + } |
| 181 | + default: { |
| 182 | + return { |
| 183 | + authorized: false, |
| 184 | + errorCode: "SERVICE_TEMPORARILY_DISABLED", |
| 185 | + errorMessage: `Access to this feature is temporarily restricted. Please reach out to us to resolve this issue: https://thirdweb.com/team/${teamAndProjectResponse.team.slug}/~/support`, |
| 186 | + status: 403, |
| 187 | + }; |
| 188 | + } |
| 189 | + } |
155 | 190 | } |
| 191 | + |
156 | 192 | // now we can validate the key itself |
157 | 193 | const clientAuth = authorizeClient(authData, teamAndProjectResponse); |
158 | 194 |
|
@@ -186,25 +222,45 @@ export async function authorize( |
186 | 222 | }; |
187 | 223 | } |
188 | 224 |
|
189 | | -function isServiceEnabledForTeam( |
| 225 | +function getServiceDisabledReason( |
190 | 226 | scope: CoreServiceConfig["serviceScope"], |
191 | 227 | teamCapabilities: TeamResponse["capabilities"], |
192 | | -): boolean { |
| 228 | +): ReasonCode | null { |
193 | 229 | switch (scope) { |
194 | 230 | case "rpc": |
195 | | - return teamCapabilities.rpc.enabled; |
| 231 | + return teamCapabilities.rpc.enabled |
| 232 | + ? null |
| 233 | + : teamCapabilities.rpc.reasonCode; |
196 | 234 | case "bundler": |
197 | | - return teamCapabilities.bundler.enabled; |
| 235 | + return teamCapabilities.bundler.enabled |
| 236 | + ? null |
| 237 | + : teamCapabilities.bundler.reasonCode; |
198 | 238 | case "storage": |
199 | | - return teamCapabilities.storage.enabled; |
| 239 | + return teamCapabilities.storage.enabled |
| 240 | + ? null |
| 241 | + : teamCapabilities.storage.reasonCode; |
200 | 242 | case "insight": |
201 | | - return teamCapabilities.insight.enabled; |
| 243 | + return teamCapabilities.insight.enabled |
| 244 | + ? null |
| 245 | + : teamCapabilities.insight.reasonCode; |
202 | 246 | case "nebula": |
203 | | - return teamCapabilities.nebula.enabled; |
| 247 | + return teamCapabilities.nebula.enabled |
| 248 | + ? null |
| 249 | + : teamCapabilities.nebula.reasonCode; |
204 | 250 | case "embeddedWallets": |
205 | | - return teamCapabilities.embeddedWallets.enabled; |
| 251 | + return teamCapabilities.embeddedWallets.enabled |
| 252 | + ? null |
| 253 | + : teamCapabilities.embeddedWallets.reasonCode; |
| 254 | + case "engineCloud": |
| 255 | + return teamCapabilities.engineCloud.enabled |
| 256 | + ? null |
| 257 | + : teamCapabilities.engineCloud.reasonCode; |
| 258 | + case "pay": |
| 259 | + return teamCapabilities.pay.enabled |
| 260 | + ? null |
| 261 | + : teamCapabilities.pay.reasonCode; |
206 | 262 | default: |
207 | | - // always return true for any legacy / un-named services |
208 | | - return true; |
| 263 | + // always return null for any legacy / un-named services |
| 264 | + return null; |
209 | 265 | } |
210 | 266 | } |
0 commit comments