Skip to content

Commit 169ae22

Browse files
jnsdlsarcoraven
andauthored
Add team capabilities to service-utils (#6641)
Co-authored-by: Phillip Ho <arcoraven@gmail.com>
1 parent 04d2bc7 commit 169ae22

File tree

5 files changed

+152
-0
lines changed

5 files changed

+152
-0
lines changed

.changeset/loose-comics-serve.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@thirdweb-dev/service-utils": patch
3+
---
4+
5+
add team capabilities

apps/dashboard/src/stories/stubs.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,40 @@ export function teamStub(id: string, billingPlan: Team["billingPlan"]): Team {
5656
"chainsaw",
5757
],
5858
stripeCustomerId: "cus_1234567890",
59+
capabilities: {
60+
rpc: {
61+
enabled: true,
62+
rateLimit: 1000,
63+
},
64+
storage: {
65+
enabled: true,
66+
download: {
67+
rateLimit: 1000,
68+
},
69+
upload: {
70+
totalFileSizeBytesLimit: 1_000_000_000,
71+
rateLimit: 1000,
72+
},
73+
},
74+
bundler: {
75+
enabled: true,
76+
rateLimit: 1000,
77+
mainnetEnabled: true,
78+
},
79+
insight: {
80+
enabled: true,
81+
rateLimit: 1000,
82+
},
83+
embeddedWallets: {
84+
enabled: true,
85+
customAuth: true,
86+
customBranding: true,
87+
},
88+
nebula: {
89+
enabled: true,
90+
rateLimit: 1000,
91+
},
92+
},
5993
};
6094

6195
return team;

packages/service-utils/src/core/api.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,45 @@ export type ApiResponse = {
4343
};
4444
};
4545

46+
/**
47+
* Stores service-specific capabilities.
48+
* This type should match the schema from API server.
49+
*/
50+
type TeamCapabilities = {
51+
rpc: {
52+
enabled: boolean;
53+
rateLimit: number;
54+
};
55+
insight: {
56+
enabled: boolean;
57+
rateLimit: number;
58+
};
59+
storage: {
60+
enabled: boolean;
61+
download: {
62+
rateLimit: number;
63+
};
64+
upload: {
65+
totalFileSizeBytesLimit: number;
66+
rateLimit: number;
67+
};
68+
};
69+
nebula: {
70+
enabled: boolean;
71+
rateLimit: number;
72+
};
73+
bundler: {
74+
enabled: boolean;
75+
mainnetEnabled: boolean;
76+
rateLimit: number;
77+
};
78+
embeddedWallets: {
79+
enabled: boolean;
80+
customAuth: boolean;
81+
customBranding: boolean;
82+
};
83+
};
84+
4685
export type TeamResponse = {
4786
id: string;
4887
name: string;
@@ -68,6 +107,7 @@ export type TeamResponse = {
68107
canCreatePublicChains: boolean | null;
69108
enabledScopes: ServiceName[];
70109
isOnboarded: boolean;
110+
capabilities: TeamCapabilities;
71111
};
72112

73113
export type ProjectSecretKey = {

packages/service-utils/src/core/authorize/index.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
type CoreServiceConfig,
33
type TeamAndProjectResponse,
4+
type TeamResponse,
45
fetchTeamAndProject,
56
} from "../api.js";
67
import { authorizeClient } from "./client.js";
@@ -129,6 +130,21 @@ export async function authorize(
129130
errorCode: "INVALID_KEY",
130131
};
131132
}
133+
// check if the service is maybe disabled for the team (usually due to a billing issue / exceeding the free plan limit)
134+
if (
135+
!isServiceEnabledForTeam(
136+
serviceConfig.serviceScope,
137+
teamAndProjectResponse.team.capabilities,
138+
)
139+
) {
140+
return {
141+
authorized: false,
142+
status: 403,
143+
errorMessage:
144+
"You currently do not have access to this service. Please check if your subscription includes this service and is active.",
145+
errorCode: "SERVICE_TEMPORARILY_DISABLED",
146+
};
147+
}
132148
// now we can validate the key itself
133149
const clientAuth = authorizeClient(authData, teamAndProjectResponse);
134150

@@ -161,3 +177,26 @@ export async function authorize(
161177
authMethod: clientAuth.authMethod,
162178
};
163179
}
180+
181+
function isServiceEnabledForTeam(
182+
scope: CoreServiceConfig["serviceScope"],
183+
teamCapabilities: TeamResponse["capabilities"],
184+
): boolean {
185+
switch (scope) {
186+
case "rpc":
187+
return teamCapabilities.rpc.enabled;
188+
case "bundler":
189+
return teamCapabilities.bundler.enabled;
190+
case "storage":
191+
return teamCapabilities.storage.enabled;
192+
case "insight":
193+
return teamCapabilities.insight.enabled;
194+
case "nebula":
195+
return teamCapabilities.nebula.enabled;
196+
case "embeddedWallets":
197+
return teamCapabilities.embeddedWallets.enabled;
198+
default:
199+
// always return true for any legacy / un-named services
200+
return true;
201+
}
202+
}

packages/service-utils/src/mocks.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,40 @@ export const validTeamResponse: TeamResponse = {
5959
canCreatePublicChains: false,
6060
enabledScopes: ["storage", "rpc", "bundler"],
6161
isOnboarded: true,
62+
capabilities: {
63+
rpc: {
64+
enabled: true,
65+
rateLimit: 1000,
66+
},
67+
insight: {
68+
enabled: true,
69+
rateLimit: 1000,
70+
},
71+
storage: {
72+
enabled: true,
73+
download: {
74+
rateLimit: 1000,
75+
},
76+
upload: {
77+
totalFileSizeBytesLimit: 1_000_000_000,
78+
rateLimit: 1000,
79+
},
80+
},
81+
nebula: {
82+
enabled: true,
83+
rateLimit: 1000,
84+
},
85+
bundler: {
86+
enabled: true,
87+
mainnetEnabled: true,
88+
rateLimit: 1000,
89+
},
90+
embeddedWallets: {
91+
enabled: true,
92+
customAuth: true,
93+
customBranding: true,
94+
},
95+
},
6296
};
6397

6498
export const validTeamAndProjectResponse: TeamAndProjectResponse = {

0 commit comments

Comments
 (0)