// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package google.cloud.bigquery.analyticshub.v1;

import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/protobuf/duration.proto";

option csharp_namespace = "Google.Cloud.BigQuery.AnalyticsHub.V1";
option go_package = "cloud.google.com/go/bigquery/analyticshub/apiv1/analyticshubpb;analyticshubpb";
option java_multiple_files = true;
option java_outer_classname = "PubsubProto";
option java_package = "com.google.cloud.bigquery.analyticshub.v1";
option php_namespace = "Google\\Cloud\\BigQuery\\AnalyticsHub\\V1";
option ruby_package = "Google::Cloud::Bigquery::AnalyticsHub::V1";

// Defines the destination Pub/Sub subscription.
// If none of `push_config`, `bigquery_config`, `cloud_storage_config`,
// `pubsub_export_config`, or `pubsublite_export_config`
// is set, then the subscriber will pull and ack messages using API methods. At
// most one of these fields may be set.
message PubSubSubscription {
  // Required. Name of the subscription.
  // Format is `projects/{project}/subscriptions/{sub}`.
  string name = 1 [(google.api.field_behavior) = REQUIRED];

  // Optional. If push delivery is used with this subscription, this field is
  // used to configure it.
  PushConfig push_config = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. If delivery to BigQuery is used with this subscription, this
  // field is used to configure it.
  BigQueryConfig bigquery_config = 18 [(google.api.field_behavior) = OPTIONAL];

  // Optional. If delivery to Google Cloud Storage is used with this
  // subscription, this field is used to configure it.
  CloudStorageConfig cloud_storage_config = 22
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. The approximate amount of time (on a best-effort basis) Pub/Sub
  // waits for the subscriber to acknowledge receipt before resending the
  // message. In the interval after the message is delivered and before it is
  // acknowledged, it is considered to be _outstanding_. During that time
  // period, the message will not be redelivered (on a best-effort basis).
  //
  // For pull subscriptions, this value is used as the initial value for the ack
  // deadline. To override this value for a given message, call
  // `ModifyAckDeadline` with the corresponding `ack_id` if using
  // non-streaming pull or send the `ack_id` in a
  // `StreamingModifyAckDeadlineRequest` if using streaming pull.
  // The minimum custom deadline you can specify is 10 seconds.
  // The maximum custom deadline you can specify is 600 seconds (10 minutes).
  // If this parameter is 0, a default value of 10 seconds is used.
  //
  // For push delivery, this value is also used to set the request timeout for
  // the call to the push endpoint.
  //
  // If the subscriber never acknowledges the message, the Pub/Sub
  // system will eventually redeliver the message.
  int32 ack_deadline_seconds = 5 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Indicates whether to retain acknowledged messages. If true, then
  // messages are not expunged from the subscription's backlog, even if they are
  // acknowledged, until they fall out of the `message_retention_duration`
  // window. This must be true if you would like to [`Seek` to a timestamp]
  // (https://cloud.google.com/pubsub/docs/replay-overview#seek_to_a_time) in
  // the past to replay previously-acknowledged messages.
  bool retain_acked_messages = 7 [(google.api.field_behavior) = OPTIONAL];

  // Optional. How long to retain unacknowledged messages in the subscription's
  // backlog, from the moment a message is published. If `retain_acked_messages`
  // is true, then this also configures the retention of acknowledged messages,
  // and thus configures how far back in time a `Seek` can be done. Defaults to
  // 7 days. Cannot be more than 31 days or less than 10 minutes.
  google.protobuf.Duration message_retention_duration = 8
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. See [Creating and managing
  // labels](https://cloud.google.com/pubsub/docs/labels).
  map<string, string> labels = 9 [(google.api.field_behavior) = OPTIONAL];

  // Optional. If true, messages published with the same `ordering_key` in
  // `PubsubMessage` will be delivered to the subscribers in the order in which
  // they are received by the Pub/Sub system. Otherwise, they may be delivered
  // in any order.
  bool enable_message_ordering = 10 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A policy that specifies the conditions for this subscription's
  // expiration. A subscription is considered active as long as any connected
  // subscriber is successfully consuming messages from the subscription or is
  // issuing operations on the subscription. If `expiration_policy` is not set,
  // a *default policy* with `ttl` of 31 days will be used. The minimum allowed
  // value for `expiration_policy.ttl` is 1 day. If `expiration_policy` is set,
  // but `expiration_policy.ttl` is not set, the subscription never expires.
  ExpirationPolicy expiration_policy = 11
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. An expression written in the Pub/Sub [filter
  // language](https://cloud.google.com/pubsub/docs/filtering). If non-empty,
  // then only `PubsubMessage`s whose `attributes` field matches the filter are
  // delivered on this subscription. If empty, then no messages are filtered
  // out.
  string filter = 12 [(google.api.field_behavior) = OPTIONAL];

  // Optional. A policy that specifies the conditions for dead lettering
  // messages in this subscription. If dead_letter_policy is not set, dead
  // lettering is disabled.
  //
  // The Pub/Sub service account associated with this subscriptions's
  // parent project (i.e.,
  // service-{project_number}@gcp-sa-pubsub.iam.gserviceaccount.com) must have
  // permission to Acknowledge() messages on this subscription.
  DeadLetterPolicy dead_letter_policy = 13
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. A policy that specifies how Pub/Sub retries message delivery for
  // this subscription.
  //
  // If not set, the default retry policy is applied. This generally implies
  // that messages will be retried as soon as possible for healthy subscribers.
  // RetryPolicy will be triggered on NACKs or acknowledgement deadline
  // exceeded events for a given message.
  RetryPolicy retry_policy = 14 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Indicates whether the subscription is detached from its topic.
  // Detached subscriptions don't receive messages from their topic and don't
  // retain any backlog. `Pull` and `StreamingPull` requests will return
  // FAILED_PRECONDITION. If the subscription is a push subscription, pushes to
  // the endpoint will not be made.
  bool detached = 15 [(google.api.field_behavior) = OPTIONAL];

  // Optional. If true, Pub/Sub provides the following guarantees for the
  // delivery of a message with a given value of `message_id` on this
  // subscription:
  //
  // * The message sent to a subscriber is guaranteed not to be resent
  // before the message's acknowledgement deadline expires.
  // * An acknowledged message will not be resent to a subscriber.
  //
  // Note that subscribers may still receive multiple copies of a message
  // when `enable_exactly_once_delivery` is true if the message was published
  // multiple times by a publisher client. These copies are  considered distinct
  // by Pub/Sub and have distinct `message_id` values.
  bool enable_exactly_once_delivery = 16
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. Transforms to be applied to messages before they are delivered to
  // subscribers. Transforms are applied in the order specified.
  repeated MessageTransform message_transforms = 25
      [(google.api.field_behavior) = OPTIONAL];
}

// A policy that specifies how Pub/Sub retries message delivery.
//
// Retry delay will be exponential based on provided minimum and maximum
// backoffs. https://en.wikipedia.org/wiki/Exponential_backoff.
//
// RetryPolicy will be triggered on NACKs or acknowledgement deadline exceeded
// events for a given message.
//
// Retry Policy is implemented on a best effort basis. At times, the delay
// between consecutive deliveries may not match the configuration. That is,
// delay can be more or less than configured backoff.
message RetryPolicy {
  // Optional. The minimum delay between consecutive deliveries of a given
  // message. Value should be between 0 and 600 seconds. Defaults to 10 seconds.
  google.protobuf.Duration minimum_backoff = 1
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. The maximum delay between consecutive deliveries of a given
  // message. Value should be between 0 and 600 seconds. Defaults to 600
  // seconds.
  google.protobuf.Duration maximum_backoff = 2
      [(google.api.field_behavior) = OPTIONAL];
}

// Dead lettering is done on a best effort basis. The same message might be
// dead lettered multiple times.
//
// If validation on any of the fields fails at subscription creation/updation,
// the create/update subscription request will fail.
message DeadLetterPolicy {
  // Optional. The name of the topic to which dead letter messages should be
  // published. Format is `projects/{project}/topics/{topic}`.The Pub/Sub
  // service account associated with the enclosing subscription's parent project
  // (i.e., service-{project_number}@gcp-sa-pubsub.iam.gserviceaccount.com) must
  // have permission to Publish() to this topic.
  //
  // The operation will fail if the topic does not exist.
  // Users should ensure that there is a subscription attached to this topic
  // since messages published to a topic with no subscriptions are lost.
  string dead_letter_topic = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The maximum number of delivery attempts for any message. The
  // value must be between 5 and 100.
  //
  // The number of delivery attempts is defined as 1 + (the sum of number of
  // NACKs and number of times the acknowledgement deadline has been exceeded
  // for the message).
  //
  // A NACK is any call to ModifyAckDeadline with a 0 deadline. Note that
  // client libraries may automatically extend ack_deadlines.
  //
  // This field will be honored on a best effort basis.
  //
  // If this parameter is 0, a default value of 5 is used.
  int32 max_delivery_attempts = 2 [(google.api.field_behavior) = OPTIONAL];
}

// A policy that specifies the conditions for resource expiration (i.e.,
// automatic resource deletion).
message ExpirationPolicy {
  // Optional. Specifies the "time-to-live" duration for an associated resource.
  // The resource expires if it is not active for a period of `ttl`. The
  // definition of "activity" depends on the type of the associated resource.
  // The minimum and maximum allowed values for `ttl` depend on the type of the
  // associated resource, as well. If `ttl` is not set, the associated resource
  // never expires.
  google.protobuf.Duration ttl = 1 [(google.api.field_behavior) = OPTIONAL];
}

// Configuration for a push delivery endpoint.
message PushConfig {
  // Contains information needed for generating an
  // [OpenID Connect
  // token](https://developers.google.com/identity/protocols/OpenIDConnect).
  message OidcToken {
    // Optional. [Service account
    // email](https://cloud.google.com/iam/docs/service-accounts)
    // used for generating the OIDC token. For more information
    // on setting up authentication, see
    // [Push subscriptions](https://cloud.google.com/pubsub/docs/push).
    string service_account_email = 1 [(google.api.field_behavior) = OPTIONAL];

    // Optional. Audience to be used when generating OIDC token. The audience
    // claim identifies the recipients that the JWT is intended for. The
    // audience value is a single case-sensitive string. Having multiple values
    // (array) for the audience field is not supported. More info about the OIDC
    // JWT token audience here:
    // https://tools.ietf.org/html/rfc7519#section-4.1.3 Note: if not specified,
    // the Push endpoint URL will be used.
    string audience = 2 [(google.api.field_behavior) = OPTIONAL];
  }

  // The payload to the push endpoint is in the form of the JSON representation
  // of a PubsubMessage
  // (https://cloud.google.com/pubsub/docs/reference/rpc/google.pubsub.v1#pubsubmessage).
  message PubsubWrapper {}

  // Sets the `data` field as the HTTP body for delivery.
  message NoWrapper {
    // Optional. When true, writes the Pub/Sub message metadata to
    // `x-goog-pubsub-<KEY>:<VAL>` headers of the HTTP request. Writes the
    // Pub/Sub message attributes to `<KEY>:<VAL>` headers of the HTTP request.
    bool write_metadata = 1 [(google.api.field_behavior) = OPTIONAL];
  }

  // An authentication method used by push endpoints to verify the source of
  // push requests. This can be used with push endpoints that are private by
  // default to allow requests only from the Pub/Sub system, for example.
  // This field is optional and should be set only by users interested in
  // authenticated push.
  oneof authentication_method {
    // Optional. If specified, Pub/Sub will generate and attach an OIDC JWT
    // token as an `Authorization` header in the HTTP request for every pushed
    // message.
    OidcToken oidc_token = 3 [(google.api.field_behavior) = OPTIONAL];
  }

  // The format of the delivered message to the push endpoint is defined by
  // the chosen wrapper. When unset, `PubsubWrapper` is used.
  oneof wrapper {
    // Optional. When set, the payload to the push endpoint is in the form of
    // the JSON representation of a PubsubMessage
    // (https://cloud.google.com/pubsub/docs/reference/rpc/google.pubsub.v1#pubsubmessage).
    PubsubWrapper pubsub_wrapper = 4 [(google.api.field_behavior) = OPTIONAL];

    // Optional. When set, the payload to the push endpoint is not wrapped.
    NoWrapper no_wrapper = 5 [(google.api.field_behavior) = OPTIONAL];
  }

  // Optional. A URL locating the endpoint to which messages should be pushed.
  // For example, a Webhook endpoint might use `https://example.com/push`.
  string push_endpoint = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Endpoint configuration attributes that can be used to control
  // different aspects of the message delivery.
  //
  // The only currently supported attribute is `x-goog-version`, which you can
  // use to change the format of the pushed message. This attribute
  // indicates the version of the data expected by the endpoint. This
  // controls the shape of the pushed message (i.e., its fields and metadata).
  //
  // If not present during the `CreateSubscription` call, it will default to
  // the version of the Pub/Sub API used to make such call. If not present in a
  // `ModifyPushConfig` call, its value will not be changed. `GetSubscription`
  // calls will always return a valid version, even if the subscription was
  // created without this attribute.
  //
  // The only supported values for the `x-goog-version` attribute are:
  //
  // * `v1beta1`: uses the push format defined in the v1beta1 Pub/Sub API.
  // * `v1` or `v1beta2`: uses the push format defined in the v1 Pub/Sub API.
  //
  // For example:
  // `attributes { "x-goog-version": "v1" }`
  map<string, string> attributes = 2 [(google.api.field_behavior) = OPTIONAL];
}

// Configuration for a BigQuery subscription.
message BigQueryConfig {
  // Optional. The name of the table to which to write data, of the form
  // {projectId}.{datasetId}.{tableId}
  string table = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. When true, use the topic's schema as the columns to write to in
  // BigQuery, if it exists. `use_topic_schema` and `use_table_schema` cannot be
  // enabled at the same time.
  bool use_topic_schema = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. When true, write the subscription name, message_id, publish_time,
  // attributes, and ordering_key to additional columns in the table. The
  // subscription name, message_id, and publish_time fields are put in their own
  // columns while all other message properties (other than data) are written to
  // a JSON object in the attributes column.
  bool write_metadata = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. When true and use_topic_schema is true, any fields that are a
  // part of the topic schema that are not part of the BigQuery table schema are
  // dropped when writing to BigQuery. Otherwise, the schemas must be kept in
  // sync and any messages with extra fields are not written and remain in the
  // subscription's backlog.
  bool drop_unknown_fields = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. When true, use the BigQuery table's schema as the columns to
  // write to in BigQuery. `use_table_schema` and `use_topic_schema` cannot be
  // enabled at the same time.
  bool use_table_schema = 6 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The service account to use to write to BigQuery. The subscription
  // creator or updater that specifies this field must have
  // `iam.serviceAccounts.actAs` permission on the service account. If not
  // specified, the Pub/Sub [service
  // agent](https://cloud.google.com/iam/docs/service-agents),
  // service-{project_number}@gcp-sa-pubsub.iam.gserviceaccount.com, is used.
  string service_account_email = 7 [(google.api.field_behavior) = OPTIONAL];
}

// Configuration for a Cloud Storage subscription.
message CloudStorageConfig {
  // Configuration for writing message data in text format.
  // Message payloads will be written to files as raw text, separated by a
  // newline.
  message TextConfig {}

  // Configuration for writing message data in Avro format.
  // Message payloads and metadata will be written to files as an Avro binary.
  message AvroConfig {
    // Optional. When true, write the subscription name, message_id,
    // publish_time, attributes, and ordering_key as additional fields in the
    // output. The subscription name, message_id, and publish_time fields are
    // put in their own fields while all other message properties other than
    // data (for example, an ordering_key, if present) are added as entries in
    // the attributes map.
    bool write_metadata = 1 [(google.api.field_behavior) = OPTIONAL];

    // Optional. When true, the output Cloud Storage file will be serialized
    // using the topic schema, if it exists.
    bool use_topic_schema = 2 [(google.api.field_behavior) = OPTIONAL];
  }

  // Defaults to text format.
  oneof output_format {
    // Optional. If set, message data will be written to Cloud Storage in text
    // format.
    TextConfig text_config = 4 [(google.api.field_behavior) = OPTIONAL];

    // Optional. If set, message data will be written to Cloud Storage in Avro
    // format.
    AvroConfig avro_config = 5 [(google.api.field_behavior) = OPTIONAL];
  }

  // Required. User-provided name for the Cloud Storage bucket.
  // The bucket must be created by the user. The bucket name must be without
  // any prefix like "gs://". See the [bucket naming
  // requirements] (https://cloud.google.com/storage/docs/buckets#naming).
  string bucket = 1 [(google.api.field_behavior) = REQUIRED];

  // Optional. User-provided prefix for Cloud Storage filename. See the [object
  // naming requirements](https://cloud.google.com/storage/docs/objects#naming).
  string filename_prefix = 2 [(google.api.field_behavior) = OPTIONAL];

  // Optional. User-provided suffix for Cloud Storage filename. See the [object
  // naming requirements](https://cloud.google.com/storage/docs/objects#naming).
  // Must not end in "/".
  string filename_suffix = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. User-provided format string specifying how to represent datetimes
  // in Cloud Storage filenames. See the [datetime format
  // guidance](https://cloud.google.com/pubsub/docs/create-cloudstorage-subscription#file_names).
  string filename_datetime_format = 10 [(google.api.field_behavior) = OPTIONAL];

  // Optional. File batching settings.
  // If no max_duration setting is specified, a max_duration of 5 minutes will
  // be set by default. max_duration is required regardless of whether other
  // file batching settings are specified.
  //
  // The maximum duration that can elapse before a new Cloud Storage file is
  // created. Min 1 minute, max 10 minutes, default 5 minutes. May not exceed
  // the subscription's acknowledgement deadline.
  google.protobuf.Duration max_duration = 6
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. The maximum bytes that can be written to a Cloud Storage file
  // before a new file is created. Min 1 KB, max 10 GiB. The max_bytes limit may
  // be exceeded in cases where messages are larger than the limit.
  int64 max_bytes = 7 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The maximum number of messages that can be written to a Cloud
  // Storage file before a new file is created. Min 1000 messages.
  int64 max_messages = 8 [(google.api.field_behavior) = OPTIONAL];

  // Optional. The service account to use to write to Cloud Storage. The
  // subscription creator or updater that specifies this field must have
  // `iam.serviceAccounts.actAs` permission on the service account. If not
  // specified, the Pub/Sub
  // [service agent](https://cloud.google.com/iam/docs/service-agents),
  // service-{project_number}@gcp-sa-pubsub.iam.gserviceaccount.com, is used.
  string service_account_email = 11 [(google.api.field_behavior) = OPTIONAL];
}

// All supported message transforms types.
message MessageTransform {
  // The type of transform to apply to messages.
  oneof transform {
    // Optional. JavaScript User Defined Function. If multiple JavaScriptUDF's
    // are specified on a resource, each must have a unique `function_name`.
    JavaScriptUDF javascript_udf = 2 [(google.api.field_behavior) = OPTIONAL];
  }

  // Optional. This field is deprecated, use the `disabled` field to disable
  // transforms.
  bool enabled = 3 [deprecated = true, (google.api.field_behavior) = OPTIONAL];

  // Optional. If true, the transform is disabled and will not be applied to
  // messages. Defaults to `false`.
  bool disabled = 4 [(google.api.field_behavior) = OPTIONAL];
}

// User-defined JavaScript function that can transform or filter a Pub/Sub
// message.
message JavaScriptUDF {
  // Required. Name of the JavasScript function that should applied to Pub/Sub
  // messages.
  string function_name = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. JavaScript code that contains a function `function_name` with the
  // below signature:
  //
  // ```
  //   /**
  //   * Transforms a Pub/Sub message.
  //
  //   * @return {(Object<string, (string | Object<string, string>)>|null)} - To
  //   * filter a message, return `null`. To transform a message return a map
  //   * with the following keys:
  //   *   - (required) 'data' : {string}
  //   *   - (optional) 'attributes' : {Object<string, string>}
  //   * Returning empty `attributes` will remove all attributes from the
  //   * message.
  //   *
  //   * @param  {(Object<string, (string | Object<string, string>)>} Pub/Sub
  //   * message. Keys:
  //   *   - (required) 'data' : {string}
  //   *   - (required) 'attributes' : {Object<string, string>}
  //   *
  //   * @param  {Object<string, any>} metadata - Pub/Sub message metadata.
  //   * Keys:
  //   *   - (required) 'message_id'  : {string}
  //   *   - (optional) 'publish_time': {string} YYYY-MM-DDTHH:MM:SSZ format
  //   *   - (optional) 'ordering_key': {string}
  //   */
  //
  //   function <function_name>(message, metadata) {
  //   }
  // ```
  string code = 2 [(google.api.field_behavior) = REQUIRED];
}
