// Package intentstream defines the frozen Redis Stream contract used for // Notification Service intent intake. package intentstream import ( "strings" "galaxy/notification/internal/service/malformedintent" "galaxy/notificationintent" ) const ( fieldNotificationType = "notification_type" fieldProducer = "producer" fieldAudienceKind = "audience_kind" fieldRecipientUserIDs = "recipient_user_ids_json" fieldIdempotencyKey = "idempotency_key" fieldOccurredAtMS = "occurred_at_ms" fieldRequestID = "request_id" fieldTraceID = "trace_id" fieldPayloadJSON = "payload_json" defaultResolvedLocale = "en" ) // NotificationType identifies one supported normalized notification type. type NotificationType = notificationintent.NotificationType const ( // NotificationTypeGeoReviewRecommended identifies the // `geo.review_recommended` notification. NotificationTypeGeoReviewRecommended = notificationintent.NotificationTypeGeoReviewRecommended // NotificationTypeGameTurnReady identifies the `game.turn.ready` // notification. NotificationTypeGameTurnReady = notificationintent.NotificationTypeGameTurnReady // NotificationTypeGameFinished identifies the `game.finished` // notification. NotificationTypeGameFinished = notificationintent.NotificationTypeGameFinished // NotificationTypeGameGenerationFailed identifies the // `game.generation_failed` notification. NotificationTypeGameGenerationFailed = notificationintent.NotificationTypeGameGenerationFailed // NotificationTypeLobbyRuntimePausedAfterStart identifies the // `lobby.runtime_paused_after_start` notification. NotificationTypeLobbyRuntimePausedAfterStart = notificationintent.NotificationTypeLobbyRuntimePausedAfterStart // NotificationTypeLobbyApplicationSubmitted identifies the // `lobby.application.submitted` notification. NotificationTypeLobbyApplicationSubmitted = notificationintent.NotificationTypeLobbyApplicationSubmitted // NotificationTypeLobbyMembershipApproved identifies the // `lobby.membership.approved` notification. NotificationTypeLobbyMembershipApproved = notificationintent.NotificationTypeLobbyMembershipApproved // NotificationTypeLobbyMembershipRejected identifies the // `lobby.membership.rejected` notification. NotificationTypeLobbyMembershipRejected = notificationintent.NotificationTypeLobbyMembershipRejected // NotificationTypeLobbyInviteCreated identifies the // `lobby.invite.created` notification. NotificationTypeLobbyInviteCreated = notificationintent.NotificationTypeLobbyInviteCreated // NotificationTypeLobbyInviteRedeemed identifies the // `lobby.invite.redeemed` notification. NotificationTypeLobbyInviteRedeemed = notificationintent.NotificationTypeLobbyInviteRedeemed // NotificationTypeLobbyInviteExpired identifies the // `lobby.invite.expired` notification. NotificationTypeLobbyInviteExpired = notificationintent.NotificationTypeLobbyInviteExpired ) // Producer identifies one supported upstream producer. type Producer = notificationintent.Producer const ( // ProducerGeoProfile identifies Geo Profile Service. ProducerGeoProfile = notificationintent.ProducerGeoProfile // ProducerGameMaster identifies Game Master. ProducerGameMaster = notificationintent.ProducerGameMaster // ProducerGameLobby identifies Game Lobby. ProducerGameLobby = notificationintent.ProducerGameLobby ) // AudienceKind identifies one supported target-audience kind. type AudienceKind = notificationintent.AudienceKind const ( // AudienceKindUser identifies user-targeted notifications. AudienceKindUser = notificationintent.AudienceKindUser // AudienceKindAdminEmail identifies administrator-email notifications. AudienceKindAdminEmail = notificationintent.AudienceKindAdminEmail ) // Channel identifies one durable notification-delivery channel slot. type Channel = notificationintent.Channel const ( // ChannelPush identifies the push-delivery channel. ChannelPush = notificationintent.ChannelPush // ChannelEmail identifies the email-delivery channel. ChannelEmail = notificationintent.ChannelEmail ) // Intent stores one normalized notification intent accepted from the Redis // Stream ingress contract. type Intent = notificationintent.Intent // DecodeIntent validates one raw Redis Stream entry and returns the normalized // notification intent frozen by the shared producer contract. func DecodeIntent(fields map[string]any) (Intent, error) { return notificationintent.DecodeIntent(fields) } // ClassifyDecodeError maps one intake decoding or validation error to the // stable malformed-intent failure surface. func ClassifyDecodeError(err error) malformedintent.FailureCode { if err == nil { return malformedintent.FailureCodeInvalidIntent } message := err.Error() switch { case strings.Contains(message, "payload_json"), strings.Contains(message, "turn_number"), strings.Contains(message, "final_turn_number"), strings.Contains(message, "failure_reason"), strings.Contains(message, "applicant_name"), strings.Contains(message, "inviter_name"), strings.Contains(message, "invitee_name"), strings.Contains(message, "review_reason"): return malformedintent.FailureCodeInvalidPayload default: return malformedintent.FailureCodeInvalidIntent } } // DefaultResolvedLocale returns the frozen fallback locale assigned when the // current rollout has no supported exact user locale other than English. func DefaultResolvedLocale() string { return defaultResolvedLocale }