import type {DATA_CATEGORY_INFO} from 'sentry/constants'; import type {DataCategoryExact} from 'sentry/types/core'; import type {User} from 'sentry/types/user'; declare global { interface Window { /** * Stripe SDK */ Stripe: stripe.Stripe; /** * Used in admin */ __sendGridApiKey: string; /** * Google analytics */ ga: any; /** * Reload agent */ ra: any; /** * Bing */ uetq: any; /** * Zendesk widget */ zE: any; /** * Pendo which is used to render guides */ pendo?: any; // TODO: use types package } } /** * Allows for declaration merging, so getsentry can add additional properties * to Sentry interfaces. */ declare module 'sentry/types/system' { interface Config { 'getsentry.amplitudeApiKey'?: string; 'getsentry.googleMapsApiKey'?: string; 'getsentry.sendgridApiKey'?: string; 'getsentry.stripePublishKey'?: string; } } export type EventBucket = { events: number; price: number; onDemandPrice?: number; /** * Available in performance plans */ unitPrice?: number; }; export enum PlanName { DEVELOPER = 'Developer', TEAM = 'Team', BUSINESS = 'Business', TEAM_BUNDLE = 'Team Bundle', BUSINESS_BUNDLE = 'Business Bundle', TEAM_SPONSORED = 'Sponsored Team', BUSINESS_SPONSORED = 'Sponsored Business', } export enum CheckoutType { STANDARD = 'standard', BUNDLE = 'bundle', } export type DataCategories = (typeof DATA_CATEGORY_INFO)[DataCategoryExact]['plural']; export type Plan = { allowAdditionalReservedEvents: boolean; allowOnDemand: boolean; /** * All available data categories on the current plan tier. * Can be used for category upsells. */ availableCategories: string[]; basePrice: number; billingInterval: 'monthly' | 'annual'; /** * Data categories on the plan (errors, transactions, etc.) */ categories: string[]; checkoutCategories: string[]; contractInterval: 'monthly' | 'annual'; description: string; features: string[]; hasOnDemandModes: boolean; id: string; maxMembers: number | null; name: string; onDemandCategories: string[]; onDemandEventPrice: number; planCategories: { [categoryKey in DataCategories]?: EventBucket[]; }; price: number; reservedMinimum: number; retentionDays: number; totalPrice: number; trialPlan: string | null; userSelectable: boolean; categoryDisplayNames?: { [categoryKey in DataCategories]?: {plural: string; singular: string}; }; checkoutType?: CheckoutType; }; type PendingChanges = { customPrice: number | null; customPriceAttachments: number | null; customPriceErrors: number | null; customPricePcss: number | null; customPriceTransactions: number | null; // TODO:categories remove customPrice{Categories} customPrices: {[categoryKey in DataCategories]?: number | null}; effectiveDate: string; onDemandBudgets: PendingOnDemandBudgets | null; onDemandEffectiveDate: string; onDemandMaxSpend: number; plan: string; planDetails: Plan; planName: string; // TODO:categories remove reserved{Categories} reserved: {[categoryKey in DataCategories]?: number | null}; reservedAttachments: number | null; reservedBudgets: PendingReservedBudget[]; reservedCpe: {[categoryKey in DataCategories]?: number | null}; reservedErrors: number | null; reservedEvents: number; reservedTransactions: number | null; }; enum VatStatus { UNKNOWN = 'unknown', PERSONAL = 'personal', BUSINESS = 'business', BUSINESS_NOVAT = 'business_novat', OTHER = 'other', } export type GDPRDetails = { dpoAddress: string; dpoEmail: string; dpoName: string; dpoPhone: string; euRepAddress: string; euRepEmail: string; euRepName: string; euRepPhone: string; }; type Partner = { externalId: string; isActive: boolean; name: string; partnership: { displayName: string; id: string; supportNote: string; }; }; export enum BillingType { CREDIT_CARD = 'credit card', INVOICED = 'invoiced', PARTNER = 'partner', } export enum OnDemandBudgetMode { SHARED = 'shared', PER_CATEGORY = 'per_category', } type SharedOnDemandBudget = { budgetMode: OnDemandBudgetMode.SHARED; sharedMaxBudget: number; }; type SharedOnDemandBudgetWithSpends = SharedOnDemandBudget & { onDemandSpendUsed: number; }; export type PerCategoryOnDemandBudget = { attachmentsBudget: number; budgetMode: OnDemandBudgetMode.PER_CATEGORY; // TODO:categories remove {categories}Budget budgets: {[categoryKey in DataCategories]?: number}; errorsBudget: number; replaysBudget: number; transactionsBudget: number; monitorSeatsBudget?: number; uptimeBudget?: number; }; type PerCategoryOnDemandBudgetWithSpends = PerCategoryOnDemandBudget & { attachmentSpendUsed: number; errorSpendUsed: number; transactionSpendUsed: number; // TODO:categories remove {categories}SpendUsed usedSpends: {[categoryKey in DataCategories]?: number}; }; export type OnDemandBudgets = SharedOnDemandBudget | PerCategoryOnDemandBudget; type OnDemandBudgetsEnabled = { enabled: boolean; }; type OnDemandBudgetsWithSpends = | SharedOnDemandBudgetWithSpends | PerCategoryOnDemandBudgetWithSpends; export type SubscriptionOnDemandBudgets = OnDemandBudgetsEnabled & OnDemandBudgetsWithSpends; export type PendingOnDemandBudgets = OnDemandBudgetsEnabled & OnDemandBudgets; export type ProductTrial = { category: DataCategories; isStarted: boolean; reasonCode: number; betaOptInStatus?: boolean; endDate?: string; lengthDays?: number; startDate?: string; }; export type Subscription = { accountBalance: number; billingInterval: 'monthly' | 'annual'; // billingPeriod varies between 1-12 months. if you're looking for the monthly usage interval, use onDemandPeriodStart billingPeriodEnd: string; billingPeriodStart: string; canCancel: boolean; canGracePeriod: boolean; canSelfServe: boolean; canTrial: boolean; cancelAtPeriodEnd: boolean; /** * Current history per data category */ categories: { [categoryKey in DataCategories]?: BillingMetricHistory; }; contractInterval: 'monthly' | 'annual'; contractPeriodEnd: string; contractPeriodStart: string; customPrice: number | null; customPriceAttachments: number | null; customPriceErrors: number | null; customPricePcss: number | null; customPriceTransactions: number | null; dataRetention: string | null; // Event details dateJoined: string; // GDPR Info gdprDetails: GDPRDetails | null; gracePeriodEnd: string | null; gracePeriodStart: string | null; hadCustomDynamicSampling: boolean; hasDismissedForcedTrialNotice: boolean; hasDismissedTrialEndingNotice: boolean; hasOverageNotificationsDisabled: boolean; hasReservedBudgets: boolean; hasRestrictedIntegration: boolean | null; hasSoftCap: boolean; id: string; isBundleEligible: boolean; // Added by SubscriptionStore to show/hide a UI element isEnterpriseTrial: boolean; // was the trial forced on to the org to rectify access to premium features isExemptFromForcedTrial: boolean; isForcedTrial: boolean; isFree: boolean; // Subscription flags isGracePeriod: boolean; isHeroku: boolean; isManaged: boolean; isOverMemberLimit: boolean; isPartner: boolean; isPastDue: boolean; isPerformancePlanTrial: boolean; isSelfServePartner: boolean; isSponsored: boolean; isSuspended: boolean; isTrial: boolean; lastTrialEnd: string | null; membersDeactivatedFromLimit: number; name: string; onDemandDisabled: boolean; onDemandInvoiced: boolean; onDemandMaxSpend: number; onDemandPeriodEnd: string; onDemandPeriodStart: string; onDemandSpendUsed: number; partner: Partner | null; paymentSource: { countryCode: string; expMonth: number; expYear: number; last4: string; zipCode: string; } | null; pendingChanges: PendingChanges | null; // Subscription details plan: string; planDetails: Plan; planTier: string; /** * Total events allowed for the current usage period including gifted */ prepaidEventsAllowed: number | null; renewalDate: string; reservedAttachments: number | null; reservedBudgetCategories: string[] | null; /** * For am1 plan tier, null for previous tiers */ reservedErrors: number | null; /** * Reserved events on a recurring subscription * For plan tiers previous to am1 */ reservedEvents: number; reservedTransactions: number | null; slug: string; spendAllocationEnabled: boolean; sponsoredType: string | null; status: 'active' | 'trialing' | 'closed' | 'past_due'; supportsOnDemand: boolean; suspensionReason: string | null; totalLicenses: number; totalMembers: number | null; totalProjects: number | null; trialEnd: string | null; trialPlan: string | null; trialTier: string | null; type: BillingType; /** * All quotas available on the plan are exceeded */ usageExceeded: boolean; // Seats usedLicenses: number; acv?: number; // Billing information billingEmail?: string | null; channel?: string; /** * Optional without access, and possibly null with access */ companyName?: string | null; contactInfo?: string | null; countryCode?: string | null; // Refetch usage data if Subscription is updated isDeleted?: boolean; isTrialStarted?: boolean; msaUpdatedForDataConsent?: boolean; onDemandBudgets?: SubscriptionOnDemandBudgets; onDemandInvoicedManual?: boolean | null; orgStatus?: { id: string; name: string; }; owner?: {email: string; name: string}; previousPaidPlans?: string[]; productTrials?: ProductTrial[]; reservedBudgets?: ReservedBudget[]; // Added by SubscriptionStore setAt?: number; stats?: { events24h: number; events30d: number; eventsPrev24h: number; eventsPrev30d: number; }; stripeCustomerID?: string; trueForward?: {attachment: boolean; error: boolean; transaction: boolean}; /** * Optional without access, and possibly null with access */ vatID?: string | null; vatStatus?: VatStatus | null; }; export type DiscountInfo = { amount: number; billingInterval: 'monthly' | 'annual'; billingPeriods: number; // TODO: better typing creditCategory: string; disclaimerText: string; discountType: 'percentPoints' | 'events'; durationText: string; maxCentsPerPeriod: number; modalDisclaimerText: string; planRequirement: 'business' | 'paid' | null; reminderText: string; }; export type Promotion = { autoOptIn: boolean; discountInfo: DiscountInfo; endDate: string; name: string; promptActivityTrigger: string | null; showDiscountInfo: boolean; slug: string; startDate: string; timeLimit: string; }; export type PromotionClaimed = { dateClaimed: string; dateCompleted: string; dateExpired: string; freeEventCreditDaysLeft: number; isLastCycleForFreeEvents: boolean; promotion: Promotion; claimant?: User; }; export type PromotionData = { activePromotions: PromotionClaimed[]; availablePromotions: Promotion[]; completedPromotions: PromotionClaimed[]; }; /** @internal exported for tests only */ export type Feature = { description: string; name: string; }; export type BillingConfig = { annualDiscount: number; defaultPlan: string; defaultReserved: { [categoryKey in DataCategories]?: number; }; featureList: Record; freePlan: string; id: string; planList: Plan[]; }; export type BillingStat = { accepted: number; date: string; dropped: { total: number; other?: number; overQuota?: number; spikeProtection?: number; // Calculated in UsageDetailItem }; filtered: number; total: number; ts: string; // TODO(chart-cleanup): Used by v1 only isProjected?: boolean; /** * Not present when user does not have the correct role */ onDemandCostRunningTotal?: number; }; export type BillingStats = BillingStat[]; export type BillingStatTotal = { accepted: number; dropped: number; droppedOther: number; droppedOverQuota: number; droppedSpikeProtection: number; filtered: number; projected: number; }; export type CustomerUsage = { onDemandEventsAllowed: number; onDemandMaxSpend: number; periodEnd: string; periodStart: string; stats: {[key: string]: BillingStats}; totals: {[key: string]: BillingStatTotal}; eventTotals?: {[key: string]: {[key: string]: BillingStatTotal}}; }; type StructuredAddress = { addressLine1: string | null; addressLine2: string | null; city: string | null; countryCode: string | null; postalCode: string | null; region: string | null; }; type TaxNumberName = { taxId: string; taxIdName: string; }; type SentryTaxIds = TaxNumberName & { region?: TaxNumberName & { code: string; }; }; export type InvoiceBase = StructuredAddress & { amount: number; amountBilled: number | null; amountRefunded: number; channel: string | null; chargeAttempts: number | null; creditApplied: number | null; dateCreated: string; displayAddress: string | null; id: string; isClosed: boolean; // guid isPaid: boolean; isRefunded: boolean; nextChargeAttempt: string | null; receipt: { url: string; }; sentryTaxIds: SentryTaxIds | null; taxNumber: string | null; type: string | null; }; export type Invoice = InvoiceBase & { charges: any[]; customer: | Subscription | { id: string; isDeleted: boolean; slug: string; name?: string; }; defaultTaxName: string | null; effectiveAt: string | null; isReverseCharge: boolean; items: InvoiceItem[]; periodEnd: string | null; periodStart: string | null; sender: { address: string[]; name: string; }; stripeInvoiceID: string | null; }; type BaseInvoiceItem = { amount: number; data: {period?: any; plan?: any; quantity?: any}; description: string; type: InvoiceItemType; }; export type InvoiceItem = BaseInvoiceItem & { periodEnd: string; periodStart: string; }; export enum InvoiceItemType { UNKOWN = '', SUBSCRIPTION = 'subscription', ONDEMAND = 'ondemand', RESERVED_EVENTS = 'reserved', DAILY_EVENTS = 'daily_events', BALANCE_CHANGE = 'balance_change', CANCELLATION_FEE = 'cancellation_fee', SUBSCRIPTION_CREDIT = 'subscription_credit', CREDIT_APPLIED = 'credit_applied', /** * Used for am1 plans */ ATTACHMENTS = 'attachments', TRANSACTIONS = 'transactions', ONDEMAND_ATTACHMENTS = 'ondemand_attachments', ONDEMAND_ERRORS = 'ondemand_errors', ONDEMAND_TRANSACTIONS = 'ondemand_transactions', ONDEMAND_REPLAYS = 'ondemand_replays', ONDEMAND_SPANS = 'ondemand_spans', ONDEMAND_SPANS_INDEXED = 'ondemand_spans_indexed', ONDEMAND_MONITOR_SEATS = 'ondemand_monitor_seats', ONDEMAND_UPTIME = 'ondemand_uptime', ONDEMAND_PROFILE_DURATION = 'ondemand_profile_duration', RESERVED_ATTACHMENTS = 'reserved_attachments', RESERVED_ERRORS = 'reserved_errors', RESERVED_TRANSACTIONS = 'reserved_transactions', RESERVED_REPLAYS = 'reserved_replays', RESERVED_SPANS = 'reserved_spans', RESERVED_SPANS_INDEXED = 'reserved_spans_indexed', RESERVED_MONITOR_SEATS = 'reserved_monitor_seats', RESERVED_UPTIME = 'reserved_uptime', RESERVED_PROFILE_DURATION = 'reserved_profile_duration', } export enum InvoiceStatus { PAID = 'paid', CLOSED = 'closed', AWAITING_PAYMENT = 'awaiting payment', } export type BillingMetricHistory = { /** * Category name (e.g. "errors") */ category: string; customPrice: number | null; free: number; onDemandBudget: number; onDemandCpe: number | null; onDemandQuantity: number; onDemandSpendUsed: number; /** * List order for billing metrics */ order: number; prepaid: number; reserved: number | null; sentUsageWarning: boolean; softCapType: 'ON_DEMAND' | 'TRUE_FORWARD' | null; trueForward: boolean; usage: number; usageExceeded: boolean; }; export type BillingHistory = { categories: {[key: string]: BillingMetricHistory}; hadCustomDynamicSampling: boolean; hasReservedBudgets: boolean; id: string; isCurrent: boolean; links: { csv: string; csvPerProject: string; }; onDemandBudgetMode: OnDemandBudgetMode; onDemandMaxSpend: number; onDemandSpend: number; periodEnd: string; // is today between periodStart/periodEnd? periodStart: string; plan: string; planName: string; reserved: { [categoryKey in DataCategories]?: number | null; }; reservedBudgetCategories: string[]; usage: { [categoryKey in DataCategories]?: number; }; planDetails?: Plan; reservedBudgets?: ReservedBudget[]; }; export type PreviewData = { atPeriodEnd: boolean; balanceChange: number; billedAmount: number; creditApplied: number; effectiveAt: string; invoiceItems: PreviewInvoiceItem[]; newBalance: number; previewToken: string; proratedAmount: number; paymentIntent?: string; paymentSecret?: string; }; type PreviewInvoiceItem = BaseInvoiceItem & { period_end: string; period_start: string; }; export enum CreditType { ERROR = 'error', TRANSACTION = 'transaction', SPAN = 'span', SPAN_INDEXED = 'spanIndexed', PROFILE_DURATION = 'profileDuration', ATTACHMENT = 'attachment', REPLAY = 'replay', MONITOR_SEAT = 'monitorSeat', DISCOUNT = 'discount', PERCENT = 'percent', UPTIME = 'uptime', } type BaseRecurringCredit = { amount: number; id: number; periodEnd: string; periodStart: string; }; interface RecurringDiscount extends BaseRecurringCredit { totalAmountRemaining: number; type: CreditType.DISCOUNT; } interface RecurringPercentDiscount extends BaseRecurringCredit { percentPoints: number; totalAmountRemaining: number; type: CreditType.PERCENT; } interface RecurringEventCredit extends BaseRecurringCredit { totalAmountRemaining: null; type: | CreditType.ERROR | CreditType.TRANSACTION | CreditType.SPAN | CreditType.PROFILE_DURATION | CreditType.ATTACHMENT | CreditType.REPLAY; } export type RecurringCredit = | RecurringDiscount | RecurringPercentDiscount | RecurringEventCredit; export enum CohortId { SECOND = 2, THIRD = 3, FOURTH = 4, FIFTH = 5, SIXTH = 6, SEVENTH = 7, EIGHTH = 8, NINTH = 9, TENTH = 10, } /** @internal exported for tests only */ export type Cohort = { cohortId: CohortId; nextPlan: NextPlanInfo | null; secondDiscount: number; }; export type NextPlanInfo = { contractPeriod: string; discountAmount: number; discountMonths: number; errorCredits: number; errorCreditsMonths: number; id: string; name: string; reserved: { [categoryKey in DataCategories]?: number; }; reservedAttachments: number; reservedErrors: number; totalPrice: number; categoryCredits?: { [categoryKey in DataCategories]?: { credits: number; months: number; }; }; reservedTransactions?: number; }; export type PlanMigration = { cohort: Cohort | null; dateApplied: string | null; effectiveAt: string | null; id: number | string; planTier: string; recurringCredits: RecurringCredit[]; scheduled: boolean; }; export enum PlanTier { /** * Performance plans with continuous profiling * and dynamic sampling for spans. */ AM3 = 'am3', /** * Performance plans with continuous profiling * and dynamic sampling for transactions. */ AM2 = 'am2', /** * First generation of application monitoring plans. * Includes performance features. */ AM1 = 'am1', /** * Monthly metered plans with variable data options. */ MM2 = 'mm2', /** * First generation of monthly metered plans. * Features and data volumes are tightly coupled. */ MM1 = 'mm1', } // Response from /organizations/:orgSlug/payments/:invoiceId/new/ export type PaymentCreateResponse = { amount: string; clientSecret: string; currency: string; returnUrl: string; }; // Response from /organizations/:orgSlug/payments/setup/ export type PaymentSetupCreateResponse = { clientSecret: string; id: string; lastError: string | null; status: string; }; export enum AddressType { STRUCTURED = 'structured', UNSTRUCTURED = 'unstructured', } export type BillingDetails = StructuredAddress & { addressType: AddressType | null; billingEmail: string | null; companyName: string | null; displayAddress: string | null; taxNumber: string | null; }; export interface MonitorCountResponse { disabledMonitorCount: number; enabledMonitorCount: number; overQuotaMonitorCount: number; } export type PendingReservedBudget = { categories: {[categoryKey in DataCategories]?: boolean | null}; reservedBudget: number; }; export type ReservedBudget = { categories: { [categoryKey in DataCategories]?: ReservedBudgetMetricHistory; }; freeBudget: number; id: string; percentUsed: number; reservedBudget: number; totalReservedSpend: number; }; export type ReservedBudgetMetricHistory = { reservedCpe: number; // in cents reservedSpend: number; }; export type ReservedBudgetForCategory = { freeBudget: number; prepaidBudget: number; reservedCpe: number; // in cents reservedSpend: number; totalReservedBudget: number; }; type PolicyConsent = { acceptedVersion: string; createdAt: string; userEmail: string; userName: string; }; export type Policy = { active: boolean; /** Policy consent signature data if policy has been signed. Null if not signed or hasSignature is false. */ consent: PolicyConsent | null; /** True if the policy can be signed. */ hasSignature: boolean; /** Readable policy name */ name: string; /** Slug of a parent policy that needs consent before this policy */ parent: string | null; slug: string; /** True if no parent policies */ standalone: boolean; /** The date of the current version */ updatedAt: string | null; url: string | null; /** The current version */ version: string | null; }; type PolicyFile = { checksum: string; name: string; size: number; }; export type PolicyRevision = { createdAt: string; current: boolean; file: PolicyFile | null; url: string | null; version: string; };