diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql index b74535d330..3f723a671d 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql @@ -1610,6 +1610,11 @@ type BillingPlan { meteredProducts: [BillingMeteredProduct!]! } +type BillingPaymentIntent { + clientSecret: String! + paymentIntentType: String! +} + type BillingSession { url: String } @@ -1879,6 +1884,7 @@ enum ModelFamily { type Billing { isBillingEnabled: Boolean! billingUrl: String + stripePublishableKey: String trialPeriods: [BillingTrialPeriod!]! } @@ -3286,6 +3292,7 @@ type Mutation { skipBookOnboardingStep: OnboardingStepSuccess! updateOneApplicationVariable(key: String!, value: String!, applicationId: UUID!): Boolean! checkoutSession(recurringInterval: SubscriptionInterval!, plan: BillingPlanKey! = PRO, requirePaymentMethod: Boolean! = true, successUrlPath: String): BillingSession! + createSubscriptionPaymentIntent(recurringInterval: SubscriptionInterval!, plan: BillingPlanKey! = PRO, requirePaymentMethod: Boolean! = true, successUrlPath: String, idempotencyKey: String!): BillingPaymentIntent! switchSubscriptionInterval: BillingUpdate! switchBillingPlan: BillingUpdate! cancelSwitchBillingPlan: BillingUpdate! diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.ts b/packages/twenty-client-sdk/src/metadata/generated/schema.ts index 4e505130ea..0957e01069 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.ts +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.ts @@ -1258,6 +1258,12 @@ export interface BillingPlan { __typename: 'BillingPlan' } +export interface BillingPaymentIntent { + clientSecret: Scalars['String'] + paymentIntentType: Scalars['String'] + __typename: 'BillingPaymentIntent' +} + export interface BillingSession { url?: Scalars['String'] __typename: 'BillingSession' @@ -1504,6 +1510,7 @@ export type ModelFamily = 'GPT' | 'CLAUDE' | 'GEMINI' | 'MISTRAL' | 'GROK' export interface Billing { isBillingEnabled: Scalars['Boolean'] billingUrl?: Scalars['String'] + stripePublishableKey?: Scalars['String'] trialPeriods: BillingTrialPeriod[] __typename: 'Billing' } @@ -2804,6 +2811,7 @@ export interface Mutation { skipBookOnboardingStep: OnboardingStepSuccess updateOneApplicationVariable: Scalars['Boolean'] checkoutSession: BillingSession + createSubscriptionPaymentIntent: BillingPaymentIntent switchSubscriptionInterval: BillingUpdate switchBillingPlan: BillingUpdate cancelSwitchBillingPlan: BillingUpdate @@ -4298,6 +4306,13 @@ export interface BillingPlanGenqlSelection{ __scalar?: boolean | number } +export interface BillingPaymentIntentGenqlSelection{ + clientSecret?: boolean | number + paymentIntentType?: boolean | number + __typename?: boolean | number + __scalar?: boolean | number +} + export interface BillingSessionGenqlSelection{ url?: boolean | number __typename?: boolean | number @@ -4547,6 +4562,7 @@ export interface ClientAiModelConfigGenqlSelection{ export interface BillingGenqlSelection{ isBillingEnabled?: boolean | number billingUrl?: boolean | number + stripePublishableKey?: boolean | number trialPeriods?: BillingTrialPeriodGenqlSelection __typename?: boolean | number __scalar?: boolean | number @@ -5978,6 +5994,7 @@ export interface MutationGenqlSelection{ skipBookOnboardingStep?: OnboardingStepSuccessGenqlSelection updateOneApplicationVariable?: { __args: {key: Scalars['String'], value: Scalars['String'], applicationId: Scalars['UUID']} } checkoutSession?: (BillingSessionGenqlSelection & { __args: {recurringInterval: SubscriptionInterval, plan: BillingPlanKey, requirePaymentMethod: Scalars['Boolean'], successUrlPath?: (Scalars['String'] | null)} }) + createSubscriptionPaymentIntent?: (BillingPaymentIntentGenqlSelection & { __args: {recurringInterval: SubscriptionInterval, plan: BillingPlanKey, requirePaymentMethod: Scalars['Boolean'], successUrlPath?: (Scalars['String'] | null), idempotencyKey: Scalars['String']} }) switchSubscriptionInterval?: BillingUpdateGenqlSelection switchBillingPlan?: BillingUpdateGenqlSelection cancelSwitchBillingPlan?: BillingUpdateGenqlSelection @@ -7321,6 +7338,14 @@ export interface LogicFunctionLogsInput {applicationId?: (Scalars['UUID'] | null + const BillingPaymentIntent_possibleTypes: string[] = ['BillingPaymentIntent'] + export const isBillingPaymentIntent = (obj?: { __typename?: any } | null): obj is BillingPaymentIntent => { + if (!obj?.__typename) throw new Error('__typename is missing in "isBillingPaymentIntent"') + return BillingPaymentIntent_possibleTypes.includes(obj.__typename) + } + + + const BillingSession_possibleTypes: string[] = ['BillingSession'] export const isBillingSession = (obj?: { __typename?: any } | null): obj is BillingSession => { if (!obj?.__typename) throw new Error('__typename is missing in "isBillingSession"') diff --git a/packages/twenty-client-sdk/src/metadata/generated/types.ts b/packages/twenty-client-sdk/src/metadata/generated/types.ts index a279b8058c..9a1719ea25 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/types.ts +++ b/packages/twenty-client-sdk/src/metadata/generated/types.ts @@ -48,41 +48,41 @@ export default { 137, 139, 148, - 160, - 163, - 165, - 169, - 171, - 176, + 161, + 164, + 166, + 170, + 172, 177, - 184, - 187, - 190, - 203, - 218, - 230, - 236, - 272, - 274, + 178, + 185, + 188, + 191, + 204, + 219, + 231, + 237, + 273, 275, 276, 277, 278, 279, 280, - 287, - 325, + 281, + 288, 326, 327, 328, - 330, - 332, - 343, - 350, - 357, - 480, - 485, - 493 + 329, + 331, + 333, + 344, + 351, + 358, + 481, + 486, + 494 ], "types": { "BillingProductDTO": { @@ -959,10 +959,10 @@ export default { 3 ], "relation": [ - 202 + 203 ], "morphRelations": [ - 202 + 203 ], "object": [ 56 @@ -1024,7 +1024,7 @@ export default { 46 ], "objectMetadata": [ - 210, + 211, { "paging": [ 49, @@ -1037,7 +1037,7 @@ export default { } ], "indexFieldMetadatas": [ - 208, + 209, { "paging": [ 49, @@ -1288,7 +1288,7 @@ export default { 47 ], "fields": [ - 215, + 216, { "paging": [ 49, @@ -1301,7 +1301,7 @@ export default { } ], "indexMetadatas": [ - 213, + 214, { "paging": [ 49, @@ -1897,7 +1897,7 @@ export default { 59 ], "featureFlags": [ - 170 + 171 ], "billingSubscriptions": [ 147 @@ -1912,7 +1912,7 @@ export default { 146 ], "billingEntitlements": [ - 229 + 230 ], "hasValidSignedEnterpriseKey": [ 6 @@ -1921,7 +1921,7 @@ export default { 6 ], "workspaceUrls": [ - 172 + 173 ], "workspaceCustomApplicationId": [ 1 @@ -2010,7 +2010,7 @@ export default { 20 ], "deletedWorkspaceMembers": [ - 228 + 229 ], "hasPassword": [ 6 @@ -2022,7 +2022,7 @@ export default { 17 ], "availableWorkspaces": [ - 227 + 228 ], "__typename": [ 1 @@ -3171,6 +3171,17 @@ export default { 1 ] }, + "BillingPaymentIntent": { + "clientSecret": [ + 1 + ], + "paymentIntentType": [ + 1 + ], + "__typename": [ + 1 + ] + }, "BillingSession": { "url": [ 1 @@ -3234,7 +3245,7 @@ export default { 1 ], "result": [ - 156 + 157 ], "__typename": [ 1 @@ -3271,7 +3282,7 @@ export default { 3 ], "type": [ - 160 + 161 ], "name": [ 1 @@ -3304,7 +3315,7 @@ export default { 4 ], "targetRecordIdentifier": [ - 158 + 159 ], "__typename": [ 1 @@ -3330,7 +3341,7 @@ export default { }, "MetadataEvent": { "type": [ - 163 + 164 ], "metadataName": [ 1 @@ -3339,7 +3350,7 @@ export default { 1 ], "properties": [ - 161 + 162 ], "updatedCollectionHash": [ 1 @@ -3351,7 +3362,7 @@ export default { "MetadataEventAction": {}, "ObjectRecordEvent": { "action": [ - 165 + 166 ], "objectNameSingular": [ 1 @@ -3366,7 +3377,7 @@ export default { 1 ], "properties": [ - 161 + 162 ], "__typename": [ 1 @@ -3378,7 +3389,7 @@ export default { 1 ], "objectRecordEvent": [ - 164 + 165 ], "__typename": [ 1 @@ -3389,10 +3400,10 @@ export default { 1 ], "objectRecordEventsWithQueryIds": [ - 166 + 167 ], "metadataEvents": [ - 162 + 163 ], "__typename": [ 1 @@ -3409,7 +3420,7 @@ export default { 11 ], "status": [ - 169 + 170 ], "error": [ 15 @@ -3421,7 +3432,7 @@ export default { "LogicFunctionExecutionStatus": {}, "FeatureFlag": { "key": [ - 171 + 172 ], "value": [ 6 @@ -3493,10 +3504,10 @@ export default { 1 ], "type": [ - 176 + 177 ], "status": [ - 177 + 178 ], "issuer": [ 1 @@ -3509,7 +3520,7 @@ export default { "SSOIdentityProviderStatus": {}, "AuthProviders": { "sso": [ - 175 + 176 ], "google": [ 6 @@ -3546,10 +3557,10 @@ export default { 3 ], "authProviders": [ - 178 + 179 ], "authBypassProviders": [ - 179 + 180 ], "logo": [ 1 @@ -3558,7 +3569,7 @@ export default { 1 ], "workspaceUrls": [ - 172 + 173 ], "__typename": [ 1 @@ -3597,7 +3608,7 @@ export default { 1 ], "modelFamily": [ - 184 + 185 ], "modelFamilyLabel": [ 1 @@ -3612,7 +3623,7 @@ export default { 11 ], "nativeCapabilities": [ - 182 + 183 ], "isDeprecated": [ 6 @@ -3647,8 +3658,11 @@ export default { "billingUrl": [ 1 ], + "stripePublishableKey": [ + 1 + ], "trialPeriods": [ - 174 + 175 ], "__typename": [ 1 @@ -3656,7 +3670,7 @@ export default { }, "Support": { "supportDriver": [ - 187 + 188 ], "supportFrontChatId": [ 1 @@ -3682,7 +3696,7 @@ export default { }, "Captcha": { "provider": [ - 190 + 191 ], "siteKey": [ 1 @@ -3716,10 +3730,10 @@ export default { }, "PublicFeatureFlag": { "key": [ - 171 + 172 ], "metadata": [ - 192 + 193 ], "__typename": [ 1 @@ -3744,13 +3758,13 @@ export default { 1 ], "authProviders": [ - 178 + 179 ], "billing": [ - 185 + 186 ], "aiModels": [ - 183 + 184 ], "signInPrefilled": [ 6 @@ -3771,25 +3785,25 @@ export default { 6 ], "support": [ - 186 + 187 ], "isAttachmentPreviewEnabled": [ 6 ], "sentry": [ - 188 - ], - "captcha": [ 189 ], + "captcha": [ + 190 + ], "api": [ - 191 + 192 ], "canManageFeatureFlags": [ 6 ], "publicFeatureFlags": [ - 193 + 194 ], "isMicrosoftMessagingEnabled": [ 6 @@ -3828,7 +3842,7 @@ export default { 6 ], "maintenance": [ - 194 + 195 ], "__typename": [ 1 @@ -3867,7 +3881,7 @@ export default { 1 ], "versionDistribution": [ - 197 + 198 ], "__typename": [ 1 @@ -3914,7 +3928,7 @@ export default { }, "Relation": { "type": [ - 203 + 204 ], "sourceObjectMetadata": [ 56 @@ -3963,10 +3977,10 @@ export default { }, "IndexConnection": { "pageInfo": [ - 205 + 206 ], "edges": [ - 204 + 205 ], "__typename": [ 1 @@ -3985,10 +3999,10 @@ export default { }, "IndexIndexFieldMetadatasConnection": { "pageInfo": [ - 205 + 206 ], "edges": [ - 207 + 208 ], "__typename": [ 1 @@ -4007,10 +4021,10 @@ export default { }, "IndexObjectMetadataConnection": { "pageInfo": [ - 205 + 206 ], "edges": [ - 209 + 210 ], "__typename": [ 1 @@ -4029,10 +4043,10 @@ export default { }, "ObjectConnection": { "pageInfo": [ - 205 + 206 ], "edges": [ - 209 + 210 ], "__typename": [ 1 @@ -4040,10 +4054,10 @@ export default { }, "ObjectIndexMetadatasConnection": { "pageInfo": [ - 205 + 206 ], "edges": [ - 204 + 205 ], "__typename": [ 1 @@ -4062,10 +4076,10 @@ export default { }, "ObjectFieldsConnection": { "pageInfo": [ - 205 + 206 ], "edges": [ - 214 + 215 ], "__typename": [ 1 @@ -4073,10 +4087,10 @@ export default { }, "FieldConnection": { "pageInfo": [ - 205 + 206 ], "edges": [ - 214 + 215 ], "__typename": [ 1 @@ -4084,7 +4098,7 @@ export default { }, "AppConnection": { "id": [ - 218 + 219 ], "providerName": [ 1 @@ -4136,7 +4150,7 @@ export default { 3 ], "type": [ - 176 + 177 ], "issuer": [ 1 @@ -4145,7 +4159,7 @@ export default { 1 ], "status": [ - 177 + 178 ], "__typename": [ 1 @@ -4164,7 +4178,7 @@ export default { }, "FindAvailableSSOIDP": { "type": [ - 176 + 177 ], "id": [ 3 @@ -4176,10 +4190,10 @@ export default { 1 ], "status": [ - 177 + 178 ], "workspace": [ - 222 + 223 ], "__typename": [ 1 @@ -4190,7 +4204,7 @@ export default { 3 ], "type": [ - 176 + 177 ], "issuer": [ 1 @@ -4199,7 +4213,7 @@ export default { 1 ], "status": [ - 177 + 178 ], "__typename": [ 1 @@ -4207,7 +4221,7 @@ export default { }, "SSOConnection": { "type": [ - 176 + 177 ], "id": [ 3 @@ -4219,7 +4233,7 @@ export default { 1 ], "status": [ - 177 + 178 ], "__typename": [ 1 @@ -4242,13 +4256,13 @@ export default { 1 ], "workspaceUrls": [ - 172 + 173 ], "logo": [ 1 ], "sso": [ - 225 + 226 ], "__typename": [ 1 @@ -4256,10 +4270,10 @@ export default { }, "AvailableWorkspaces": { "availableWorkspacesForSignIn": [ - 226 + 227 ], "availableWorkspacesForSignUp": [ - 226 + 227 ], "__typename": [ 1 @@ -4287,7 +4301,7 @@ export default { }, "BillingEntitlement": { "key": [ - 230 + 231 ], "value": [ 6 @@ -4325,7 +4339,7 @@ export default { 1 ], "records": [ - 231 + 232 ], "__typename": [ 1 @@ -4361,7 +4375,7 @@ export default { 1 ], "connectionSecurity": [ - 236 + 237 ], "__typename": [ 1 @@ -4370,13 +4384,13 @@ export default { "EmailConnectionSecurity": {}, "PublicImapSmtpCaldavConnectionParameters": { "IMAP": [ - 235 + 236 ], "SMTP": [ - 235 + 236 ], "CALDAV": [ - 235 + 236 ], "__typename": [ 1 @@ -4432,7 +4446,7 @@ export default { 4 ], "connectionParameters": [ - 237 + 238 ], "__typename": [ 1 @@ -4483,10 +4497,10 @@ export default { }, "AvailableWorkspacesAndAccessTokens": { "tokens": [ - 243 + 244 ], "availableWorkspaces": [ - 227 + 228 ], "__typename": [ 1 @@ -4524,7 +4538,7 @@ export default { }, "WorkspaceUrlsAndId": { "workspaceUrls": [ - 172 + 173 ], "id": [ 3 @@ -4538,7 +4552,7 @@ export default { 32 ], "workspace": [ - 248 + 249 ], "__typename": [ 1 @@ -4571,7 +4585,7 @@ export default { 32 ], "workspaceUrls": [ - 172 + 173 ], "__typename": [ 1 @@ -4612,7 +4626,7 @@ export default { }, "AuthTokens": { "tokens": [ - 243 + 244 ], "__typename": [ 1 @@ -4653,7 +4667,7 @@ export default { 32 ], "workspace": [ - 248 + 249 ], "__typename": [ 1 @@ -4675,7 +4689,7 @@ export default { 1 ], "dailyUsage": [ - 261 + 262 ], "__typename": [ 1 @@ -4683,16 +4697,16 @@ export default { }, "UsageAnalytics": { "usageByUser": [ - 196 + 197 ], "usageByOperationType": [ - 196 + 197 ], "usageByModel": [ - 196 + 197 ], "timeSeries": [ - 261 + 262 ], "periodStart": [ 4 @@ -4701,7 +4715,7 @@ export default { 4 ], "userDailyUsage": [ - 262 + 263 ], "__typename": [ 1 @@ -4858,10 +4872,10 @@ export default { 1 ], "status": [ - 272 + 273 ], "verificationRecords": [ - 270 + 271 ], "verifiedAt": [ 4 @@ -4876,22 +4890,22 @@ export default { 3 ], "visibility": [ - 274 + 275 ], "handle": [ 1 ], "type": [ - 275 + 276 ], "isContactAutoCreationEnabled": [ 6 ], "contactAutoCreationPolicy": [ - 276 + 277 ], "messageFolderImportPolicy": [ - 277 + 278 ], "excludeNonProfessionalEmails": [ 6 @@ -4900,7 +4914,7 @@ export default { 6 ], "pendingGroupEmailsAction": [ - 278 + 279 ], "isSyncEnabled": [ 6 @@ -4909,10 +4923,10 @@ export default { 4 ], "syncStatus": [ - 279 + 280 ], "syncStage": [ - 280 + 281 ], "syncStageStartedAt": [ 4 @@ -4933,7 +4947,7 @@ export default { 4 ], "connectedAccount": [ - 238 + 239 ], "__typename": [ 1 @@ -4948,7 +4962,7 @@ export default { "MessageChannelSyncStage": {}, "CreateEmailGroupChannelOutput": { "messageChannel": [ - 273 + 274 ], "forwardingAddress": [ 1 @@ -5010,7 +5024,7 @@ export default { 21 ], "skipped": [ - 284 + 285 ], "__typename": [ 1 @@ -5033,7 +5047,7 @@ export default { 1 ], "visibility": [ - 287 + 288 ], "__typename": [ 1 @@ -5079,7 +5093,7 @@ export default { 1 ], "location": [ - 289 + 290 ], "__typename": [ 1 @@ -5096,7 +5110,7 @@ export default { 1 ], "connectionSecurity": [ - 236 + 237 ], "__typename": [ 1 @@ -5104,13 +5118,13 @@ export default { }, "ImapSmtpCaldavPublicConnectionParameters": { "IMAP": [ - 291 + 292 ], "SMTP": [ - 291 + 292 ], "CALDAV": [ - 291 + 292 ], "__typename": [ 1 @@ -5130,7 +5144,7 @@ export default { 3 ], "connectionParameters": [ - 292 + 293 ], "__typename": [ 1 @@ -5332,7 +5346,7 @@ export default { 1 ], "series": [ - 300 + 301 ], "xAxisLabel": [ 1 @@ -5381,7 +5395,7 @@ export default { 1 ], "data": [ - 302 + 303 ], "__typename": [ 1 @@ -5389,7 +5403,7 @@ export default { }, "LineChartData": { "series": [ - 303 + 304 ], "xAxisLabel": [ 1 @@ -5426,7 +5440,7 @@ export default { }, "PieChartData": { "data": [ - 305 + 306 ], "showLegend": [ 6 @@ -5528,13 +5542,13 @@ export default { }, "EventLogQueryResult": { "records": [ - 310 + 311 ], "totalCount": [ 21 ], "pageInfo": [ - 311 + 312 ], "__typename": [ 1 @@ -5598,7 +5612,7 @@ export default { 1 ], "parts": [ - 297 + 298 ], "processedAt": [ 4 @@ -5612,7 +5626,7 @@ export default { }, "AgentChatThread": { "id": [ - 218 + 219 ], "title": [ 1 @@ -5667,7 +5681,7 @@ export default { }, "AiSystemPromptPreview": { "sections": [ - 316 + 317 ], "estimatedTokenCount": [ 21 @@ -5743,10 +5757,10 @@ export default { 3 ], "evaluations": [ - 321 + 322 ], "messages": [ - 314 + 315 ], "createdAt": [ 4 @@ -5777,19 +5791,19 @@ export default { 1 ], "syncStatus": [ - 325 - ], - "syncStage": [ 326 ], - "visibility": [ + "syncStage": [ 327 ], + "visibility": [ + 328 + ], "isContactAutoCreationEnabled": [ 6 ], "contactAutoCreationPolicy": [ - 328 + 329 ], "isSyncEnabled": [ 6 @@ -5840,7 +5854,7 @@ export default { 1 ], "pendingSyncAction": [ - 330 + 331 ], "messageChannelId": [ 3 @@ -5858,7 +5872,7 @@ export default { "MessageFolderPendingSyncAction": {}, "CollectionHash": { "collectionName": [ - 332 + 333 ], "hash": [ 1 @@ -5922,13 +5936,13 @@ export default { }, "MinimalMetadata": { "objectMetadataItems": [ - 333 - ], - "views": [ 334 ], + "views": [ + 335 + ], "collectionHashes": [ - 331 + 332 ], "__typename": [ 1 @@ -5936,10 +5950,10 @@ export default { }, "Query": { "navigationMenuItems": [ - 159 + 160 ], "navigationMenuItem": [ - 159, + 160, { "id": [ 3, @@ -6081,13 +6095,13 @@ export default { 2, { "input": [ - 337, + 338, "GetApiKeyInput!" ] } ], "getInviteSuggestions": [ - 154 + 155 ], "applicationConnectionProviders": [ 127, @@ -6099,7 +6113,7 @@ export default { } ], "billingPortalSession": [ - 152, + 153, { "returnUrlPath": [ 1 @@ -6116,7 +6130,7 @@ export default { 150 ], "findWorkspaceInvitations": [ - 156 + 157 ], "getApprovedAccessDomains": [ 130 @@ -6184,13 +6198,13 @@ export default { 25, { "input": [ - 338, + 339, "AgentIdInput!" ] } ], "objectRecordCounts": [ - 211 + 212 ], "object": [ 56, @@ -6202,7 +6216,7 @@ export default { } ], "objects": [ - 212, + 213, { "paging": [ 49, @@ -6224,7 +6238,7 @@ export default { } ], "indexMetadatas": [ - 206, + 207, { "paging": [ 49, @@ -6240,7 +6254,7 @@ export default { 41, { "input": [ - 339, + 340, "LogicFunctionIdInput!" ] } @@ -6252,7 +6266,7 @@ export default { 15, { "input": [ - 339, + 340, "LogicFunctionIdInput!" ] } @@ -6261,7 +6275,7 @@ export default { 1, { "input": [ - 339, + 340, "LogicFunctionIdInput!" ] } @@ -6291,22 +6305,22 @@ export default { } ], "previewMessageCampaignAudience": [ - 282, + 283, { "input": [ - 340, + 341, "PreviewMessageCampaignAudienceInput!" ] } ], "unsubscribeTopics": [ - 286 + 287 ], "unsubscribePagePreviewUrl": [ 1 ], "myMessageChannels": [ - 273, + 274, { "connectedAccountId": [ 3 @@ -6314,16 +6328,16 @@ export default { } ], "getEmailingDomains": [ - 271 + 272 ], "myConnectedAccounts": [ - 238 + 239 ], "getRoles": [ 29 ], "getToolIndex": [ - 296 + 297 ], "getToolInputSchema": [ 15, @@ -6335,10 +6349,10 @@ export default { } ], "webhooks": [ - 295 + 296 ], "webhook": [ - 295, + 296, { "id": [ 3, @@ -6356,7 +6370,7 @@ export default { } ], "fields": [ - 216, + 217, { "paging": [ 49, @@ -6386,7 +6400,7 @@ export default { } ], "myMessageFolders": [ - 329, + 330, { "messageChannelId": [ 3 @@ -6394,7 +6408,7 @@ export default { } ], "myCalendarChannels": [ - 324, + 325, { "connectedAccountId": [ 3 @@ -6402,33 +6416,33 @@ export default { } ], "minimalMetadata": [ - 335 + 336 ], "appConnections": [ - 217, + 218, { "filter": [ - 341 + 342 ] } ], "appConnection": [ - 217, + 218, { "id": [ - 218, + 219, "ID!" ] } ], "findWorkspaceAiStats": [ - 323 + 324 ], "chatThreads": [ - 315 + 316 ], "chatThread": [ - 315, + 316, { "id": [ 3, @@ -6437,7 +6451,7 @@ export default { } ], "chatMessages": [ - 314, + 315, { "threadId": [ 3, @@ -6446,7 +6460,7 @@ export default { } ], "chatStreamCatchupChunks": [ - 318, + 319, { "threadId": [ 3, @@ -6455,13 +6469,13 @@ export default { } ], "getAiSystemPromptPreview": [ - 317 + 318 ], "skills": [ - 313 + 314 ], "skill": [ - 313, + 314, { "id": [ 3, @@ -6470,7 +6484,7 @@ export default { } ], "agentTurns": [ - 322, + 323, { "agentId": [ 3, @@ -6479,7 +6493,7 @@ export default { } ], "checkUserExists": [ - 258, + 259, { "email": [ 1, @@ -6491,7 +6505,7 @@ export default { } ], "checkWorkspaceInviteHashIsValid": [ - 259, + 260, { "inviteHash": [ 1, @@ -6509,7 +6523,7 @@ export default { } ], "checkWorkspaceSubdomainAvailability": [ - 253, + 254, { "subdomain": [ 1, @@ -6518,10 +6532,10 @@ export default { } ], "getWorkspaceCreationDefaults": [ - 254 + 255 ], "validatePasswordResetToken": [ - 251, + 252, { "passwordResetToken": [ 1, @@ -6530,7 +6544,7 @@ export default { } ], "findApplicationRegistrationByClientId": [ - 200, + 201, { "clientId": [ 1, @@ -6560,7 +6574,7 @@ export default { } ], "findApplicationRegistrationStats": [ - 198, + 199, { "id": [ 1, @@ -6569,7 +6583,7 @@ export default { } ], "findApplicationRegistrationVariables": [ - 173, + 174, { "applicationRegistrationId": [ 1, @@ -6593,7 +6607,7 @@ export default { 76 ], "getPublicWorkspaceDataByDomain": [ - 180, + 181, { "origin": [ 1 @@ -6601,7 +6615,7 @@ export default { } ], "getPublicWorkspaceDataById": [ - 181, + 182, { "id": [ 3, @@ -6624,46 +6638,46 @@ export default { } ], "getSSOIdentityProviders": [ - 223 + 224 ], "eventLogs": [ - 312, + 313, { "input": [ - 342, + 343, "EventLogQueryInput!" ] } ], "pieChartData": [ - 306, + 307, { "input": [ - 346, + 347, "PieChartDataInput!" ] } ], "lineChartData": [ - 304, + 305, { "input": [ - 347, + 348, "LineChartDataInput!" ] } ], "barChartData": [ - 301, + 302, { "input": [ - 348, + 349, "BarChartDataInput!" ] } ], "getConnectedImapSmtpCaldavAccount": [ - 293, + 294, { "id": [ 3, @@ -6672,7 +6686,7 @@ export default { } ], "getAutoCompleteAddress": [ - 288, + 289, { "address": [ 1, @@ -6691,7 +6705,7 @@ export default { } ], "getAddressDetails": [ - 290, + 291, { "placeId": [ 1, @@ -6704,21 +6718,21 @@ export default { } ], "getUsageAnalytics": [ - 263, + 264, { "input": [ - 349 + 350 ] } ], "findManyPublicDomains": [ - 269 + 270 ], "findManyMarketplaceApps": [ - 267 + 268 ], "findMarketplaceAppDetail": [ - 268, + 269, { "universalIdentifier": [ 1, @@ -6748,7 +6762,7 @@ export default { }, "LogicFunctionIdInput": { "id": [ - 218 + 219 ], "__typename": [ 1 @@ -6781,10 +6795,10 @@ export default { }, "EventLogQueryInput": { "table": [ - 343 + 344 ], "filters": [ - 344 + 345 ], "first": [ 21 @@ -6805,7 +6819,7 @@ export default { 1 ], "dateRange": [ - 345 + 346 ], "recordId": [ 1 @@ -6872,7 +6886,7 @@ export default { 1 ], "operationTypes": [ - 350 + 351 ], "__typename": [ 1 @@ -6884,7 +6898,7 @@ export default { 6, { "input": [ - 352, + 353, "AddQuerySubscriptionInput!" ] } @@ -6893,49 +6907,49 @@ export default { 6, { "input": [ - 353, + 354, "RemoveQueryFromEventStreamInput!" ] } ], "createManyNavigationMenuItems": [ - 159, + 160, { "inputs": [ - 354, + 355, "[CreateNavigationMenuItemInput!]!" ] } ], "createNavigationMenuItem": [ - 159, + 160, { "input": [ - 354, + 355, "CreateNavigationMenuItemInput!" ] } ], "updateManyNavigationMenuItems": [ - 159, + 160, { "inputs": [ - 355, + 356, "[UpdateOneNavigationMenuItemInput!]!" ] } ], "updateNavigationMenuItem": [ - 159, + 160, { "input": [ - 355, + 356, "UpdateOneNavigationMenuItemInput!" ] } ], "deleteManyNavigationMenuItems": [ - 159, + 160, { "ids": [ 3, @@ -6944,7 +6958,7 @@ export default { } ], "deleteNavigationMenuItem": [ - 159, + 160, { "id": [ 3, @@ -6956,7 +6970,7 @@ export default { 131, { "file": [ - 357, + 358, "Upload!" ] } @@ -6977,7 +6991,7 @@ export default { 131, { "file": [ - 357, + 358, "Upload!" ] } @@ -6986,7 +7000,7 @@ export default { 131, { "file": [ - 357, + 358, "Upload!" ] } @@ -6995,7 +7009,7 @@ export default { 131, { "file": [ - 357, + 358, "Upload!" ] } @@ -7004,7 +7018,7 @@ export default { 131, { "file": [ - 357, + 358, "Upload!" ] } @@ -7013,7 +7027,7 @@ export default { 131, { "file": [ - 357, + 358, "Upload!" ], "fieldMetadataId": [ @@ -7026,7 +7040,7 @@ export default { 131, { "file": [ - 357, + 358, "Upload!" ], "fieldMetadataUniversalIdentifier": [ @@ -7039,7 +7053,7 @@ export default { 62, { "input": [ - 358, + 359, "CreateViewFilterGroupInput!" ] } @@ -7052,7 +7066,7 @@ export default { "String!" ], "input": [ - 359, + 360, "UpdateViewFilterGroupInput!" ] } @@ -7079,7 +7093,7 @@ export default { 64, { "input": [ - 360, + 361, "CreateViewFilterInput!" ] } @@ -7088,7 +7102,7 @@ export default { 64, { "input": [ - 361, + 362, "UpdateViewFilterInput!" ] } @@ -7097,7 +7111,7 @@ export default { 64, { "input": [ - 363, + 364, "DeleteViewFilterInput!" ] } @@ -7106,7 +7120,7 @@ export default { 64, { "input": [ - 364, + 365, "DestroyViewFilterInput!" ] } @@ -7115,7 +7129,7 @@ export default { 70, { "input": [ - 365, + 366, "CreateViewInput!" ] } @@ -7128,7 +7142,7 @@ export default { "String!" ], "input": [ - 366, + 367, "UpdateViewInput!" ] } @@ -7155,7 +7169,7 @@ export default { 70, { "input": [ - 367, + 368, "UpsertViewWidgetInput!" ] } @@ -7164,7 +7178,7 @@ export default { 67, { "input": [ - 372, + 373, "CreateViewSortInput!" ] } @@ -7173,7 +7187,7 @@ export default { 67, { "input": [ - 373, + 374, "UpdateViewSortInput!" ] } @@ -7182,7 +7196,7 @@ export default { 6, { "input": [ - 375, + 376, "DeleteViewSortInput!" ] } @@ -7191,7 +7205,7 @@ export default { 6, { "input": [ - 376, + 377, "DestroyViewSortInput!" ] } @@ -7200,7 +7214,7 @@ export default { 60, { "input": [ - 377, + 378, "UpdateViewFieldInput!" ] } @@ -7209,7 +7223,7 @@ export default { 60, { "input": [ - 379, + 380, "CreateViewFieldInput!" ] } @@ -7218,7 +7232,7 @@ export default { 60, { "inputs": [ - 379, + 380, "[CreateViewFieldInput!]!" ] } @@ -7227,7 +7241,7 @@ export default { 60, { "input": [ - 380, + 381, "DeleteViewFieldInput!" ] } @@ -7236,7 +7250,7 @@ export default { 60, { "input": [ - 381, + 382, "DestroyViewFieldInput!" ] } @@ -7245,7 +7259,7 @@ export default { 69, { "input": [ - 382, + 383, "UpdateViewFieldGroupInput!" ] } @@ -7254,7 +7268,7 @@ export default { 69, { "input": [ - 384, + 385, "CreateViewFieldGroupInput!" ] } @@ -7263,7 +7277,7 @@ export default { 69, { "inputs": [ - 384, + 385, "[CreateViewFieldGroupInput!]!" ] } @@ -7272,7 +7286,7 @@ export default { 69, { "input": [ - 385, + 386, "DeleteViewFieldGroupInput!" ] } @@ -7281,7 +7295,7 @@ export default { 69, { "input": [ - 386, + 387, "DestroyViewFieldGroupInput!" ] } @@ -7290,7 +7304,7 @@ export default { 70, { "input": [ - 387, + 388, "UpsertFieldsWidgetInput!" ] } @@ -7299,7 +7313,7 @@ export default { 2, { "input": [ - 390, + 391, "CreateApiKeyInput!" ] } @@ -7308,7 +7322,7 @@ export default { 2, { "input": [ - 391, + 392, "UpdateApiKeyInput!" ] } @@ -7317,7 +7331,7 @@ export default { 2, { "input": [ - 392, + 393, "RevokeApiKeyInput!" ] } @@ -7336,10 +7350,10 @@ export default { } ], "skipSyncEmailOnboardingStep": [ - 155 + 156 ], "skipBookOnboardingStep": [ - 155 + 156 ], "updateOneApplicationVariable": [ 6, @@ -7359,7 +7373,7 @@ export default { } ], "checkoutSession": [ - 152, + 153, { "recurringInterval": [ 139, @@ -7378,20 +7392,44 @@ export default { ] } ], + "createSubscriptionPaymentIntent": [ + 152, + { + "recurringInterval": [ + 139, + "SubscriptionInterval!" + ], + "plan": [ + 135, + "BillingPlanKey!" + ], + "requirePaymentMethod": [ + 6, + "Boolean!" + ], + "successUrlPath": [ + 1 + ], + "idempotencyKey": [ + 1, + "String!" + ] + } + ], "switchSubscriptionInterval": [ - 153 + 154 ], "switchBillingPlan": [ - 153 + 154 ], "cancelSwitchBillingPlan": [ - 153 + 154 ], "cancelSwitchBillingInterval": [ - 153 + 154 ], "setResourceCreditSubscriptionPrice": [ - 153, + 154, { "priceId": [ 1, @@ -7403,7 +7441,7 @@ export default { 149 ], "cancelSwitchResourceCreditPrice": [ - 153 + 154 ], "deleteWorkspaceInvitation": [ 1, @@ -7415,7 +7453,7 @@ export default { } ], "resendWorkspaceInvitation": [ - 157, + 158, { "appTokenId": [ 1, @@ -7424,7 +7462,7 @@ export default { } ], "sendInvitations": [ - 157, + 158, { "emails": [ 1, @@ -7439,7 +7477,7 @@ export default { 130, { "input": [ - 393, + 394, "CreateApprovedAccessDomainInput!" ] } @@ -7448,7 +7486,7 @@ export default { 6, { "input": [ - 394, + 395, "DeleteApprovedAccessDomainInput!" ] } @@ -7457,7 +7495,7 @@ export default { 130, { "input": [ - 395, + 396, "ValidateApprovedAccessDomainInput!" ] } @@ -7466,7 +7504,7 @@ export default { 123, { "input": [ - 396, + 397, "CreatePageLayoutTabInput!" ] } @@ -7479,7 +7517,7 @@ export default { "String!" ], "input": [ - 397, + 398, "UpdatePageLayoutTabInput!" ] } @@ -7497,7 +7535,7 @@ export default { 124, { "input": [ - 398, + 399, "CreatePageLayoutInput!" ] } @@ -7510,7 +7548,7 @@ export default { "String!" ], "input": [ - 399, + 400, "UpdatePageLayoutInput!" ] } @@ -7532,7 +7570,7 @@ export default { "String!" ], "input": [ - 400, + 401, "UpdatePageLayoutWithTabsInput!" ] } @@ -7568,7 +7606,7 @@ export default { 85, { "input": [ - 404, + 405, "CreatePageLayoutWidgetInput!" ] } @@ -7581,7 +7619,7 @@ export default { "String!" ], "input": [ - 405, + 406, "UpdatePageLayoutWidgetInput!" ] } @@ -7599,7 +7637,7 @@ export default { 25, { "input": [ - 406, + 407, "CreateAgentInput!" ] } @@ -7608,7 +7646,7 @@ export default { 25, { "input": [ - 407, + 408, "UpdateAgentInput!" ] } @@ -7617,7 +7655,7 @@ export default { 25, { "input": [ - 338, + 339, "AgentIdInput!" ] } @@ -7626,7 +7664,7 @@ export default { 56, { "input": [ - 408, + 409, "CreateOneObjectInput!" ] } @@ -7635,7 +7673,7 @@ export default { 56, { "input": [ - 410, + 411, "DeleteOneObjectInput!" ] } @@ -7644,7 +7682,7 @@ export default { 56, { "input": [ - 411, + 412, "UpdateOneObjectInput!" ] } @@ -7653,7 +7691,7 @@ export default { 47, { "input": [ - 413, + 414, "CreateOneIndexInput!" ] } @@ -7662,7 +7700,7 @@ export default { 47, { "input": [ - 416, + 417, "DeleteOneIndexInput!" ] } @@ -7671,7 +7709,7 @@ export default { 41, { "input": [ - 339, + 340, "LogicFunctionIdInput!" ] } @@ -7680,16 +7718,16 @@ export default { 41, { "input": [ - 417, + 418, "CreateLogicFunctionFromSourceInput!" ] } ], "executeOneLogicFunction": [ - 168, + 169, { "input": [ - 418, + 419, "ExecuteOneLogicFunctionInput!" ] } @@ -7698,7 +7736,7 @@ export default { 6, { "input": [ - 419, + 420, "UpdateLogicFunctionFromSourceInput!" ] } @@ -7707,7 +7745,7 @@ export default { 35, { "input": [ - 421, + 422, "CreateCommandMenuItemInput!" ] } @@ -7716,7 +7754,7 @@ export default { 35, { "input": [ - 422, + 423, "UpdateCommandMenuItemInput!" ] } @@ -7743,7 +7781,7 @@ export default { 34, { "input": [ - 423, + 424, "CreateFrontComponentInput!" ] } @@ -7752,7 +7790,7 @@ export default { 34, { "input": [ - 424, + 425, "UpdateFrontComponentInput!" ] } @@ -7767,37 +7805,37 @@ export default { } ], "sendEmailViaEmailingDomain": [ - 283, + 284, { "input": [ - 426, + 427, "SendEmailViaDomainInput!" ] } ], "sendMessageCampaign": [ - 285, + 286, { "input": [ - 427, + 428, "SendMessageCampaignInput!" ] } ], "createUnsubscribeTopic": [ - 286, + 287, { "input": [ - 428, + 429, "CreateUnsubscribeTopicInput!" ] } ], "updateUnsubscribeTopic": [ - 286, + 287, { "input": [ - 429, + 430, "UpdateUnsubscribeTopicInput!" ] } @@ -7812,25 +7850,25 @@ export default { } ], "updateMessageChannel": [ - 273, + 274, { "input": [ - 430, + 431, "UpdateMessageChannelInput!" ] } ], "createEmailGroupChannel": [ - 281, + 282, { "input": [ - 432, + 433, "CreateEmailGroupChannelInput!" ] } ], "deleteEmailGroupChannel": [ - 273, + 274, { "id": [ 3, @@ -7839,10 +7877,10 @@ export default { } ], "createEmailingDomain": [ - 271, + 272, { "input": [ - 433, + 434, "CreateEmailingDomainInput!" ] } @@ -7857,7 +7895,7 @@ export default { } ], "verifyEmailingDomain": [ - 271, + 272, { "id": [ 1, @@ -7866,7 +7904,7 @@ export default { } ], "deleteConnectedAccount": [ - 238, + 239, { "id": [ 3, @@ -7891,7 +7929,7 @@ export default { 29, { "createRoleInput": [ - 434, + 435, "CreateRoleInput!" ] } @@ -7900,7 +7938,7 @@ export default { 29, { "updateRoleInput": [ - 435, + 436, "UpdateRoleInput!" ] } @@ -7918,7 +7956,7 @@ export default { 16, { "upsertObjectPermissionsInput": [ - 437, + 438, "UpsertObjectPermissionsInput!" ] } @@ -7927,7 +7965,7 @@ export default { 27, { "upsertPermissionFlagsInput": [ - 439, + 440, "UpsertPermissionFlagsInput!" ] } @@ -7936,16 +7974,16 @@ export default { 26, { "upsertFieldPermissionsInput": [ - 440, + 441, "UpsertFieldPermissionsInput!" ] } ], "upsertRowLevelPermissionPredicates": [ - 233, + 234, { "input": [ - 442, + 443, "UpsertRowLevelPermissionPredicatesInput!" ] } @@ -7973,34 +8011,34 @@ export default { } ], "runAgent": [ - 298, + 299, { "input": [ - 445, + 446, "RunAgentInput!" ] } ], "createWebhook": [ - 295, + 296, { "input": [ - 446, + 447, "CreateWebhookInput!" ] } ], "updateWebhook": [ - 295, + 296, { "input": [ - 447, + 448, "UpdateWebhookInput!" ] } ], "deleteWebhook": [ - 295, + 296, { "id": [ 3, @@ -8012,7 +8050,7 @@ export default { 44, { "input": [ - 449, + 450, "CreateOneFieldMetadataInput!" ] } @@ -8021,7 +8059,7 @@ export default { 44, { "input": [ - 451, + 452, "UpdateOneFieldMetadataInput!" ] } @@ -8030,7 +8068,7 @@ export default { 44, { "input": [ - 453, + 454, "DeleteOneFieldInput!" ] } @@ -8039,7 +8077,7 @@ export default { 66, { "input": [ - 454, + 455, "CreateViewGroupInput!" ] } @@ -8048,7 +8086,7 @@ export default { 66, { "inputs": [ - 454, + 455, "[CreateViewGroupInput!]!" ] } @@ -8057,7 +8095,7 @@ export default { 66, { "input": [ - 455, + 456, "UpdateViewGroupInput!" ] } @@ -8066,7 +8104,7 @@ export default { 66, { "inputs": [ - 455, + 456, "[UpdateViewGroupInput!]!" ] } @@ -8075,7 +8113,7 @@ export default { 66, { "input": [ - 457, + 458, "DeleteViewGroupInput!" ] } @@ -8084,43 +8122,43 @@ export default { 66, { "input": [ - 458, + 459, "DestroyViewGroupInput!" ] } ], "updateMessageFolder": [ - 329, + 330, { "input": [ - 459, + 460, "UpdateMessageFolderInput!" ] } ], "updateMessageFolders": [ - 329, + 330, { "input": [ - 461, + 462, "UpdateMessageFoldersInput!" ] } ], "updateCalendarChannel": [ - 324, + 325, { "input": [ - 462, + 463, "UpdateCalendarChannelInput!" ] } ], "createChatThread": [ - 315 + 316 ], "sendChatMessage": [ - 319, + 320, { "threadId": [ 3, @@ -8141,7 +8179,7 @@ export default { 1 ], "fileAttachments": [ - 464, + 465, "[FileAttachmentInput!]" ] } @@ -8156,7 +8194,7 @@ export default { } ], "renameChatThread": [ - 315, + 316, { "id": [ 3, @@ -8169,7 +8207,7 @@ export default { } ], "archiveChatThread": [ - 315, + 316, { "id": [ 3, @@ -8178,7 +8216,7 @@ export default { } ], "unarchiveChatThread": [ - 315, + 316, { "id": [ 3, @@ -8205,25 +8243,25 @@ export default { } ], "createSkill": [ - 313, + 314, { "input": [ - 465, + 466, "CreateSkillInput!" ] } ], "updateSkill": [ - 313, + 314, { "input": [ - 466, + 467, "UpdateSkillInput!" ] } ], "deleteSkill": [ - 313, + 314, { "id": [ 3, @@ -8232,7 +8270,7 @@ export default { } ], "activateSkill": [ - 313, + 314, { "id": [ 3, @@ -8241,7 +8279,7 @@ export default { } ], "deactivateSkill": [ - 313, + 314, { "id": [ 3, @@ -8250,7 +8288,7 @@ export default { } ], "evaluateAgentTurn": [ - 321, + 322, { "turnId": [ 3, @@ -8259,7 +8297,7 @@ export default { } ], "runEvaluationInput": [ - 322, + 323, { "agentId": [ 3, @@ -8272,16 +8310,16 @@ export default { } ], "getAuthorizationUrlForSSO": [ - 246, + 247, { "input": [ - 467, + 468, "GetAuthorizationUrlForSSOInput!" ] } ], "getLoginTokenFromCredentials": [ - 257, + 258, { "email": [ 1, @@ -8307,7 +8345,7 @@ export default { } ], "signIn": [ - 244, + 245, { "email": [ 1, @@ -8329,7 +8367,7 @@ export default { } ], "verifyEmailAndGetLoginToken": [ - 252, + 253, { "emailVerificationToken": [ 1, @@ -8349,7 +8387,7 @@ export default { } ], "verifyEmailAndGetWorkspaceAgnosticToken": [ - 244, + 245, { "emailVerificationToken": [ 1, @@ -8365,7 +8403,7 @@ export default { } ], "getAuthTokensFromOTP": [ - 256, + 257, { "otp": [ 1, @@ -8385,7 +8423,7 @@ export default { } ], "signUp": [ - 244, + 245, { "email": [ 1, @@ -8407,7 +8445,7 @@ export default { } ], "signUpInWorkspace": [ - 249, + 250, { "email": [ 1, @@ -8438,10 +8476,10 @@ export default { } ], "signUpInNewWorkspace": [ - 249, + 250, { "input": [ - 468 + 469 ] } ], @@ -8453,16 +8491,16 @@ export default { "String!" ], "file": [ - 357, + 358, "Upload!" ] } ], "generateTransientToken": [ - 250 + 251 ], "getAuthTokensFromLoginToken": [ - 256, + 257, { "loginToken": [ 1, @@ -8475,7 +8513,7 @@ export default { } ], "authorizeApp": [ - 242, + 243, { "clientId": [ 1, @@ -8497,7 +8535,7 @@ export default { } ], "renewToken": [ - 256, + 257, { "appToken": [ 1, @@ -8506,7 +8544,7 @@ export default { } ], "generateApiKeyToken": [ - 255, + 256, { "apiKeyId": [ 3, @@ -8522,7 +8560,7 @@ export default { 32 ], "emailPasswordResetLink": [ - 245, + 246, { "email": [ 1, @@ -8534,7 +8572,7 @@ export default { } ], "updatePasswordViaResetToken": [ - 247, + 248, { "passwordResetToken": [ 1, @@ -8547,10 +8585,10 @@ export default { } ], "createApplicationRegistration": [ - 199, + 200, { "input": [ - 469, + 470, "CreateApplicationRegistrationInput!" ] } @@ -8559,7 +8597,7 @@ export default { 7, { "input": [ - 470, + 471, "UpdateApplicationRegistrationInput!" ] } @@ -8574,7 +8612,7 @@ export default { } ], "rotateApplicationRegistrationClientSecret": [ - 201, + 202, { "id": [ 1, @@ -8586,7 +8624,7 @@ export default { 5, { "input": [ - 472, + 473, "CreateApplicationRegistrationVariableInput!" ] } @@ -8595,7 +8633,7 @@ export default { 5, { "input": [ - 473, + 474, "UpdateApplicationRegistrationVariableInput!" ] } @@ -8613,7 +8651,7 @@ export default { 7, { "file": [ - 357, + 358, "Upload!" ], "universalIdentifier": [ @@ -8635,7 +8673,7 @@ export default { } ], "initiateOTPProvisioning": [ - 240, + 241, { "loginToken": [ 1, @@ -8648,10 +8686,10 @@ export default { } ], "initiateOTPProvisioningForAuthenticatedUser": [ - 240 + 241 ], "deleteTwoFactorAuthenticationMethod": [ - 239, + 240, { "twoFactorAuthenticationMethodId": [ 3, @@ -8660,7 +8698,7 @@ export default { } ], "verifyTwoFactorAuthenticationMethodForAuthenticatedUser": [ - 241, + 242, { "otp": [ 1, @@ -8684,7 +8722,7 @@ export default { 6, { "input": [ - 475, + 476, "UpdateWorkspaceMemberSettingsInput!" ] } @@ -8702,7 +8740,7 @@ export default { } ], "resendEmailVerificationToken": [ - 219, + 220, { "email": [ 1, @@ -8718,7 +8756,7 @@ export default { 76, { "data": [ - 476, + 477, "ActivateWorkspaceInput!" ] } @@ -8727,7 +8765,7 @@ export default { 76, { "data": [ - 477, + 478, "UpdateWorkspaceInput!" ] } @@ -8736,13 +8774,13 @@ export default { 76 ], "checkCustomDomainValidRecords": [ - 232 + 233 ], "runWorkspaceMigration": [ 6, { "workspaceMigration": [ - 478, + 479, "WorkspaceMigrationInput!" ] } @@ -8757,43 +8795,43 @@ export default { } ], "createOIDCIdentityProvider": [ - 224, + 225, { "input": [ - 481, + 482, "SetupOIDCSsoInput!" ] } ], "createSAMLIdentityProvider": [ - 224, + 225, { "input": [ - 482, + 483, "SetupSAMLSsoInput!" ] } ], "deleteSSOIdentityProvider": [ - 220, + 221, { "input": [ - 483, + 484, "DeleteSsoInput!" ] } ], "editSSOIdentityProvider": [ - 221, + 222, { "input": [ - 484, + 485, "EditSsoInput!" ] } ], "createObjectEvent": [ - 309, + 310, { "event": [ 1, @@ -8813,10 +8851,10 @@ export default { } ], "trackAnalytics": [ - 309, + 310, { "type": [ - 485, + 486, "AnalyticsType!" ], "name": [ @@ -8831,7 +8869,7 @@ export default { } ], "duplicateDashboard": [ - 307, + 308, { "id": [ 3, @@ -8840,7 +8878,7 @@ export default { } ], "impersonate": [ - 260, + 261, { "userId": [ 3, @@ -8853,16 +8891,16 @@ export default { } ], "sendEmail": [ - 308, + 309, { "input": [ - 486, + 487, "SendEmailInput!" ] } ], "startChannelSync": [ - 299, + 300, { "connectedAccountId": [ 3, @@ -8871,14 +8909,14 @@ export default { } ], "saveImapSmtpCaldavAccount": [ - 294, + 295, { "handle": [ 1, "String!" ], "connectionParameters": [ - 488, + 489, "EmailAccountConnectionParameters!" ], "id": [ @@ -8887,16 +8925,16 @@ export default { } ], "updateLabPublicFeatureFlag": [ - 170, + 171, { "input": [ - 490, + 491, "UpdateLabPublicFeatureFlagInput!" ] } ], "createPublicDomain": [ - 269, + 270, { "domain": [ 1, @@ -8908,7 +8946,7 @@ export default { } ], "updatePublicDomain": [ - 269, + 270, { "domain": [ 1, @@ -8929,7 +8967,7 @@ export default { } ], "checkPublicDomainValidRecords": [ - 232, + 233, { "domain": [ 1, @@ -8941,7 +8979,7 @@ export default { 78, { "input": [ - 491, + 492, "CreateOneAppTokenInput!" ] } @@ -8974,7 +9012,7 @@ export default { 6 ], "createDevelopmentApplication": [ - 264, + 265, { "universalIdentifier": [ 1, @@ -8996,7 +9034,7 @@ export default { } ], "syncApplication": [ - 265, + 266, { "manifest": [ 15, @@ -9008,10 +9046,10 @@ export default { } ], "uploadApplicationFile": [ - 266, + 267, { "file": [ - 357, + 358, "Upload!" ], "applicationUniversalIdentifier": [ @@ -9019,7 +9057,7 @@ export default { "String!" ], "fileFolder": [ - 493, + 494, "FileFolder!" ], "filePath": [ @@ -9096,7 +9134,7 @@ export default { 3 ], "type": [ - 160 + 161 ], "name": [ 1 @@ -9128,7 +9166,7 @@ export default { 3 ], "update": [ - 356 + 357 ], "__typename": [ 1 @@ -9238,7 +9276,7 @@ export default { 3 ], "update": [ - 362 + 363 ], "__typename": [ 1 @@ -9397,17 +9435,17 @@ export default { 3 ], "viewFields": [ - 368 - ], - "viewFilters": [ 369 ], - "viewFilterGroups": [ + "viewFilters": [ 370 ], - "viewSorts": [ + "viewFilterGroups": [ 371 ], + "viewSorts": [ + 372 + ], "__typename": [ 1 ] @@ -9517,7 +9555,7 @@ export default { 3 ], "update": [ - 374 + 375 ], "__typename": [ 1 @@ -9555,7 +9593,7 @@ export default { 3 ], "update": [ - 378 + 379 ], "__typename": [ 1 @@ -9631,7 +9669,7 @@ export default { 3 ], "update": [ - 383 + 384 ], "__typename": [ 1 @@ -9695,10 +9733,10 @@ export default { 3 ], "groups": [ - 388 + 389 ], "fields": [ - 389 + 390 ], "__typename": [ 1 @@ -9718,7 +9756,7 @@ export default { 6 ], "fields": [ - 389 + 390 ], "__typename": [ 1 @@ -9886,7 +9924,7 @@ export default { 3 ], "tabs": [ - 401 + 402 ], "__typename": [ 1 @@ -9909,7 +9947,7 @@ export default { 89 ], "widgets": [ - 402 + 403 ], "__typename": [ 1 @@ -9932,7 +9970,7 @@ export default { 3 ], "gridPosition": [ - 403 + 404 ], "position": [ 15 @@ -9981,7 +10019,7 @@ export default { 3 ], "gridPosition": [ - 403 + 404 ], "position": [ 15 @@ -10007,7 +10045,7 @@ export default { 3 ], "gridPosition": [ - 403 + 404 ], "position": [ 15 @@ -10100,7 +10138,7 @@ export default { }, "CreateOneObjectInput": { "object": [ - 409 + 410 ], "__typename": [ 1 @@ -10160,7 +10198,7 @@ export default { }, "UpdateOneObjectInput": { "update": [ - 412 + 413 ], "id": [ 3 @@ -10215,7 +10253,7 @@ export default { }, "CreateOneIndexInput": { "index": [ - 414 + 415 ], "__typename": [ 1 @@ -10226,7 +10264,7 @@ export default { 3 ], "fields": [ - 415 + 416 ], "indexType": [ 48 @@ -10308,7 +10346,7 @@ export default { 3 ], "update": [ - 420 + 421 ], "__typename": [ 1 @@ -10468,7 +10506,7 @@ export default { 3 ], "update": [ - 425 + 426 ], "__typename": [ 1 @@ -10545,7 +10583,7 @@ export default { 1 ], "visibility": [ - 287 + 288 ], "__typename": [ 1 @@ -10562,7 +10600,7 @@ export default { 1 ], "visibility": [ - 287 + 288 ], "__typename": [ 1 @@ -10573,7 +10611,7 @@ export default { 3 ], "update": [ - 431 + 432 ], "__typename": [ 1 @@ -10581,16 +10619,16 @@ export default { }, "UpdateMessageChannelInputUpdates": { "visibility": [ - 274 + 275 ], "isContactAutoCreationEnabled": [ 6 ], "contactAutoCreationPolicy": [ - 276 + 277 ], "messageFolderImportPolicy": [ - 277 + 278 ], "isSyncEnabled": [ 6 @@ -10667,7 +10705,7 @@ export default { }, "UpdateRoleInput": { "update": [ - 436 + 437 ], "id": [ 3 @@ -10722,7 +10760,7 @@ export default { 3 ], "objectPermissions": [ - 438 + 439 ], "__typename": [ 1 @@ -10764,7 +10802,7 @@ export default { 3 ], "fieldPermissions": [ - 441 + 442 ], "__typename": [ 1 @@ -10795,10 +10833,10 @@ export default { 3 ], "predicates": [ - 443 + 444 ], "predicateGroups": [ - 444 + 445 ], "__typename": [ 1 @@ -10892,7 +10930,7 @@ export default { 3 ], "update": [ - 448 + 449 ], "__typename": [ 1 @@ -10917,7 +10955,7 @@ export default { }, "CreateOneFieldMetadataInput": { "field": [ - 450 + 451 ], "__typename": [ 1 @@ -10990,7 +11028,7 @@ export default { 3 ], "update": [ - 452 + 453 ], "__typename": [ 1 @@ -11085,7 +11123,7 @@ export default { 3 ], "update": [ - 456 + 457 ], "__typename": [ 1 @@ -11129,7 +11167,7 @@ export default { 3 ], "update": [ - 460 + 461 ], "__typename": [ 1 @@ -11148,7 +11186,7 @@ export default { 3 ], "update": [ - 460 + 461 ], "__typename": [ 1 @@ -11159,7 +11197,7 @@ export default { 3 ], "update": [ - 463 + 464 ], "__typename": [ 1 @@ -11167,13 +11205,13 @@ export default { }, "UpdateCalendarChannelInputUpdates": { "visibility": [ - 327 + 328 ], "isContactAutoCreationEnabled": [ 6 ], "contactAutoCreationPolicy": [ - 328 + 329 ], "isSyncEnabled": [ 6 @@ -11286,7 +11324,7 @@ export default { 1 ], "update": [ - 471 + 472 ], "__typename": [ 1 @@ -11334,7 +11372,7 @@ export default { 1 ], "update": [ - 474 + 475 ], "__typename": [ 1 @@ -11452,7 +11490,7 @@ export default { }, "WorkspaceMigrationInput": { "actions": [ - 479 + 480 ], "__typename": [ 1 @@ -11460,10 +11498,10 @@ export default { }, "WorkspaceMigrationDeleteActionInput": { "type": [ - 480 + 481 ], "metadataName": [ - 332 + 333 ], "universalIdentifier": [ 1 @@ -11526,7 +11564,7 @@ export default { 3 ], "status": [ - 177 + 178 ], "__typename": [ 1 @@ -11556,7 +11594,7 @@ export default { 1 ], "files": [ - 487 + 488 ], "__typename": [ 1 @@ -11575,13 +11613,13 @@ export default { }, "EmailAccountConnectionParameters": { "IMAP": [ - 489 + 490 ], "SMTP": [ - 489 + 490 ], "CALDAV": [ - 489 + 490 ], "__typename": [ 1 @@ -11601,7 +11639,7 @@ export default { 1 ], "connectionSecurity": [ - 236 + 237 ], "__typename": [ 1 @@ -11620,7 +11658,7 @@ export default { }, "CreateOneAppTokenInput": { "appToken": [ - 492 + 493 ], "__typename": [ 1 @@ -11637,7 +11675,7 @@ export default { "FileFolder": {}, "Subscription": { "onEventSubscription": [ - 167, + 168, { "eventStreamId": [ 1, @@ -11646,16 +11684,16 @@ export default { } ], "logicFunctionLogs": [ - 234, + 235, { "input": [ - 495, + 496, "LogicFunctionLogsInput!" ] } ], "onAgentChatEvent": [ - 320, + 321, { "threadId": [ 3, @@ -11664,10 +11702,10 @@ export default { } ], "eventLogsLive": [ - 310, + 311, { "table": [ - 343, + 344, "EventLogTable!" ] } diff --git a/packages/twenty-front/package.json b/packages/twenty-front/package.json index 0183477647..ef7f4ebc46 100644 --- a/packages/twenty-front/package.json +++ b/packages/twenty-front/package.json @@ -62,6 +62,8 @@ "@scalar/api-reference-react": "^0.9.42", "@sentry/react": "^10.51.0", "@sniptt/guards": "^0.2.0", + "@stripe/react-stripe-js": "^6.6.0", + "@stripe/stripe-js": "^9.8.0", "@tiptap/core": "3.4.2", "@tiptap/extension-bold": "3.4.2", "@tiptap/extension-document": "3.4.2", diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index 7e93128138..734a44c984 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -566,6 +566,7 @@ export type Billing = { __typename?: 'Billing'; billingUrl?: Maybe; isBillingEnabled: Scalars['Boolean']['output']; + stripePublishableKey?: Maybe; trialPeriods: Array; }; @@ -616,6 +617,12 @@ export type BillingMeteredProduct = BillingProductDto & { prices?: Maybe>; }; +export type BillingPaymentIntent = { + __typename?: 'BillingPaymentIntent'; + clientSecret: Scalars['String']['output']; + paymentIntentType: Scalars['String']['output']; +}; + export type BillingPlan = { __typename?: 'BillingPlan'; baseProducts: Array; @@ -2482,6 +2489,7 @@ export type Mutation = { createPublicDomain: PublicDomain; createSAMLIdentityProvider: SetupSso; createSkill: Skill; + createSubscriptionPaymentIntent: BillingPaymentIntent; createUnsubscribeTopic: UnsubscribeTopic; createView: View; createViewField: ViewField; @@ -2866,6 +2874,15 @@ export type MutationCreateSkillArgs = { }; +export type MutationCreateSubscriptionPaymentIntentArgs = { + idempotencyKey: Scalars['String']['input']; + plan?: BillingPlanKey; + recurringInterval: SubscriptionInterval; + requirePaymentMethod?: Scalars['Boolean']['input']; + successUrlPath?: InputMaybe; +}; + + export type MutationCreateUnsubscribeTopicArgs = { input: CreateUnsubscribeTopicInput; }; @@ -7717,6 +7734,15 @@ export type CheckoutSessionMutationVariables = Exact<{ export type CheckoutSessionMutation = { __typename?: 'Mutation', checkoutSession: { __typename?: 'BillingSession', url?: string | null } }; +export type CreateSubscriptionPaymentIntentMutationVariables = Exact<{ + recurringInterval: SubscriptionInterval; + plan: BillingPlanKey; + idempotencyKey: Scalars['String']['input']; +}>; + + +export type CreateSubscriptionPaymentIntentMutation = { __typename?: 'Mutation', createSubscriptionPaymentIntent: { __typename?: 'BillingPaymentIntent', clientSecret: string, paymentIntentType: string } }; + export type EndSubscriptionTrialPeriodMutationVariables = Exact<{ [key: string]: never; }>; @@ -8803,6 +8829,7 @@ export const CancelSwitchBillingIntervalDocument = {"kind":"Document","definitio export const CancelSwitchBillingPlanDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CancelSwitchBillingPlan"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cancelSwitchBillingPlan"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentBillingSubscription"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CurrentBillingSubscriptionFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"billingSubscriptions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseItemFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhase"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start_date"}},{"kind":"Field","name":{"kind":"Name","value":"end_date"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseItemFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CurrentBillingSubscriptionFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscription"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"interval"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"currentPeriodEnd"}},{"kind":"Field","name":{"kind":"Name","value":"phases"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"billingSubscriptionItems"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"hasReachedCurrentPeriodCap"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}},{"kind":"Field","name":{"kind":"Name","value":"stripePriceId"}},{"kind":"Field","name":{"kind":"Name","value":"billingProduct"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"images"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"productKey"}},{"kind":"Field","name":{"kind":"Name","value":"planKey"}},{"kind":"Field","name":{"kind":"Name","value":"priceUsageBased"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingSubscriptionFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscription"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"phases"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseFragment"}}]}}]}}]} as unknown as DocumentNode; export const CancelSwitchResourceCreditPriceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CancelSwitchResourceCreditPrice"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"cancelSwitchResourceCreditPrice"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentBillingSubscription"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CurrentBillingSubscriptionFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"billingSubscriptions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseItemFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhase"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start_date"}},{"kind":"Field","name":{"kind":"Name","value":"end_date"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseItemFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CurrentBillingSubscriptionFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscription"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"interval"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"currentPeriodEnd"}},{"kind":"Field","name":{"kind":"Name","value":"phases"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"billingSubscriptionItems"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"hasReachedCurrentPeriodCap"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}},{"kind":"Field","name":{"kind":"Name","value":"stripePriceId"}},{"kind":"Field","name":{"kind":"Name","value":"billingProduct"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"images"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"productKey"}},{"kind":"Field","name":{"kind":"Name","value":"planKey"}},{"kind":"Field","name":{"kind":"Name","value":"priceUsageBased"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingSubscriptionFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscription"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"phases"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseFragment"}}]}}]}}]} as unknown as DocumentNode; export const CheckoutSessionDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CheckoutSession"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"recurringInterval"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriptionInterval"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"successUrlPath"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"plan"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"BillingPlanKey"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"requirePaymentMethod"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"Boolean"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"checkoutSession"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"recurringInterval"},"value":{"kind":"Variable","name":{"kind":"Name","value":"recurringInterval"}}},{"kind":"Argument","name":{"kind":"Name","value":"successUrlPath"},"value":{"kind":"Variable","name":{"kind":"Name","value":"successUrlPath"}}},{"kind":"Argument","name":{"kind":"Name","value":"plan"},"value":{"kind":"Variable","name":{"kind":"Name","value":"plan"}}},{"kind":"Argument","name":{"kind":"Name","value":"requirePaymentMethod"},"value":{"kind":"Variable","name":{"kind":"Name","value":"requirePaymentMethod"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}}]} as unknown as DocumentNode; +export const CreateSubscriptionPaymentIntentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"CreateSubscriptionPaymentIntent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"recurringInterval"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"SubscriptionInterval"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"plan"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"BillingPlanKey"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"idempotencyKey"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"createSubscriptionPaymentIntent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"recurringInterval"},"value":{"kind":"Variable","name":{"kind":"Name","value":"recurringInterval"}}},{"kind":"Argument","name":{"kind":"Name","value":"plan"},"value":{"kind":"Variable","name":{"kind":"Name","value":"plan"}}},{"kind":"Argument","name":{"kind":"Name","value":"idempotencyKey"},"value":{"kind":"Variable","name":{"kind":"Name","value":"idempotencyKey"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"clientSecret"}},{"kind":"Field","name":{"kind":"Name","value":"paymentIntentType"}}]}}]}}]} as unknown as DocumentNode; export const EndSubscriptionTrialPeriodDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"EndSubscriptionTrialPeriod"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"endSubscriptionTrialPeriod"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"hasPaymentMethod"}},{"kind":"Field","name":{"kind":"Name","value":"billingPortalUrl"}}]}}]}}]} as unknown as DocumentNode; export const SetResourceCreditSubscriptionPriceDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SetResourceCreditSubscriptionPrice"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"priceId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"setResourceCreditSubscriptionPrice"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"priceId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"priceId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentBillingSubscription"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CurrentBillingSubscriptionFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"billingSubscriptions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseItemFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhase"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start_date"}},{"kind":"Field","name":{"kind":"Name","value":"end_date"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseItemFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CurrentBillingSubscriptionFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscription"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"interval"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"currentPeriodEnd"}},{"kind":"Field","name":{"kind":"Name","value":"phases"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"billingSubscriptionItems"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"hasReachedCurrentPeriodCap"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}},{"kind":"Field","name":{"kind":"Name","value":"stripePriceId"}},{"kind":"Field","name":{"kind":"Name","value":"billingProduct"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"images"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"productKey"}},{"kind":"Field","name":{"kind":"Name","value":"planKey"}},{"kind":"Field","name":{"kind":"Name","value":"priceUsageBased"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingSubscriptionFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscription"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"phases"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseFragment"}}]}}]}}]} as unknown as DocumentNode; export const SwitchBillingPlanDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"SwitchBillingPlan"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"switchBillingPlan"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"currentBillingSubscription"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"CurrentBillingSubscriptionFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"billingSubscriptions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionFragment"}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseItemFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseItem"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"price"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhase"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"start_date"}},{"kind":"Field","name":{"kind":"Name","value":"end_date"}},{"kind":"Field","name":{"kind":"Name","value":"items"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseItemFragment"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"CurrentBillingSubscriptionFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscription"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"interval"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"currentPeriodEnd"}},{"kind":"Field","name":{"kind":"Name","value":"phases"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseFragment"}}]}},{"kind":"Field","name":{"kind":"Name","value":"billingSubscriptionItems"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"hasReachedCurrentPeriodCap"}},{"kind":"Field","name":{"kind":"Name","value":"quantity"}},{"kind":"Field","name":{"kind":"Name","value":"stripePriceId"}},{"kind":"Field","name":{"kind":"Name","value":"billingProduct"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"images"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"productKey"}},{"kind":"Field","name":{"kind":"Name","value":"planKey"}},{"kind":"Field","name":{"kind":"Name","value":"priceUsageBased"}}]}}]}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"BillingSubscriptionFragment"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"BillingSubscription"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"metadata"}},{"kind":"Field","name":{"kind":"Name","value":"phases"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"BillingSubscriptionSchedulePhaseFragment"}}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/twenty-front/src/modules/settings/billing/components/SubscriptionPaymentForm.tsx b/packages/twenty-front/src/modules/settings/billing/components/SubscriptionPaymentForm.tsx new file mode 100644 index 0000000000..23629a68d3 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/billing/components/SubscriptionPaymentForm.tsx @@ -0,0 +1,190 @@ +import { currentUserState } from '@/auth/states/currentUserState'; +import { useStripeAppearance } from '@/settings/billing/hooks/useStripeAppearance'; +import { useStripePromise } from '@/settings/billing/hooks/useStripePromise'; +import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar'; +import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; +import { CombinedGraphQLErrors } from '@apollo/client/errors'; +import { useMutation } from '@apollo/client/react'; +import { styled } from '@linaria/react'; +import { t } from '@lingui/core/macro'; +import { + Elements, + PaymentElement, + useElements, + useStripe, +} from '@stripe/react-stripe-js'; +import { useState } from 'react'; +import { AppPath } from 'twenty-shared/types'; +import { isDefined } from 'twenty-shared/utils'; +import { Info, Loader } from 'twenty-ui/feedback'; +import { MainButton } from 'twenty-ui/input'; +import { themeCssVariables } from 'twenty-ui/theme-constants'; +import { + type BillingPlanKey, + type SubscriptionInterval, + CreateSubscriptionPaymentIntentDocument, +} from '~/generated-metadata/graphql'; + +type SubscriptionPaymentFormContentProps = { + plan: BillingPlanKey; + recurringInterval: SubscriptionInterval; +}; + +type SubscriptionPaymentFormProps = SubscriptionPaymentFormContentProps & { + amount: number; +}; + +const StyledFormContainer = styled.div` + display: flex; + flex-direction: column; + gap: ${themeCssVariables.spacing[4]}; + margin-bottom: ${themeCssVariables.spacing[8]}; + width: 100%; +`; + +const StyledButtonContainer = styled.div` + display: flex; + justify-content: center; +`; + +const SubscriptionPaymentFormContent = ({ + plan, + recurringInterval, +}: SubscriptionPaymentFormContentProps) => { + const stripe = useStripe(); + const elements = useElements(); + const { enqueueErrorSnackBar } = useSnackBar(); + const [isSubmitting, setIsSubmitting] = useState(false); + + const customerEmail = useAtomStateValue(currentUserState)?.email; + + const [createSubscriptionPaymentIntent] = useMutation( + CreateSubscriptionPaymentIntentDocument, + ); + + const isStripeReady = isDefined(stripe) && isDefined(elements); + + const handleSubmit = async () => { + if (!isStripeReady) { + return; + } + + setIsSubmitting(true); + + try { + const { error: submitError } = await elements.submit(); + if (isDefined(submitError)) { + enqueueErrorSnackBar({ + message: + submitError.message ?? + t`Your payment details are incomplete. Please review and retry.`, + }); + setIsSubmitting(false); + return; + } + + const idempotencyKey = crypto.randomUUID(); + const { data } = await createSubscriptionPaymentIntent({ + variables: { recurringInterval, plan, idempotencyKey }, + }); + + const paymentIntent = data?.createSubscriptionPaymentIntent; + if (!isDefined(paymentIntent?.clientSecret)) { + enqueueErrorSnackBar({ + message: t`Subscription error. Please retry or contact Twenty team`, + }); + setIsSubmitting(false); + return; + } + + const returnUrl = new URL( + AppPath.PlanRequiredSuccess, + window.location.origin, + ).toString(); + + const { error } = + paymentIntent.paymentIntentType === 'setup' + ? await stripe.confirmSetup({ + elements, + clientSecret: paymentIntent.clientSecret, + confirmParams: { return_url: returnUrl }, + }) + : await stripe.confirmPayment({ + elements, + clientSecret: paymentIntent.clientSecret, + confirmParams: { return_url: returnUrl }, + }); + + if (isDefined(error)) { + enqueueErrorSnackBar({ + message: + error.message ?? + t`We couldn't confirm your payment method. Please retry.`, + }); + setIsSubmitting(false); + } + } catch (error) { + if (CombinedGraphQLErrors.is(error)) { + enqueueErrorSnackBar({ apolloError: error }); + } else { + enqueueErrorSnackBar({ + message: t`Subscription error. Please retry or contact Twenty team`, + }); + } + setIsSubmitting(false); + } + }; + + return ( + + + + (isSubmitting ? : null)} + disabled={!isStripeReady || isSubmitting} + /> + + + ); +}; + +export const SubscriptionPaymentForm = ({ + plan, + recurringInterval, + amount, +}: SubscriptionPaymentFormProps) => { + const stripePromise = useStripePromise(); + const appearance = useStripeAppearance(); + + if (!isDefined(stripePromise)) { + return ( + + + + ); + } + + return ( + + + + ); +}; diff --git a/packages/twenty-front/src/modules/settings/billing/components/TrialCard.tsx b/packages/twenty-front/src/modules/settings/billing/components/TrialCard.tsx index 5ed876ec1f..e0374a484c 100644 --- a/packages/twenty-front/src/modules/settings/billing/components/TrialCard.tsx +++ b/packages/twenty-front/src/modules/settings/billing/components/TrialCard.tsx @@ -31,7 +31,7 @@ export const TrialCard = ({ duration, withCreditCard }: TrialCardProps) => { {t`${duration} days trial`} - {withCreditCard ? t`With Credit Card` : t`Without Credit Card`} + {withCreditCard ? t`With Credit Card` : t`No Credit Card`} ); diff --git a/packages/twenty-front/src/modules/settings/billing/graphql/mutations/createSubscriptionPaymentIntent.ts b/packages/twenty-front/src/modules/settings/billing/graphql/mutations/createSubscriptionPaymentIntent.ts new file mode 100644 index 0000000000..da84a27e81 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/billing/graphql/mutations/createSubscriptionPaymentIntent.ts @@ -0,0 +1,18 @@ +import { gql } from '@apollo/client'; + +export const CREATE_SUBSCRIPTION_PAYMENT_INTENT = gql` + mutation CreateSubscriptionPaymentIntent( + $recurringInterval: SubscriptionInterval! + $plan: BillingPlanKey! + $idempotencyKey: String! + ) { + createSubscriptionPaymentIntent( + recurringInterval: $recurringInterval + plan: $plan + idempotencyKey: $idempotencyKey + ) { + clientSecret + paymentIntentType + } + } +`; diff --git a/packages/twenty-front/src/modules/settings/billing/hooks/useStripeAppearance.ts b/packages/twenty-front/src/modules/settings/billing/hooks/useStripeAppearance.ts new file mode 100644 index 0000000000..ecfff268a6 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/billing/hooks/useStripeAppearance.ts @@ -0,0 +1,42 @@ +import { type Appearance } from '@stripe/stripe-js'; +import { useContext } from 'react'; +import { isDefined } from 'twenty-shared/utils'; +import { THEME_DARK, THEME_LIGHT } from 'twenty-ui/theme'; +import { ThemeContext } from 'twenty-ui/theme-constants'; + +// Stripe's Appearance API rejects CSS color(display-p3 ...) values, which is +// how the Twenty theme stores colors; map them to sRGB so the PaymentElement +// is themed instead of silently falling back to Stripe defaults. +const toStripeColor = (color: string): string => { + const match = color.match( + /^color\(display-p3\s+([\d.]+)\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*([\d.]+))?\)$/, + ); + + if (!isDefined(match)) { + return color; + } + + const [, red, green, blue, alpha] = match; + const toByte = (value: string) => Math.round(Number(value) * 255); + const rgb = `${toByte(red)}, ${toByte(green)}, ${toByte(blue)}`; + + // oxlint-disable-next-line twenty/no-hardcoded-colors + return isDefined(alpha) ? `rgba(${rgb}, ${alpha})` : `rgb(${rgb})`; +}; + +export const useStripeAppearance = (): Appearance => { + const { colorScheme } = useContext(ThemeContext); + const isDark = colorScheme === 'dark'; + const theme = isDark ? THEME_DARK : THEME_LIGHT; + + return { + theme: isDark ? 'night' : 'stripe', + variables: { + colorPrimary: toStripeColor(theme.color.blue), + colorBackground: toStripeColor(theme.background.primary), + colorText: toStripeColor(theme.font.color.primary), + colorDanger: toStripeColor(theme.font.color.danger), + borderRadius: '8px', + }, + }; +}; diff --git a/packages/twenty-front/src/modules/settings/billing/hooks/useStripePromise.ts b/packages/twenty-front/src/modules/settings/billing/hooks/useStripePromise.ts new file mode 100644 index 0000000000..e38be9a163 --- /dev/null +++ b/packages/twenty-front/src/modules/settings/billing/hooks/useStripePromise.ts @@ -0,0 +1,30 @@ +import { billingState } from '@/client-config/states/billingState'; +import { useAtomStateValue } from '@/ui/utilities/state/jotai/hooks/useAtomStateValue'; +import { type Stripe } from '@stripe/stripe-js'; +import { loadStripe } from '@stripe/stripe-js/pure'; +import { isDefined } from 'twenty-shared/utils'; + +const stripePromiseByKey = new Map>(); + +const getStripePromise = (publishableKey: string): Promise => { + const existingPromise = stripePromiseByKey.get(publishableKey); + + if (isDefined(existingPromise)) { + return existingPromise; + } + + const stripePromise = loadStripe(publishableKey); + + stripePromiseByKey.set(publishableKey, stripePromise); + + return stripePromise; +}; + +export const useStripePromise = (): Promise | null => { + const billing = useAtomStateValue(billingState); + const publishableKey = billing?.stripePublishableKey; + + return isDefined(publishableKey) && publishableKey !== '' + ? getStripePromise(publishableKey) + : null; +}; diff --git a/packages/twenty-front/src/pages/onboarding/WorkspaceActivation.tsx b/packages/twenty-front/src/pages/onboarding/WorkspaceActivation.tsx index d1a8e1cb46..ce77d70d36 100644 --- a/packages/twenty-front/src/pages/onboarding/WorkspaceActivation.tsx +++ b/packages/twenty-front/src/pages/onboarding/WorkspaceActivation.tsx @@ -1,5 +1,5 @@ import { styled } from '@linaria/react'; -import { useCallback, useEffect, useState } from 'react'; +import { useCallback, useEffect, useRef, useState } from 'react'; import { Logo } from '@/auth/components/Logo'; import { SubTitle } from '@/auth/components/SubTitle'; @@ -106,15 +106,20 @@ export const WorkspaceActivation = () => { setNextOnboardingStatus, ]); - const [hasTriggered, setHasTriggered] = useState(false); + // Guard the one-shot trigger with a ref, not state: a ref mutation is + // synchronous and survives StrictMode's double-invocation of effects, whereas + // a state flag stays false in the second (same-closure) invocation and fires + // a second concurrent activation that trips the server's lock. + // oxlint-disable-next-line twenty/no-state-useref + const hasTriggeredRef = useRef(false); useEffect(() => { - if (hasTriggered || !isDefined(currentWorkspace)) { + if (hasTriggeredRef.current || !isDefined(currentWorkspace)) { return; } - setHasTriggered(true); + hasTriggeredRef.current = true; void activate(); - }, [activate, hasTriggered, currentWorkspace]); + }, [activate, currentWorkspace]); return ( diff --git a/packages/twenty-front/src/pages/onboarding/internal/ChooseYourPlanContent.tsx b/packages/twenty-front/src/pages/onboarding/internal/ChooseYourPlanContent.tsx index 7f2dcdb75d..40b48f05dc 100644 --- a/packages/twenty-front/src/pages/onboarding/internal/ChooseYourPlanContent.tsx +++ b/packages/twenty-front/src/pages/onboarding/internal/ChooseYourPlanContent.tsx @@ -4,8 +4,7 @@ import { Title } from '@/auth/components/Title'; import { useAuth } from '@/auth/hooks/useAuth'; import { billingCheckoutSessionState } from '@/auth/states/billingCheckoutSessionState'; import { calendarBookingPageIdState } from '@/client-config/states/calendarBookingPageIdState'; -import { SubscriptionBenefit } from '@/settings/billing/components/SubscriptionBenefit'; -import { SubscriptionPrice } from '@/settings/billing/components/SubscriptionPrice'; +import { SubscriptionPaymentForm } from '@/settings/billing/components/SubscriptionPaymentForm'; import { TrialCard } from '@/settings/billing/components/TrialCard'; import { useBaseLicensedPriceByPlanKeyAndInterval } from '@/settings/billing/hooks/useBaseLicensedPriceByPlanKeyAndInterval'; import { useBaseProductByPlanKey } from '@/settings/billing/hooks/useBaseProductByPlanKey'; @@ -20,60 +19,20 @@ import { Loader } from 'twenty-ui/feedback'; import { CardPicker, MainButton } from 'twenty-ui/input'; import { CAL_LINK, ClickToActionLink } from 'twenty-ui/navigation'; import { themeCssVariables } from 'twenty-ui/theme-constants'; -import { BillingPlanKey, type Billing } from '~/generated-metadata/graphql'; - -const StyledSubscriptionContainer = styled.div<{ - withLongerMarginBottom: boolean; -}>` - background-color: ${themeCssVariables.background.secondary}; - border: 1px solid ${themeCssVariables.border.color.medium}; - border-radius: ${themeCssVariables.border.radius.md}; - - display: flex; - flex-direction: column; - margin: ${themeCssVariables.spacing[8]} 0 - ${({ withLongerMarginBottom }) => - withLongerMarginBottom - ? themeCssVariables.spacing[8] - : themeCssVariables.spacing[2]}; - width: 100%; -`; - -const StyledSubscriptionPriceContainer = styled.div` - align-items: center; - border-bottom: 1px solid ${themeCssVariables.border.color.light}; - display: flex; - flex-direction: column; - margin: ${themeCssVariables.spacing[4]} ${themeCssVariables.spacing[3]} 0 - ${themeCssVariables.spacing[4]}; - padding-bottom: ${themeCssVariables.spacing[3]}; -`; - -const StyledBenefitsContainer = styled.div` - box-sizing: border-box; - display: flex; - flex-direction: column; - gap: 16px; - padding: ${themeCssVariables.spacing[4]} ${themeCssVariables.spacing[3]}; - width: 100%; -`; - -const StyledOrganizationBenefitsContainer = styled.div` - border-bottom: 1px solid ${themeCssVariables.border.color.light}; - box-sizing: border-box; - display: flex; - flex-direction: column; - gap: 16px; - padding: ${themeCssVariables.spacing[4]} ${themeCssVariables.spacing[3]}; - width: 100%; -`; +import { type Billing } from '~/generated-metadata/graphql'; const StyledChooseTrialContainer = styled.div` display: flex; flex-direction: row; gap: ${themeCssVariables.spacing[2]}; - margin-bottom: ${themeCssVariables.spacing[8]}; + margin-bottom: ${themeCssVariables.spacing[4]}; + margin-top: ${themeCssVariables.spacing[8]}; width: 100%; + + > * { + flex: 1 1 0; + min-width: 0; + } `; const StyledLinkGroup = styled.div` @@ -114,40 +73,6 @@ export const ChooseYourPlanContent = ({ billing }: { billing: Billing }) => { const currentPlanKey = billingCheckoutSession.plan; - const getPlanBenefits = (planKey: BillingPlanKey) => { - if (planKey === BillingPlanKey.ENTERPRISE) { - return { - organizationBenefits: [ - t`SSO (SAML / OIDC)`, - t`20,000 workflow node executions`, - t`Priority support`, - ], - standardBenefits: [ - t`Full access`, - t`Unlimited contacts`, - t`Email integration`, - t`Custom objects`, - t`API & Webhooks`, - ], - }; - } - - return { - organizationBenefits: [], - standardBenefits: [ - t`Full access`, - t`Unlimited contacts`, - t`Email integration`, - t`Custom objects`, - t`API & Webhooks`, - t`50,000 workflow node executions`, - ], - }; - }; - - const { organizationBenefits, standardBenefits } = - getPlanBenefits(currentPlanKey); - const baseProduct = getBaseProductByPlanKey(currentPlanKey); const baseProductPrice = getBaseLicensedPriceByPlanKeyAndInterval( currentPlanKey, @@ -184,14 +109,6 @@ export const ChooseYourPlanContent = ({ billing }: { billing: Billing }) => { }; }; - const planChangeLink = (plan: BillingPlanKey) => { - const interval = billingCheckoutSession.interval; - const requirePaymentMethod = billingCheckoutSession.requirePaymentMethod; - return AppPath.PlanRequired.concat( - `?billingCheckoutSession={%22plan%22:%22${plan}%22,%22interval%22:%22${interval}%22,%22requirePaymentMethod%22:${requirePaymentMethod}}`, - ); - }; - const { signOut } = useAuth(); const withCreditCardTrialPeriodDuration = withCreditCardTrialPeriod?.duration; @@ -212,28 +129,6 @@ export const ChooseYourPlanContent = ({ billing }: { billing: Billing }) => { ) )} - - - - - {organizationBenefits.length > 0 && ( - - {organizationBenefits.map((benefit) => ( - {benefit} - ))} - - )} - - {standardBenefits.map((benefit) => ( - {benefit} - ))} - - {hasWithoutCreditCardTrialPeriod && ( {billing.trialPeriods.map((trialPeriod) => ( @@ -255,13 +150,21 @@ export const ChooseYourPlanContent = ({ billing }: { billing: Billing }) => { ))} )} - isSubmitting && } - disabled={isSubmitting} - /> + {billingCheckoutSession.requirePaymentMethod ? ( + + ) : ( + isSubmitting && } + disabled={isSubmitting} + /> + )} Log out @@ -274,16 +177,6 @@ export const ChooseYourPlanContent = ({ billing }: { billing: Billing }) => { > Book a Call - - {currentPlanKey === BillingPlanKey.PRO ? ( - - Organization plan - - ) : ( - - Pro plan - - )} ); diff --git a/packages/twenty-server/src/engine/core-modules/billing/billing.resolver.ts b/packages/twenty-server/src/engine/core-modules/billing/billing.resolver.ts index ccd5ce0bea..906717c14e 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/billing.resolver.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/billing.resolver.ts @@ -12,6 +12,7 @@ import { type AuthContextUser } from 'src/engine/core-modules/auth/types/auth-co import { BillingEndTrialPeriodDTO } from 'src/engine/core-modules/billing/dtos/billing-end-trial-period.dto'; import { BillingResourceCreditUsageDTO } from 'src/engine/core-modules/billing/dtos/billing-resource-credit-usage.dto'; import { BillingPlanDTO } from 'src/engine/core-modules/billing/dtos/billing-plan.dto'; +import { BillingPaymentIntentDTO } from 'src/engine/core-modules/billing/dtos/billing-payment-intent.dto'; import { BillingSessionDTO } from 'src/engine/core-modules/billing/dtos/billing-session.dto'; import { BillingUpdateDTO } from 'src/engine/core-modules/billing/dtos/billing-update.dto'; import { BillingCheckoutSessionInput } from 'src/engine/core-modules/billing/dtos/inputs/billing-checkout-session.input'; @@ -143,6 +144,40 @@ export class BillingResolver { } } + @Mutation(() => BillingPaymentIntentDTO) + @UseGuards(WorkspaceAuthGuard, UserAuthGuard, NoPermissionGuard) + async createSubscriptionPaymentIntent( + @AuthWorkspace() workspace: WorkspaceEntity, + @AuthUser() user: AuthContextUser, + @AuthUserWorkspaceId() userWorkspaceId: string, + @Args() { recurringInterval, plan }: BillingCheckoutSessionInput, + @Args('idempotencyKey', { type: () => String }) idempotencyKey: string, + @AuthApiKey() apiKey?: ApiKeyEntity, + ): Promise { + await this.validateCanCheckoutSessionPermissionOrThrow({ + workspaceId: workspace.id, + userWorkspaceId, + apiKeyId: apiKey?.id, + workspaceActivationStatus: workspace.activationStatus, + }); + + const resolvedPlan = plan ?? BillingPlanKey.PRO; + + const billingPricesPerPlan = + await this.billingPlanService.getPricesPerPlanByInterval({ + planKey: resolvedPlan, + interval: recurringInterval, + }); + + return this.billingPortalWorkspaceService.createSubscriptionPaymentIntent({ + user, + workspace, + plan: resolvedPlan, + billingPricesPerPlan, + idempotencyKey, + }); + } + @Mutation(() => BillingUpdateDTO) @UseGuards( WorkspaceAuthGuard, diff --git a/packages/twenty-server/src/engine/core-modules/billing/dtos/billing-payment-intent.dto.ts b/packages/twenty-server/src/engine/core-modules/billing/dtos/billing-payment-intent.dto.ts new file mode 100644 index 0000000000..a2f49eb7f2 --- /dev/null +++ b/packages/twenty-server/src/engine/core-modules/billing/dtos/billing-payment-intent.dto.ts @@ -0,0 +1,12 @@ +/* @license Enterprise */ + +import { Field, ObjectType } from '@nestjs/graphql'; + +@ObjectType('BillingPaymentIntent') +export class BillingPaymentIntentDTO { + @Field(() => String) + clientSecret: string; + + @Field(() => String) + paymentIntentType: string; +} diff --git a/packages/twenty-server/src/engine/core-modules/billing/services/billing-portal.workspace-service.ts b/packages/twenty-server/src/engine/core-modules/billing/services/billing-portal.workspace-service.ts index 3bec9ff59f..6b86fac5f5 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/services/billing-portal.workspace-service.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/services/billing-portal.workspace-service.ts @@ -72,8 +72,7 @@ export class BillingPortalWorkspaceService { stripeCustomerId: customer?.stripeCustomerId, plan, requirePaymentMethod, - withTrialPeriod: - !isDefined(customer) || customer.billingSubscriptions.length === 0, + withTrialPeriod: this.isCustomerEligibleForTrialPeriod(customer), }); assertIsDefinedOrThrow( @@ -122,8 +121,7 @@ export class BillingPortalWorkspaceService { stripeCustomerId: customer?.stripeCustomerId, plan, requirePaymentMethod, - withTrialPeriod: - !isDefined(customer) || customer.billingSubscriptions.length === 0, + withTrialPeriod: this.isCustomerEligibleForTrialPeriod(customer), }); await this.billingSubscriptionService.syncSubscriptionToDatabase( @@ -134,6 +132,158 @@ export class BillingPortalWorkspaceService { return successUrl; } + async createSubscriptionPaymentIntent({ + user, + workspace, + billingPricesPerPlan, + plan, + idempotencyKey, + }: BillingPortalCheckoutSessionParameters & { + idempotencyKey: string; + }): Promise<{ + clientSecret: string; + paymentIntentType: string; + }> { + const { customer, stripeSubscriptionLineItems } = + await this.prepareSubscriptionParameters({ + workspace, + billingPricesPerPlan, + }); + + const resumablePaymentIntent = + await this.findResumableSubscriptionPaymentIntent(customer); + + if (isDefined(resumablePaymentIntent)) { + return resumablePaymentIntent; + } + + const stripeSubscription = + await this.stripeCheckoutService.createSubscriptionWithPaymentMethodCollection( + { + user, + workspace, + stripeSubscriptionLineItems, + stripeCustomerId: customer?.stripeCustomerId, + plan, + withTrialPeriod: this.isCustomerEligibleForTrialPeriod(customer), + idempotencyKey, + }, + ); + + await this.billingSubscriptionService.syncSubscriptionToDatabase( + workspace.id, + stripeSubscription.id, + ); + + const paymentIntent = + this.extractSubscriptionClientSecret(stripeSubscription); + + return paymentIntent; + } + + // A failed earlier attempt leaves an incomplete subscription; it must not + // count, or a retry would be charged immediately instead of getting the + // trial. Only a real (non-incomplete) subscription blocks a new trial. + private isCustomerEligibleForTrialPeriod( + customer: BillingCustomerEntity | null, + ): boolean { + return ( + !isDefined(customer) || + !customer.billingSubscriptions.some( + (subscription) => + subscription.status !== SubscriptionStatus.Incomplete && + subscription.status !== SubscriptionStatus.IncompleteExpired, + ) + ); + } + + private async findResumableSubscriptionPaymentIntent( + customer: BillingCustomerEntity | null, + ): Promise<{ clientSecret: string; paymentIntentType: string } | null> { + const existingSubscription = customer?.billingSubscriptions?.find( + (subscription) => subscription.status !== SubscriptionStatus.Canceled, + ); + + if (!isDefined(existingSubscription)) { + return null; + } + + const stripeSubscription = + await this.stripeCheckoutService.retrieveSubscriptionForResume( + existingSubscription.stripeSubscriptionId, + ); + + const paymentIntent = this.findSubscriptionClientSecret(stripeSubscription); + + if (isDefined(paymentIntent)) { + return paymentIntent; + } + + if ( + stripeSubscription.status === 'incomplete' || + stripeSubscription.status === 'incomplete_expired' + ) { + return null; + } + + throw new BillingException( + 'Customer already has a non-canceled billing subscription', + BillingExceptionCode.BILLING_SUBSCRIPTION_INVALID, + ); + } + + private extractSubscriptionClientSecret(subscription: Stripe.Subscription): { + clientSecret: string; + paymentIntentType: string; + } { + const paymentIntent = this.findSubscriptionClientSecret(subscription); + + if (!isDefined(paymentIntent)) { + throw new BillingException( + 'Error: missing subscription client secret', + BillingExceptionCode.BILLING_STRIPE_ERROR, + ); + } + + return paymentIntent; + } + + private findSubscriptionClientSecret(subscription: Stripe.Subscription): { + clientSecret: string; + paymentIntentType: string; + } | null { + const pendingSetupIntent = subscription.pending_setup_intent; + + if ( + isDefined(pendingSetupIntent) && + typeof pendingSetupIntent !== 'string' && + isDefined(pendingSetupIntent.client_secret) + ) { + return { + clientSecret: pendingSetupIntent.client_secret, + paymentIntentType: 'setup', + }; + } + + const latestInvoice = subscription.latest_invoice; + const confirmationSecret = + isDefined(latestInvoice) && typeof latestInvoice !== 'string' + ? latestInvoice.confirmation_secret + : undefined; + + if ( + isDefined(confirmationSecret) && + isDefined(confirmationSecret.client_secret) + ) { + return { + clientSecret: confirmationSecret.client_secret, + paymentIntentType: 'payment', + }; + } + + return null; + } + private async prepareSubscriptionParameters({ workspace, billingPricesPerPlan, diff --git a/packages/twenty-server/src/engine/core-modules/billing/stripe/services/stripe-checkout.service.ts b/packages/twenty-server/src/engine/core-modules/billing/stripe/services/stripe-checkout.service.ts index 17842b08e6..74606a245d 100644 --- a/packages/twenty-server/src/engine/core-modules/billing/stripe/services/stripe-checkout.service.ts +++ b/packages/twenty-server/src/engine/core-modules/billing/stripe/services/stripe-checkout.service.ts @@ -52,16 +52,11 @@ export class StripeCheckoutService { requirePaymentMethod?: boolean; withTrialPeriod: boolean; }): Promise { - if (!isDefined(stripeCustomerId)) { - const stripeCustomer = - await this.stripeCustomerService.createStripeCustomer( - user.email, - workspace.id, - workspace.displayName, - ); - - stripeCustomerId = stripeCustomer.id; - } + stripeCustomerId = await this.getOrCreateStripeCustomerId({ + user, + workspace, + stripeCustomerId, + }); return await this.stripe.checkout.sessions.create({ line_items: stripeSubscriptionLineItems, @@ -105,18 +100,12 @@ export class StripeCheckoutService { requirePaymentMethod?: boolean; withTrialPeriod: boolean; }): Promise { - if (!isDefined(stripeCustomerId)) { - const stripeCustomer = - await this.stripeCustomerService.createStripeCustomer( - user.email, - workspace.id, - workspace.displayName, - ); + stripeCustomerId = await this.getOrCreateStripeCustomerId({ + user, + workspace, + stripeCustomerId, + }); - stripeCustomerId = stripeCustomer.id; - } - - // Convert checkout session line items to subscription items format const subscriptionItems: Stripe.SubscriptionCreateParams.Item[] = stripeSubscriptionLineItems.map((lineItem) => ({ price: lineItem.price as string, @@ -140,6 +129,88 @@ export class StripeCheckoutService { return await this.stripe.subscriptions.create(subscriptionParams); } + async createSubscriptionWithPaymentMethodCollection({ + user, + workspace, + stripeSubscriptionLineItems, + stripeCustomerId, + plan = BillingPlanKey.PRO, + withTrialPeriod, + idempotencyKey, + }: { + user: AuthContextUser; + workspace: Pick; + stripeSubscriptionLineItems: Stripe.Checkout.SessionCreateParams.LineItem[]; + stripeCustomerId?: string; + plan?: BillingPlanKey; + withTrialPeriod: boolean; + idempotencyKey: string; + }): Promise { + const customerId = await this.getOrCreateStripeCustomerId({ + user, + workspace, + stripeCustomerId, + }); + + const subscriptionItems: Stripe.SubscriptionCreateParams.Item[] = + stripeSubscriptionLineItems.map((lineItem) => ({ + price: lineItem.price as string, + quantity: lineItem.quantity, + })); + + return await this.stripe.subscriptions.create( + { + customer: customerId, + items: subscriptionItems, + metadata: { + workspaceId: workspace.id, + plan, + }, + payment_behavior: 'default_incomplete', + payment_settings: { + save_default_payment_method: 'on_subscription', + }, + ...this.getStripeSubscriptionTrialPeriodConfig(withTrialPeriod, true), + automatic_tax: { enabled: false }, + expand: ['pending_setup_intent', 'latest_invoice.confirmation_secret'], + }, + { + idempotencyKey: `onboarding-subscription-${workspace.id}-${idempotencyKey}`, + }, + ); + } + + async retrieveSubscriptionForResume( + stripeSubscriptionId: string, + ): Promise { + return this.stripe.subscriptions.retrieve(stripeSubscriptionId, { + expand: ['pending_setup_intent', 'latest_invoice.confirmation_secret'], + }); + } + + private async getOrCreateStripeCustomerId({ + user, + workspace, + stripeCustomerId, + }: { + user: AuthContextUser; + workspace: Pick; + stripeCustomerId?: string; + }): Promise { + if (isDefined(stripeCustomerId)) { + return stripeCustomerId; + } + + const stripeCustomer = + await this.stripeCustomerService.createStripeCustomer( + user.email, + workspace.id, + workspace.displayName, + ); + + return stripeCustomer.id; + } + private getStripeSubscriptionTrialPeriodConfig( withTrialPeriod: boolean, requirePaymentMethod: boolean, diff --git a/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts b/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts index 50d8980567..ac1abb00a6 100644 --- a/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts +++ b/packages/twenty-server/src/engine/core-modules/client-config/client-config.entity.ts @@ -165,6 +165,9 @@ export class Billing { @Field(() => String, { nullable: true }) billingUrl?: string; + @Field(() => String, { nullable: true }) + stripePublishableKey?: string; + @Field(() => [BillingTrialPeriodDTO]) trialPeriods: BillingTrialPeriodDTO[]; } diff --git a/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.spec.ts b/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.spec.ts index 0e27d5dcc5..ee754c6955 100644 --- a/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.spec.ts +++ b/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.spec.ts @@ -74,6 +74,7 @@ describe('ClientConfigService', () => { BILLING_PLAN_REQUIRED_LINK: 'https://billing.example.com', BILLING_FREE_TRIAL_WITH_CREDIT_CARD_DURATION_IN_DAYS: 30, BILLING_FREE_TRIAL_WITHOUT_CREDIT_CARD_DURATION_IN_DAYS: 7, + BILLING_STRIPE_PUBLISHABLE_KEY: 'pk_test_123', AUTH_GOOGLE_ENABLED: true, AUTH_PASSWORD_ENABLED: true, AUTH_MICROSOFT_ENABLED: false, @@ -121,6 +122,7 @@ describe('ClientConfigService', () => { billing: { isBillingEnabled: true, billingUrl: 'https://billing.example.com', + stripePublishableKey: 'pk_test_123', trialPeriods: [ { duration: 30, diff --git a/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.ts b/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.ts index 8a8155ac30..c482103391 100644 --- a/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.ts +++ b/packages/twenty-server/src/engine/core-modules/client-config/services/client-config.service.ts @@ -160,6 +160,9 @@ export class ClientConfigService { billing: { isBillingEnabled: this.twentyConfigService.get('IS_BILLING_ENABLED'), billingUrl: this.twentyConfigService.get('BILLING_PLAN_REQUIRED_LINK'), + stripePublishableKey: this.twentyConfigService.get( + 'BILLING_STRIPE_PUBLISHABLE_KEY', + ), trialPeriods: [ { duration: this.twentyConfigService.get( diff --git a/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts b/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts index eb6191506d..ff94b60ef9 100644 --- a/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts +++ b/packages/twenty-server/src/engine/core-modules/twenty-config/config-variables.ts @@ -836,6 +836,15 @@ export class ConfigVariables { @ValidateIf((env) => env.IS_BILLING_ENABLED === true) BILLING_STRIPE_WEBHOOK_SECRET: string; + @ConfigVariablesMetadata({ + group: ConfigVariablesGroup.BILLING_CONFIG, + description: + 'Stripe publishable key for billing, exposed to the frontend to mount Stripe Elements', + type: ConfigVariableType.STRING, + }) + @ValidateIf((env) => env.IS_BILLING_ENABLED === true) + BILLING_STRIPE_PUBLISHABLE_KEY: string; + @ConfigVariablesMetadata({ group: ConfigVariablesGroup.BILLING_CONFIG, description: diff --git a/yarn.lock b/yarn.lock index 1752e5668d..982d9f9f4b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -20864,6 +20864,26 @@ __metadata: languageName: node linkType: hard +"@stripe/react-stripe-js@npm:^6.6.0": + version: 6.6.0 + resolution: "@stripe/react-stripe-js@npm:6.6.0" + dependencies: + prop-types: "npm:^15.7.2" + peerDependencies: + "@stripe/stripe-js": ">=9.5.0 <10.0.0" + react: ">=16.8.0 <20.0.0" + react-dom: ">=16.8.0 <20.0.0" + checksum: 10c0/fb093073d19efb15c18cd4b4007b886bfff4bbee17b270fabb86c82e1dad0377ebb15d58bab37c41c3ea01599fc0a5117747611226ac232e1350ebbfeecb17a7 + languageName: node + linkType: hard + +"@stripe/stripe-js@npm:^9.8.0": + version: 9.8.0 + resolution: "@stripe/stripe-js@npm:9.8.0" + checksum: 10c0/90c473b938800a3c7f5794e052b22b2a277e1e61a1b54353a8117c3fd630e42cba2530d42ca12a9e06b674cd3ad5d74adf815b54763dc14726aeb05056592031 + languageName: node + linkType: hard + "@svgr/babel-plugin-add-jsx-attribute@npm:8.0.0": version: 8.0.0 resolution: "@svgr/babel-plugin-add-jsx-attribute@npm:8.0.0" @@ -47138,7 +47158,7 @@ __metadata: languageName: node linkType: hard -"prop-types@npm:15.x, prop-types@npm:^15.6.1, prop-types@npm:^15.6.2, prop-types@npm:^15.8.1": +"prop-types@npm:15.x, prop-types@npm:^15.6.1, prop-types@npm:^15.6.2, prop-types@npm:^15.7.2, prop-types@npm:^15.8.1": version: 15.8.1 resolution: "prop-types@npm:15.8.1" dependencies: @@ -54024,6 +54044,8 @@ __metadata: "@storybook/addon-docs": "npm:^10.3.3" "@storybook/addon-links": "npm:^10.3.3" "@storybook/react-vite": "npm:^10.3.3" + "@stripe/react-stripe-js": "npm:^6.6.0" + "@stripe/stripe-js": "npm:^9.8.0" "@swc/core": "npm:^1.15.11" "@swc/jest": "npm:^0.2.39" "@testing-library/dom": "npm:^10.4.0"