diff --git a/libs/shared/cms/src/__generated__/gql.ts b/libs/shared/cms/src/__generated__/gql.ts index 0fdab7301ff..0a83b3024cc 100644 --- a/libs/shared/cms/src/__generated__/gql.ts +++ b/libs/shared/cms/src/__generated__/gql.ts @@ -24,6 +24,7 @@ type Documents = { "\n query IapOfferingsByStoreIDs($locale: String!, $storeIDs: [String!]!) {\n iaps(filters: { storeID: { in: $storeIDs } }) {\n storeID\n interval\n offering {\n apiIdentifier\n commonContent {\n supportUrl\n localizations(filters: { locale: { eq: $locale } }) {\n supportUrl\n }\n }\n defaultPurchase {\n stripePlanChoices {\n stripePlanChoice\n }\n purchaseDetails {\n productName\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n productName\n webIcon\n }\n }\n }\n subGroups {\n groupName\n offerings {\n apiIdentifier\n }\n }\n }\n }\n }\n": typeof types.IapOfferingsByStoreIDsDocument, "\n query LegalTerms($identifier: String!) {\n legalNotices(\n filters: { serviceOrClientId: { eq: $identifier } }\n pagination: { limit: 1 }\n ) {\n serviceOrClientId\n Terms {\n label\n termsOfServiceLink\n privacyNoticeLink\n fontSize\n }\n l10nId\n }\n }\n": typeof types.LegalTermsDocument, "\n query Locales {\n i18NLocales(pagination: { limit: 100 }) {\n code\n }\n }\n": typeof types.LocalesDocument, + "\n query MeterBySlug($slug: String!) {\n meters(\n filters: { slug: { eq: $slug } }\n pagination: { limit: 1 }\n ) {\n slug\n unit\n limit\n window\n notificationThresholds\n webhooks {\n url\n signingClientId\n }\n }\n }\n": typeof types.MeterBySlugDocument, "\n query Offering($id: ID!, $locale: String!) {\n offering(documentId: $id) {\n stripeProductId\n countries\n defaultPurchase {\n purchaseDetails {\n productName\n details\n subtitle\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n productName\n details\n subtitle\n webIcon\n }\n }\n }\n }\n }\n": typeof types.OfferingDocument, "\n query pageContentByPriceIds($locale: String!, $stripePlanIds: [String]!) {\n purchases(\n filters: {\n or: [\n { stripePlanChoices: { stripePlanChoice: { in: $stripePlanIds } } }\n {\n offering: {\n stripeLegacyPlans: { stripeLegacyPlan: { in: $stripePlanIds } }\n }\n }\n ]\n }\n pagination: { limit: 50 }\n ) {\n offering {\n stripeLegacyPlans(pagination: { limit: 100 }) {\n stripeLegacyPlan\n }\n commonContent {\n emailIcon\n supportUrl\n localizations(filters: { locale: { eq: $locale } }) {\n emailIcon\n supportUrl\n }\n }\n apiIdentifier\n }\n purchaseDetails {\n productName\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n productName\n webIcon\n }\n }\n stripePlanChoices {\n stripePlanChoice\n }\n }\n }\n": typeof types.PageContentByPriceIdsDocument, "\n query PageContentForOffering($locale: String!, $apiIdentifier: String!) {\n offerings(\n filters: { apiIdentifier: { eq: $apiIdentifier } }\n pagination: { limit: 200 }\n ) {\n apiIdentifier\n countries\n stripeProductId\n defaultPurchase {\n purchaseDetails {\n details\n productName\n subtitle\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n details\n productName\n subtitle\n webIcon\n }\n }\n }\n commonContent {\n privacyNoticeUrl\n privacyNoticeDownloadUrl\n termsOfServiceUrl\n termsOfServiceDownloadUrl\n cancellationUrl\n emailIcon\n successActionButtonUrl\n successActionButtonLabel\n newsletterLabelTextCode\n newsletterSlug\n localizations(filters: { locale: { eq: $locale } }) {\n privacyNoticeUrl\n privacyNoticeDownloadUrl\n termsOfServiceUrl\n termsOfServiceDownloadUrl\n cancellationUrl\n emailIcon\n successActionButtonUrl\n successActionButtonLabel\n newsletterLabelTextCode\n newsletterSlug\n }\n }\n }\n }\n": typeof types.PageContentForOfferingDocument, @@ -53,6 +54,7 @@ const documents: Documents = { "\n query IapOfferingsByStoreIDs($locale: String!, $storeIDs: [String!]!) {\n iaps(filters: { storeID: { in: $storeIDs } }) {\n storeID\n interval\n offering {\n apiIdentifier\n commonContent {\n supportUrl\n localizations(filters: { locale: { eq: $locale } }) {\n supportUrl\n }\n }\n defaultPurchase {\n stripePlanChoices {\n stripePlanChoice\n }\n purchaseDetails {\n productName\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n productName\n webIcon\n }\n }\n }\n subGroups {\n groupName\n offerings {\n apiIdentifier\n }\n }\n }\n }\n }\n": types.IapOfferingsByStoreIDsDocument, "\n query LegalTerms($identifier: String!) {\n legalNotices(\n filters: { serviceOrClientId: { eq: $identifier } }\n pagination: { limit: 1 }\n ) {\n serviceOrClientId\n Terms {\n label\n termsOfServiceLink\n privacyNoticeLink\n fontSize\n }\n l10nId\n }\n }\n": types.LegalTermsDocument, "\n query Locales {\n i18NLocales(pagination: { limit: 100 }) {\n code\n }\n }\n": types.LocalesDocument, + "\n query MeterBySlug($slug: String!) {\n meters(\n filters: { slug: { eq: $slug } }\n pagination: { limit: 1 }\n ) {\n slug\n unit\n limit\n window\n notificationThresholds\n webhooks {\n url\n signingClientId\n }\n }\n }\n": types.MeterBySlugDocument, "\n query Offering($id: ID!, $locale: String!) {\n offering(documentId: $id) {\n stripeProductId\n countries\n defaultPurchase {\n purchaseDetails {\n productName\n details\n subtitle\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n productName\n details\n subtitle\n webIcon\n }\n }\n }\n }\n }\n": types.OfferingDocument, "\n query pageContentByPriceIds($locale: String!, $stripePlanIds: [String]!) {\n purchases(\n filters: {\n or: [\n { stripePlanChoices: { stripePlanChoice: { in: $stripePlanIds } } }\n {\n offering: {\n stripeLegacyPlans: { stripeLegacyPlan: { in: $stripePlanIds } }\n }\n }\n ]\n }\n pagination: { limit: 50 }\n ) {\n offering {\n stripeLegacyPlans(pagination: { limit: 100 }) {\n stripeLegacyPlan\n }\n commonContent {\n emailIcon\n supportUrl\n localizations(filters: { locale: { eq: $locale } }) {\n emailIcon\n supportUrl\n }\n }\n apiIdentifier\n }\n purchaseDetails {\n productName\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n productName\n webIcon\n }\n }\n stripePlanChoices {\n stripePlanChoice\n }\n }\n }\n": types.PageContentByPriceIdsDocument, "\n query PageContentForOffering($locale: String!, $apiIdentifier: String!) {\n offerings(\n filters: { apiIdentifier: { eq: $apiIdentifier } }\n pagination: { limit: 200 }\n ) {\n apiIdentifier\n countries\n stripeProductId\n defaultPurchase {\n purchaseDetails {\n details\n productName\n subtitle\n webIcon\n localizations(filters: { locale: { eq: $locale } }) {\n details\n productName\n subtitle\n webIcon\n }\n }\n }\n commonContent {\n privacyNoticeUrl\n privacyNoticeDownloadUrl\n termsOfServiceUrl\n termsOfServiceDownloadUrl\n cancellationUrl\n emailIcon\n successActionButtonUrl\n successActionButtonLabel\n newsletterLabelTextCode\n newsletterSlug\n localizations(filters: { locale: { eq: $locale } }) {\n privacyNoticeUrl\n privacyNoticeDownloadUrl\n termsOfServiceUrl\n termsOfServiceDownloadUrl\n cancellationUrl\n emailIcon\n successActionButtonUrl\n successActionButtonLabel\n newsletterLabelTextCode\n newsletterSlug\n }\n }\n }\n }\n": types.PageContentForOfferingDocument, @@ -126,6 +128,10 @@ export function graphql(source: "\n query LegalTerms($identifier: String!) {\n * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\n query Locales {\n i18NLocales(pagination: { limit: 100 }) {\n code\n }\n }\n"): (typeof documents)["\n query Locales {\n i18NLocales(pagination: { limit: 100 }) {\n code\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n query MeterBySlug($slug: String!) {\n meters(\n filters: { slug: { eq: $slug } }\n pagination: { limit: 1 }\n ) {\n slug\n unit\n limit\n window\n notificationThresholds\n webhooks {\n url\n signingClientId\n }\n }\n }\n"): (typeof documents)["\n query MeterBySlug($slug: String!) {\n meters(\n filters: { slug: { eq: $slug } }\n pagination: { limit: 1 }\n ) {\n slug\n unit\n limit\n window\n notificationThresholds\n webhooks {\n url\n signingClientId\n }\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/libs/shared/cms/src/__generated__/graphql.ts b/libs/shared/cms/src/__generated__/graphql.ts index e9bcfe5aad8..1ee9e792dba 100644 --- a/libs/shared/cms/src/__generated__/graphql.ts +++ b/libs/shared/cms/src/__generated__/graphql.ts @@ -668,6 +668,27 @@ export type ComponentAccountsTosAndPrivacyNoticeDetailsInput = { termsOfServiceLink: InputMaybe; }; +export type ComponentEntitlementsWebhooks = { + __typename?: 'ComponentEntitlementsWebhooks'; + id: Scalars['ID']['output']; + signingClientId: Scalars['String']['output']; + url: Scalars['String']['output']; +}; + +export type ComponentEntitlementsWebhooksFiltersInput = { + and: InputMaybe>>; + not: InputMaybe; + or: InputMaybe>>; + signingClientId: InputMaybe; + url: InputMaybe; +}; + +export type ComponentEntitlementsWebhooksInput = { + id: InputMaybe; + signingClientId: InputMaybe; + url: InputMaybe; +}; + export type ComponentIapAppleProductIDs = { __typename?: 'ComponentIapAppleProductIDs'; appleProductID: Scalars['String']['output']; @@ -893,6 +914,12 @@ export enum Enum_Iap_Interval { Yearly = 'yearly' } +export enum Enum_Meter_Window { + Daily = 'daily', + Monthly = 'monthly', + Weekly = 'weekly' +} + export type FileInfoInput = { alternativeText: InputMaybe; caption: InputMaybe; @@ -990,7 +1017,7 @@ export type FreeTrialRelationResponseCollection = { nodes: Array; }; -export type GenericMorph = CancelInterstitialOffer | Capability | ChurnIntervention | CommonContent | ComponentAccountsEmailConfig | ComponentAccountsFeatureFlags | ComponentAccountsIllustrationsTheme | ComponentAccountsImage | ComponentAccountsPageConfig | ComponentAccountsShared | ComponentAccountsSharedBackgrounds | ComponentAccountsTosAndPrivacyNoticeDetails | ComponentIapAppleProductIDs | ComponentIapGoogleSkUs | ComponentIapStripeLegacyIapPrices | ComponentIapStripePlanChoices | ComponentStripeStripeLegacyPlans | ComponentStripeStripePlanChoices | ComponentStripeStripePromoCodes | CouponConfig | Default | FreeTrial | I18NLocale | Iap | LegalNotice | Offering | Purchase | PurchaseDetail | RelyingParty | ReviewWorkflowsWorkflow | ReviewWorkflowsWorkflowStage | Service | Subgroup | UploadFile | UsersPermissionsPermission | UsersPermissionsRole | UsersPermissionsUser; +export type GenericMorph = CancelInterstitialOffer | Capability | ChurnIntervention | CommonContent | ComponentAccountsEmailConfig | ComponentAccountsFeatureFlags | ComponentAccountsIllustrationsTheme | ComponentAccountsImage | ComponentAccountsPageConfig | ComponentAccountsShared | ComponentAccountsSharedBackgrounds | ComponentAccountsTosAndPrivacyNoticeDetails | ComponentEntitlementsWebhooks | ComponentIapAppleProductIDs | ComponentIapGoogleSkUs | ComponentIapStripeLegacyIapPrices | ComponentIapStripePlanChoices | ComponentStripeStripeLegacyPlans | ComponentStripeStripePlanChoices | ComponentStripeStripePromoCodes | CouponConfig | Default | FreeTrial | I18NLocale | Iap | LegalNotice | Meter | Offering | Purchase | PurchaseDetail | RelyingParty | ReviewWorkflowsWorkflow | ReviewWorkflowsWorkflowStage | Service | Subgroup | UploadFile | UsersPermissionsPermission | UsersPermissionsRole | UsersPermissionsUser; export type I18NLocale = { __typename?: 'I18NLocale'; @@ -1177,6 +1204,59 @@ export type LegalNoticeInput = { serviceOrClientId: InputMaybe; }; +export type Meter = { + __typename?: 'Meter'; + createdAt: Maybe; + documentId: Scalars['ID']['output']; + limit: Scalars['Int']['output']; + notificationThresholds: Scalars['String']['output']; + publishedAt: Maybe; + slug: Scalars['String']['output']; + unit: Scalars['String']['output']; + updatedAt: Maybe; + webhooks: Array>; + window: Enum_Meter_Window; +}; + + +export type MeterWebhooksArgs = { + filters: InputMaybe; + pagination?: InputMaybe; + sort?: InputMaybe>>; +}; + +export type MeterEntityResponseCollection = { + __typename?: 'MeterEntityResponseCollection'; + nodes: Array; + pageInfo: Pagination; +}; + +export type MeterFiltersInput = { + and: InputMaybe>>; + createdAt: InputMaybe; + documentId: InputMaybe; + limit: InputMaybe; + not: InputMaybe; + notificationThresholds: InputMaybe; + or: InputMaybe>>; + publishedAt: InputMaybe; + slug: InputMaybe; + unit: InputMaybe; + updatedAt: InputMaybe; + webhooks: InputMaybe; + window: InputMaybe; +}; + +export type MeterInput = { + limit: InputMaybe; + notificationThresholds: InputMaybe; + publishedAt: InputMaybe; + slug: InputMaybe; + unit: InputMaybe; + webhooks: InputMaybe>>; + window: InputMaybe; +}; + export type Mutation = { __typename?: 'Mutation'; /** Change user password. Confirm with the current password. */ @@ -1189,6 +1269,7 @@ export type Mutation = { createFreeTrial: Maybe; createIap: Maybe; createLegalNotice: Maybe; + createMeter: Maybe; createOffering: Maybe; createPurchase: Maybe; createPurchaseDetail: Maybe; @@ -1210,6 +1291,7 @@ export type Mutation = { deleteFreeTrial: Maybe; deleteIap: Maybe; deleteLegalNotice: Maybe; + deleteMeter: Maybe; deleteOffering: Maybe; deletePurchase: Maybe; deletePurchaseDetail: Maybe; @@ -1241,6 +1323,7 @@ export type Mutation = { updateFreeTrial: Maybe; updateIap: Maybe; updateLegalNotice: Maybe; + updateMeter: Maybe; updateOffering: Maybe; updatePurchase: Maybe; updatePurchaseDetail: Maybe; @@ -1315,6 +1398,12 @@ export type MutationCreateLegalNoticeArgs = { }; +export type MutationCreateMeterArgs = { + data: MeterInput; + status?: InputMaybe; +}; + + export type MutationCreateOfferingArgs = { data: OfferingInput; status?: InputMaybe; @@ -1422,6 +1511,11 @@ export type MutationDeleteLegalNoticeArgs = { }; +export type MutationDeleteMeterArgs = { + documentId: Scalars['ID']['input']; +}; + + export type MutationDeleteOfferingArgs = { documentId: Scalars['ID']['input']; }; @@ -1571,6 +1665,13 @@ export type MutationUpdateLegalNoticeArgs = { }; +export type MutationUpdateMeterArgs = { + data: MeterInput; + documentId: Scalars['ID']['input']; + status?: InputMaybe; +}; + + export type MutationUpdateOfferingArgs = { data: OfferingInput; documentId: Scalars['ID']['input']; @@ -1991,6 +2092,9 @@ export type Query = { legalNotices: Array>; legalNotices_connection: Maybe; me: Maybe; + meter: Maybe; + meters: Array>; + meters_connection: Maybe; offering: Maybe; offerings: Array>; offerings_connection: Maybe; @@ -2268,6 +2372,31 @@ export type QueryLegalNotices_ConnectionArgs = { }; +export type QueryMeterArgs = { + documentId: Scalars['ID']['input']; + hasPublishedVersion: InputMaybe; + status?: InputMaybe; +}; + + +export type QueryMetersArgs = { + filters: InputMaybe; + hasPublishedVersion: InputMaybe; + pagination?: InputMaybe; + sort?: InputMaybe>>; + status?: InputMaybe; +}; + + +export type QueryMeters_ConnectionArgs = { + filters: InputMaybe; + hasPublishedVersion: InputMaybe; + pagination?: InputMaybe; + sort?: InputMaybe>>; + status?: InputMaybe; +}; + + export type QueryOfferingArgs = { documentId: Scalars['ID']['input']; hasPublishedVersion: InputMaybe; @@ -3233,6 +3362,13 @@ export type LocalesQueryVariables = Exact<{ [key: string]: never; }>; export type LocalesQuery = { __typename?: 'Query', i18NLocales: Array<{ __typename?: 'I18NLocale', code: string | null } | null> }; +export type MeterBySlugQueryVariables = Exact<{ + slug: Scalars['String']['input']; +}>; + + +export type MeterBySlugQuery = { __typename?: 'Query', meters: Array<{ __typename?: 'Meter', slug: string, unit: string, limit: number, window: Enum_Meter_Window, notificationThresholds: string, webhooks: Array<{ __typename?: 'ComponentEntitlementsWebhooks', url: string, signingClientId: string } | null> } | null> }; + export type OfferingQueryVariables = Exact<{ id: Scalars['ID']['input']; locale: Scalars['String']['input']; @@ -3344,6 +3480,7 @@ export const FreeTrialDocument = {"kind":"Document","definitions":[{"kind":"Oper export const IapOfferingsByStoreIDsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"IapOfferingsByStoreIDs"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"locale"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"storeIDs"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"iaps"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"storeID"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"in"},"value":{"kind":"Variable","name":{"kind":"Name","value":"storeIDs"}}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"storeID"}},{"kind":"Field","name":{"kind":"Name","value":"interval"}},{"kind":"Field","name":{"kind":"Name","value":"offering"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"apiIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"commonContent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"supportUrl"}},{"kind":"Field","name":{"kind":"Name","value":"localizations"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"locale"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"supportUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"defaultPurchase"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stripePlanChoices"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stripePlanChoice"}}]}},{"kind":"Field","name":{"kind":"Name","value":"purchaseDetails"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"productName"}},{"kind":"Field","name":{"kind":"Name","value":"webIcon"}},{"kind":"Field","name":{"kind":"Name","value":"localizations"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"locale"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"productName"}},{"kind":"Field","name":{"kind":"Name","value":"webIcon"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"subGroups"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"groupName"}},{"kind":"Field","name":{"kind":"Name","value":"offerings"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"apiIdentifier"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const LegalTermsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"LegalTerms"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"identifier"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"legalNotices"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"serviceOrClientId"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"identifier"}}}]}}]}},{"kind":"Argument","name":{"kind":"Name","value":"pagination"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"1"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"serviceOrClientId"}},{"kind":"Field","name":{"kind":"Name","value":"Terms"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"termsOfServiceLink"}},{"kind":"Field","name":{"kind":"Name","value":"privacyNoticeLink"}},{"kind":"Field","name":{"kind":"Name","value":"fontSize"}}]}},{"kind":"Field","name":{"kind":"Name","value":"l10nId"}}]}}]}}]} as unknown as DocumentNode; export const LocalesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Locales"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"i18NLocales"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"pagination"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"100"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"code"}}]}}]}}]} as unknown as DocumentNode; +export const MeterBySlugDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"MeterBySlug"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"slug"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"meters"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"slug"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"slug"}}}]}}]}},{"kind":"Argument","name":{"kind":"Name","value":"pagination"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"1"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"slug"}},{"kind":"Field","name":{"kind":"Name","value":"unit"}},{"kind":"Field","name":{"kind":"Name","value":"limit"}},{"kind":"Field","name":{"kind":"Name","value":"window"}},{"kind":"Field","name":{"kind":"Name","value":"notificationThresholds"}},{"kind":"Field","name":{"kind":"Name","value":"webhooks"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"url"}},{"kind":"Field","name":{"kind":"Name","value":"signingClientId"}}]}}]}}]}}]} as unknown as DocumentNode; export const OfferingDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"Offering"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"locale"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"offering"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"documentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stripeProductId"}},{"kind":"Field","name":{"kind":"Name","value":"countries"}},{"kind":"Field","name":{"kind":"Name","value":"defaultPurchase"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"purchaseDetails"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"productName"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"subtitle"}},{"kind":"Field","name":{"kind":"Name","value":"webIcon"}},{"kind":"Field","name":{"kind":"Name","value":"localizations"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"locale"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"productName"}},{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"subtitle"}},{"kind":"Field","name":{"kind":"Name","value":"webIcon"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const PageContentByPriceIdsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"pageContentByPriceIds"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"locale"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"stripePlanIds"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"purchases"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"or"},"value":{"kind":"ListValue","values":[{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"stripePlanChoices"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"stripePlanChoice"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"in"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stripePlanIds"}}}]}}]}}]},{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"offering"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"stripeLegacyPlans"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"stripeLegacyPlan"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"in"},"value":{"kind":"Variable","name":{"kind":"Name","value":"stripePlanIds"}}}]}}]}}]}}]}]}}]}},{"kind":"Argument","name":{"kind":"Name","value":"pagination"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"50"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"offering"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stripeLegacyPlans"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"pagination"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"100"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stripeLegacyPlan"}}]}},{"kind":"Field","name":{"kind":"Name","value":"commonContent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"emailIcon"}},{"kind":"Field","name":{"kind":"Name","value":"supportUrl"}},{"kind":"Field","name":{"kind":"Name","value":"localizations"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"locale"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"emailIcon"}},{"kind":"Field","name":{"kind":"Name","value":"supportUrl"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"apiIdentifier"}}]}},{"kind":"Field","name":{"kind":"Name","value":"purchaseDetails"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"productName"}},{"kind":"Field","name":{"kind":"Name","value":"webIcon"}},{"kind":"Field","name":{"kind":"Name","value":"localizations"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"locale"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"productName"}},{"kind":"Field","name":{"kind":"Name","value":"webIcon"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"stripePlanChoices"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"stripePlanChoice"}}]}}]}}]}}]} as unknown as DocumentNode; export const PageContentForOfferingDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"PageContentForOffering"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"locale"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"apiIdentifier"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"offerings"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"apiIdentifier"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"apiIdentifier"}}}]}}]}},{"kind":"Argument","name":{"kind":"Name","value":"pagination"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"limit"},"value":{"kind":"IntValue","value":"200"}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"apiIdentifier"}},{"kind":"Field","name":{"kind":"Name","value":"countries"}},{"kind":"Field","name":{"kind":"Name","value":"stripeProductId"}},{"kind":"Field","name":{"kind":"Name","value":"defaultPurchase"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"purchaseDetails"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"productName"}},{"kind":"Field","name":{"kind":"Name","value":"subtitle"}},{"kind":"Field","name":{"kind":"Name","value":"webIcon"}},{"kind":"Field","name":{"kind":"Name","value":"localizations"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"locale"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"details"}},{"kind":"Field","name":{"kind":"Name","value":"productName"}},{"kind":"Field","name":{"kind":"Name","value":"subtitle"}},{"kind":"Field","name":{"kind":"Name","value":"webIcon"}}]}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"commonContent"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"privacyNoticeUrl"}},{"kind":"Field","name":{"kind":"Name","value":"privacyNoticeDownloadUrl"}},{"kind":"Field","name":{"kind":"Name","value":"termsOfServiceUrl"}},{"kind":"Field","name":{"kind":"Name","value":"termsOfServiceDownloadUrl"}},{"kind":"Field","name":{"kind":"Name","value":"cancellationUrl"}},{"kind":"Field","name":{"kind":"Name","value":"emailIcon"}},{"kind":"Field","name":{"kind":"Name","value":"successActionButtonUrl"}},{"kind":"Field","name":{"kind":"Name","value":"successActionButtonLabel"}},{"kind":"Field","name":{"kind":"Name","value":"newsletterLabelTextCode"}},{"kind":"Field","name":{"kind":"Name","value":"newsletterSlug"}},{"kind":"Field","name":{"kind":"Name","value":"localizations"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"filters"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"locale"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"eq"},"value":{"kind":"Variable","name":{"kind":"Name","value":"locale"}}}]}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"privacyNoticeUrl"}},{"kind":"Field","name":{"kind":"Name","value":"privacyNoticeDownloadUrl"}},{"kind":"Field","name":{"kind":"Name","value":"termsOfServiceUrl"}},{"kind":"Field","name":{"kind":"Name","value":"termsOfServiceDownloadUrl"}},{"kind":"Field","name":{"kind":"Name","value":"cancellationUrl"}},{"kind":"Field","name":{"kind":"Name","value":"emailIcon"}},{"kind":"Field","name":{"kind":"Name","value":"successActionButtonUrl"}},{"kind":"Field","name":{"kind":"Name","value":"successActionButtonLabel"}},{"kind":"Field","name":{"kind":"Name","value":"newsletterLabelTextCode"}},{"kind":"Field","name":{"kind":"Name","value":"newsletterSlug"}}]}}]}}]}}]}}]} as unknown as DocumentNode; diff --git a/libs/shared/cms/src/index.ts b/libs/shared/cms/src/index.ts index 1557bd58bdf..097d2f41f23 100644 --- a/libs/shared/cms/src/index.ts +++ b/libs/shared/cms/src/index.ts @@ -17,6 +17,7 @@ export * from './lib/queries/eligibility-content-by-plan-ids'; export * from './lib/queries/free-trial'; export * from './lib/queries/iap-offerings-by-storeids'; export * from './lib/queries/legal-terms'; +export * from './lib/queries/meter'; export * from './lib/queries/offering'; export * from './lib/queries/page-content-for-offering'; export * from './lib/queries/page-content-by-price-ids'; diff --git a/libs/shared/cms/src/lib/cms.error.ts b/libs/shared/cms/src/lib/cms.error.ts index f65166ad71b..e72203c4b46 100644 --- a/libs/shared/cms/src/lib/cms.error.ts +++ b/libs/shared/cms/src/lib/cms.error.ts @@ -119,19 +119,34 @@ export class MultipleEligilityContentOfferingResultsError extends QueriesUtilErr } } +export class MeterNotFoundError extends QueriesUtilError { + constructor(slug: string) { + super('Meter not found', { slug }); + this.name = 'MeterNotFoundError'; + } +} + +export class MeterInvalidNotificationThresholdError extends QueriesUtilError { + constructor(slug: string, value: number) { + super('Notification threshold must be between 0 and 100', { slug, value }); + this.name = 'MeterInvalidNotificationThresholdError'; + } +} + export class CmsValidationError extends CMSError { constructor( public readonly model: string, public readonly zodErrors: ZodError[] ) { - const errorCount = zodErrors.reduce( - (sum, e) => sum + e.issues.length, - 0 + const errorCount = zodErrors.reduce((sum, e) => sum + e.issues.length, 0); + super( + `CMS validation failed for ${model}: ${errorCount} issue(s)`, + { + model, + issues: zodErrors.map((e) => e.issues), + }, + new BaseMultiError(zodErrors) ); - super(`CMS validation failed for ${model}: ${errorCount} issue(s)`, { - model, - issues: zodErrors.map((e) => e.issues), - }, new BaseMultiError(zodErrors)); this.name = 'CmsValidationError'; } } diff --git a/libs/shared/cms/src/lib/queries/meter/factories.ts b/libs/shared/cms/src/lib/queries/meter/factories.ts new file mode 100644 index 00000000000..3209e04827d --- /dev/null +++ b/libs/shared/cms/src/lib/queries/meter/factories.ts @@ -0,0 +1,41 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { faker } from '@faker-js/faker'; +import { + METERING_WINDOWS, + MeterBySlugResult, + StrapiMeter, + StrapiMeterWebhook, +} from './types'; + +export const StrapiMeterWebhookFactory = ( + override?: Partial +): StrapiMeterWebhook => ({ + url: faker.internet.url(), + signingClientId: faker.string.uuid(), + ...override, +}); + +export const StrapiMeterFactory = ( + override?: Partial +): StrapiMeter => ({ + slug: faker.lorem.slug(), + unit: faker.string.sample(), + limit: faker.number.int({ min: 1, max: 1000 }), + window: faker.helpers.arrayElement(METERING_WINDOWS), + notificationThresholds: Array.from( + { length: faker.number.int({ min: 1, max: 4 }) }, + () => faker.number.int({ min: 1, max: 100 }) + ).join(','), + webhooks: [StrapiMeterWebhookFactory()], + ...override, +}); + +export const MeterBySlugResultFactory = ( + override?: Partial +): MeterBySlugResult => ({ + meters: [StrapiMeterFactory()], + ...override, +}); diff --git a/libs/shared/cms/src/lib/queries/meter/index.ts b/libs/shared/cms/src/lib/queries/meter/index.ts new file mode 100644 index 00000000000..81d1bbb1db8 --- /dev/null +++ b/libs/shared/cms/src/lib/queries/meter/index.ts @@ -0,0 +1,8 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +export * from './factories'; +export * from './query'; +export * from './types'; +export * from './util'; diff --git a/libs/shared/cms/src/lib/queries/meter/query.ts b/libs/shared/cms/src/lib/queries/meter/query.ts new file mode 100644 index 00000000000..14fd9e3ec45 --- /dev/null +++ b/libs/shared/cms/src/lib/queries/meter/query.ts @@ -0,0 +1,24 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { graphql } from '../../../__generated__/gql'; + +export const meterBySlugQuery = graphql(` + query MeterBySlug($slug: String!) { + meters( + filters: { slug: { eq: $slug } } + pagination: { limit: 1 } + ) { + slug + unit + limit + window + notificationThresholds + webhooks { + url + signingClientId + } + } + } +`); diff --git a/libs/shared/cms/src/lib/queries/meter/types.ts b/libs/shared/cms/src/lib/queries/meter/types.ts new file mode 100644 index 00000000000..7cbb828bbe5 --- /dev/null +++ b/libs/shared/cms/src/lib/queries/meter/types.ts @@ -0,0 +1,28 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +export const METERING_WINDOWS = ['daily', 'weekly', 'monthly'] as const; +export type MeteringWindow = (typeof METERING_WINDOWS)[number]; + +export interface StrapiMeterWebhook { + url: string; + signingClientId: string; +} + +export interface StrapiMeter { + slug: string; + unit: string; + limit: number; + window: MeteringWindow; + notificationThresholds: string; + webhooks: StrapiMeterWebhook[]; +} + +export interface MeterBySlugResult { + meters: StrapiMeter[]; +} + +export type MeterBySlugVariables = { + slug: string; +}; diff --git a/libs/shared/cms/src/lib/queries/meter/util.spec.ts b/libs/shared/cms/src/lib/queries/meter/util.spec.ts new file mode 100644 index 00000000000..38842b540c5 --- /dev/null +++ b/libs/shared/cms/src/lib/queries/meter/util.spec.ts @@ -0,0 +1,103 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { + MeterBySlugResultFactory, + MeterBySlugResultUtil, + StrapiMeterFactory, +} from '.'; +import { + MeterInvalidNotificationThresholdError, + MeterNotFoundError, +} from '../../cms.error'; + +describe('MeterBySlugResultUtil', () => { + it('returns the meter matching the factory result', () => { + const result = MeterBySlugResultFactory(); + const util = new MeterBySlugResultUtil(result, 'test-slug'); + expect(util.getMeter()).toEqual(result.meters[0]); + }); + + it('exposes the raw meters array', () => { + const result = MeterBySlugResultFactory(); + const util = new MeterBySlugResultUtil(result, 'test-slug'); + expect(util.meters).toHaveLength(1); + }); + + it('throws MeterNotFoundError when no meter is returned', () => { + const result = MeterBySlugResultFactory({ meters: [] }); + const util = new MeterBySlugResultUtil(result, 'test-slug'); + expect(() => util.getMeter()).toThrow(MeterNotFoundError); + }); + + it('parses comma-separated notificationThresholds into numbers', () => { + const result = MeterBySlugResultFactory({ + meters: [StrapiMeterFactory({ notificationThresholds: '50,75,90' })], + }); + const util = new MeterBySlugResultUtil(result, 'test-slug'); + expect(util.getNotificationThresholds()).toEqual([50, 75, 90]); + }); + + it('ignores empty entries from double commas or trailing commas', () => { + const result = MeterBySlugResultFactory({ + meters: [StrapiMeterFactory({ notificationThresholds: '50,,80,100,' })], + }); + const util = new MeterBySlugResultUtil(result, 'test-slug'); + expect(util.getNotificationThresholds()).toEqual([50, 80, 100]); + }); + + it('returns an empty array for empty-string notificationThresholds', () => { + const result = MeterBySlugResultFactory({ + meters: [StrapiMeterFactory({ notificationThresholds: '' })], + }); + const util = new MeterBySlugResultUtil(result, 'test-slug'); + expect(util.getNotificationThresholds()).toEqual([]); + }); + + it('preserves 0 as a valid threshold value', () => { + const result = MeterBySlugResultFactory({ + meters: [StrapiMeterFactory({ notificationThresholds: '0,50,100' })], + }); + const util = new MeterBySlugResultUtil(result, 'test-slug'); + expect(util.getNotificationThresholds()).toEqual([0, 50, 100]); + }); + + it('trims whitespace around threshold values', () => { + const result = MeterBySlugResultFactory({ + meters: [ + StrapiMeterFactory({ notificationThresholds: ' 50 , 75 , 90 ' }), + ], + }); + const util = new MeterBySlugResultUtil(result, 'test-slug'); + expect(util.getNotificationThresholds()).toEqual([50, 75, 90]); + }); + + it('throws MeterInvalidNotificationThresholdError for negative values', () => { + const result = MeterBySlugResultFactory({ + meters: [StrapiMeterFactory({ notificationThresholds: '-10,50,90' })], + }); + const util = new MeterBySlugResultUtil(result, 'test-slug'); + expect(() => util.getNotificationThresholds()).toThrow( + MeterInvalidNotificationThresholdError + ); + }); + + it('throws MeterInvalidNotificationThresholdError for values above 100', () => { + const result = MeterBySlugResultFactory({ + meters: [StrapiMeterFactory({ notificationThresholds: '50,150,90' })], + }); + const util = new MeterBySlugResultUtil(result, 'test-slug'); + expect(() => util.getNotificationThresholds()).toThrow( + MeterInvalidNotificationThresholdError + ); + }); + + it('filters out non-numeric notificationThresholds values', () => { + const result = MeterBySlugResultFactory({ + meters: [StrapiMeterFactory({ notificationThresholds: '50,abc,90' })], + }); + const util = new MeterBySlugResultUtil(result, 'test-slug'); + expect(util.getNotificationThresholds()).toEqual([50, 90]); + }); +}); diff --git a/libs/shared/cms/src/lib/queries/meter/util.ts b/libs/shared/cms/src/lib/queries/meter/util.ts new file mode 100644 index 00000000000..5653efb8c30 --- /dev/null +++ b/libs/shared/cms/src/lib/queries/meter/util.ts @@ -0,0 +1,44 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +import { + MeterInvalidNotificationThresholdError, + MeterNotFoundError, +} from '../../cms.error'; +import { MeterBySlugResult, StrapiMeter } from './types'; + +export class MeterBySlugResultUtil { + constructor( + private rawResult: MeterBySlugResult, + private slug: string + ) {} + + getMeter(): StrapiMeter { + const meter = this.meters.at(0); + if (!meter) throw new MeterNotFoundError(this.slug); + return meter; + } + + getNotificationThresholds(): number[] { + const meter = this.getMeter(); + const thresholds = meter.notificationThresholds + .split(',') + .map((s) => s.trim()) + .filter((s) => s.length > 0) + .map(Number) + .filter((n) => !Number.isNaN(n)); + + for (const n of thresholds) { + if (n < 0 || n > 100) { + throw new MeterInvalidNotificationThresholdError(this.slug, n); + } + } + + return thresholds; + } + + get meters(): MeterBySlugResult['meters'] { + return this.rawResult.meters; + } +}