// 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/annotations.proto";
import "google/api/client.proto";
import "google/api/field_behavior.proto";
import "google/api/resource.proto";
import "google/cloud/bigquery/analyticshub/v1/pubsub.proto";
import "google/iam/v1/iam_policy.proto";
import "google/iam/v1/policy.proto";
import "google/longrunning/operations.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/field_mask.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/wrappers.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 = "AnalyticsHubProto";
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";
option (google.api.resource_definition) = {
  type: "bigquery.googleapis.com/Dataset"
  pattern: "projects/{project}/datasets/{dataset}"
};
option (google.api.resource_definition) = {
  type: "bigquery.googleapis.com/Table"
  pattern: "projects/{project}/datasets/{dataset}/tables/{table}"
};
option (google.api.resource_definition) = {
  type: "pubsub.googleapis.com/Topic"
  pattern: "projects/{project}/topics/{topic}"
};
option (google.api.resource_definition) = {
  type: "bigquery.googleapis.com/Routine"
  pattern: "projects/{project}/datasets/{dataset}/routines/{routine}"
};
option (google.api.resource_definition) = {
  type: "servicemanagement.googleapis.com/ManagedService"
  pattern: "services/{service}"
};
option (google.api.resource_definition) = {
  type: "cloudcommerceconsumerprocurement.googleapis.com/Order"
  pattern: "projects/{project}/orders/{order}"
};

// The `AnalyticsHubService` API facilitates data sharing within and across
// organizations. It allows data providers to publish listings that reference
// shared datasets. With Analytics Hub, users can discover and search for
// listings that they have access to. Subscribers can view and subscribe to
// listings. When you subscribe to a listing, Analytics Hub creates a linked
// dataset in your project.
service AnalyticsHubService {
  option (google.api.default_host) = "analyticshub.googleapis.com";
  option (google.api.oauth_scopes) =
      "https://www.googleapis.com/auth/bigquery,"
      "https://www.googleapis.com/auth/cloud-platform";

  // Lists all data exchanges in a given project and location.
  rpc ListDataExchanges(ListDataExchangesRequest)
      returns (ListDataExchangesResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=projects/*/locations/*}/dataExchanges"
    };
    option (google.api.method_signature) = "parent";
  }

  // Lists all data exchanges from projects in a given organization and
  // location.
  rpc ListOrgDataExchanges(ListOrgDataExchangesRequest)
      returns (ListOrgDataExchangesResponse) {
    option (google.api.http) = {
      get: "/v1/{organization=organizations/*/locations/*}/dataExchanges"
    };
    option (google.api.method_signature) = "organization";
  }

  // Gets the details of a data exchange.
  rpc GetDataExchange(GetDataExchangeRequest) returns (DataExchange) {
    option (google.api.http) = {
      get: "/v1/{name=projects/*/locations/*/dataExchanges/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Creates a new data exchange.
  rpc CreateDataExchange(CreateDataExchangeRequest) returns (DataExchange) {
    option (google.api.http) = {
      post: "/v1/{parent=projects/*/locations/*}/dataExchanges"
      body: "data_exchange"
    };
    option (google.api.method_signature) = "parent,data_exchange";
  }

  // Updates an existing data exchange.
  rpc UpdateDataExchange(UpdateDataExchangeRequest) returns (DataExchange) {
    option (google.api.http) = {
      patch: "/v1/{data_exchange.name=projects/*/locations/*/dataExchanges/*}"
      body: "data_exchange"
    };
    option (google.api.method_signature) = "data_exchange,update_mask";
  }

  // Deletes an existing data exchange.
  rpc DeleteDataExchange(DeleteDataExchangeRequest)
      returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/v1/{name=projects/*/locations/*/dataExchanges/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Lists all listings in a given project and location.
  rpc ListListings(ListListingsRequest) returns (ListListingsResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=projects/*/locations/*/dataExchanges/*}/listings"
    };
    option (google.api.method_signature) = "parent";
  }

  // Gets the details of a listing.
  rpc GetListing(GetListingRequest) returns (Listing) {
    option (google.api.http) = {
      get: "/v1/{name=projects/*/locations/*/dataExchanges/*/listings/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Creates a new listing.
  rpc CreateListing(CreateListingRequest) returns (Listing) {
    option (google.api.http) = {
      post: "/v1/{parent=projects/*/locations/*/dataExchanges/*}/listings"
      body: "listing"
    };
    option (google.api.method_signature) = "parent,listing";
  }

  // Updates an existing listing.
  rpc UpdateListing(UpdateListingRequest) returns (Listing) {
    option (google.api.http) = {
      patch: "/v1/{listing.name=projects/*/locations/*/dataExchanges/*/listings/*}"
      body: "listing"
    };
    option (google.api.method_signature) = "listing,update_mask";
  }

  // Deletes a listing.
  rpc DeleteListing(DeleteListingRequest) returns (google.protobuf.Empty) {
    option (google.api.http) = {
      delete: "/v1/{name=projects/*/locations/*/dataExchanges/*/listings/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Subscribes to a listing.
  //
  // Currently, with Analytics Hub, you can create listings that
  // reference only BigQuery datasets.
  // Upon subscription to a listing for a BigQuery dataset, Analytics Hub
  // creates a linked dataset in the subscriber's project.
  rpc SubscribeListing(SubscribeListingRequest)
      returns (SubscribeListingResponse) {
    option (google.api.http) = {
      post: "/v1/{name=projects/*/locations/*/dataExchanges/*/listings/*}:subscribe"
      body: "*"
    };
    option (google.api.method_signature) = "name";
  }

  // Creates a Subscription to a Data Clean Room. This is a
  // long-running operation as it will create one or more linked datasets.
  // Throws a Bad Request error if the Data Exchange does not contain any
  // listings.
  rpc SubscribeDataExchange(SubscribeDataExchangeRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v1/{name=projects/*/locations/*/dataExchanges/*}:subscribe"
      body: "*"
    };
    option (google.api.method_signature) = "name";
    option (google.longrunning.operation_info) = {
      response_type: "SubscribeDataExchangeResponse"
      metadata_type: "OperationMetadata"
    };
  }

  // Refreshes a Subscription to a Data Exchange. A Data Exchange can become
  // stale when a publisher adds or removes data. This is a long-running
  // operation as it may create many linked datasets.
  rpc RefreshSubscription(RefreshSubscriptionRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      post: "/v1/{name=projects/*/locations/*/subscriptions/*}:refresh"
      body: "*"
    };
    option (google.api.method_signature) = "name";
    option (google.longrunning.operation_info) = {
      response_type: "RefreshSubscriptionResponse"
      metadata_type: "OperationMetadata"
    };
  }

  // Gets the details of a Subscription.
  rpc GetSubscription(GetSubscriptionRequest) returns (Subscription) {
    option (google.api.http) = {
      get: "/v1/{name=projects/*/locations/*/subscriptions/*}"
    };
    option (google.api.method_signature) = "name";
  }

  // Lists all subscriptions in a given project and location.
  rpc ListSubscriptions(ListSubscriptionsRequest)
      returns (ListSubscriptionsResponse) {
    option (google.api.http) = {
      get: "/v1/{parent=projects/*/locations/*}/subscriptions"
    };
    option (google.api.method_signature) = "parent";
  }

  // Lists all subscriptions on a given Data Exchange or Listing.
  rpc ListSharedResourceSubscriptions(ListSharedResourceSubscriptionsRequest)
      returns (ListSharedResourceSubscriptionsResponse) {
    option (google.api.http) = {
      get: "/v1/{resource=projects/*/locations/*/dataExchanges/*}:listSubscriptions"
      additional_bindings {
        get: "/v1/{resource=projects/*/locations/*/dataExchanges/*/listings/*}:listSubscriptions"
      }
    };
    option (google.api.method_signature) = "resource";
  }

  // Revokes a given subscription.
  rpc RevokeSubscription(RevokeSubscriptionRequest)
      returns (RevokeSubscriptionResponse) {
    option (google.api.http) = {
      post: "/v1/{name=projects/*/locations/*/subscriptions/*}:revoke"
      body: "*"
    };
    option (google.api.method_signature) = "name";
  }

  // Deletes a subscription.
  rpc DeleteSubscription(DeleteSubscriptionRequest)
      returns (google.longrunning.Operation) {
    option (google.api.http) = {
      delete: "/v1/{name=projects/*/locations/*/subscriptions/*}"
    };
    option (google.api.method_signature) = "name";
    option (google.longrunning.operation_info) = {
      response_type: "google.protobuf.Empty"
      metadata_type: "OperationMetadata"
    };
  }

  // Gets the IAM policy.
  rpc GetIamPolicy(google.iam.v1.GetIamPolicyRequest)
      returns (google.iam.v1.Policy) {
    option (google.api.http) = {
      post: "/v1/{resource=projects/*/locations/*/dataExchanges/*}:getIamPolicy"
      body: "*"
      additional_bindings {
        post: "/v1/{resource=projects/*/locations/*/dataExchanges/*/listings/*}:getIamPolicy"
        body: "*"
      }
      additional_bindings {
        post: "/v1/{resource=projects/*/locations/*/subscriptions/*}:getIamPolicy"
        body: "*"
      }
    };
  }

  // Sets the IAM policy.
  rpc SetIamPolicy(google.iam.v1.SetIamPolicyRequest)
      returns (google.iam.v1.Policy) {
    option (google.api.http) = {
      post: "/v1/{resource=projects/*/locations/*/dataExchanges/*}:setIamPolicy"
      body: "*"
      additional_bindings {
        post: "/v1/{resource=projects/*/locations/*/dataExchanges/*/listings/*}:setIamPolicy"
        body: "*"
      }
      additional_bindings {
        post: "/v1/{resource=projects/*/locations/*/subscriptions/*}:setIamPolicy"
        body: "*"
      }
    };
  }

  // Returns the permissions that a caller has.
  rpc TestIamPermissions(google.iam.v1.TestIamPermissionsRequest)
      returns (google.iam.v1.TestIamPermissionsResponse) {
    option (google.api.http) = {
      post: "/v1/{resource=projects/*/locations/*/dataExchanges/*}:testIamPermissions"
      body: "*"
      additional_bindings {
        post: "/v1/{resource=projects/*/locations/*/dataExchanges/*/listings/*}:testIamPermissions"
        body: "*"
      }
    };
  }
}

// Specifies the type of discovery on the discovery page. Note that
// this does not control the visibility of the exchange/listing which is
// defined by IAM permission.
enum DiscoveryType {
  // Unspecified. Defaults to DISCOVERY_TYPE_PRIVATE.
  DISCOVERY_TYPE_UNSPECIFIED = 0;

  // The Data exchange/listing can be discovered in the 'Private' results
  // list.
  DISCOVERY_TYPE_PRIVATE = 1;

  // The Data exchange/listing can be discovered in the 'Public' results
  // list.
  DISCOVERY_TYPE_PUBLIC = 2;
}

// The underlying shared asset type shared in a listing by a publisher.
enum SharedResourceType {
  // Not specified.
  SHARED_RESOURCE_TYPE_UNSPECIFIED = 0;

  // BigQuery Dataset Asset.
  BIGQUERY_DATASET = 1;

  // Pub/Sub Topic Asset.
  PUBSUB_TOPIC = 2;
}

// A data exchange is a container that lets you share data. Along with the
// descriptive information about the data exchange, it contains listings that
// reference shared datasets.
message DataExchange {
  option (google.api.resource) = {
    type: "analyticshub.googleapis.com/DataExchange"
    pattern: "projects/{project}/locations/{location}/dataExchanges/{data_exchange}"
  };

  // Output only. The resource name of the data exchange.
  // e.g. `projects/myproject/locations/us/dataExchanges/123`.
  string name = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Required. Human-readable display name of the data exchange. The display
  // name must contain only Unicode letters, numbers (0-9), underscores (_),
  // dashes (-), spaces ( ), ampersands (&) and must not start or end with
  // spaces. Default value is an empty string. Max length: 63 bytes.
  string display_name = 2 [(google.api.field_behavior) = REQUIRED];

  // Optional. Description of the data exchange. The description must not
  // contain Unicode non-characters as well as C0 and C1 control codes except
  // tabs (HT), new lines (LF), carriage returns (CR), and page breaks (FF).
  // Default value is an empty string.
  // Max length: 2000 bytes.
  string description = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Email or URL of the primary point of contact of the data
  // exchange. Max Length: 1000 bytes.
  string primary_contact = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Documentation describing the data exchange.
  string documentation = 5 [(google.api.field_behavior) = OPTIONAL];

  // Output only. Number of listings contained in the data exchange.
  int32 listing_count = 6 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. Base64 encoded image representing the data exchange. Max
  // Size: 3.0MiB Expected image dimensions are 512x512 pixels, however the API
  // only performs validation on size of the encoded data. Note: For byte
  // fields, the content of the fields are base64-encoded (which increases the
  // size of the data by 33-36%) when using JSON on the wire.
  bytes icon = 7 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Configurable data sharing environment option for a data exchange.
  SharingEnvironmentConfig sharing_environment_config = 8
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. Type of discovery on the discovery page for all the listings
  // under this exchange. Updating this field also updates (overwrites) the
  // discovery_type field for all the listings under this exchange.
  optional DiscoveryType discovery_type = 9
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. By default, false.
  // If true, the DataExchange has an email sharing mandate enabled.
  optional bool log_linked_dataset_query_user_email = 10
      [(google.api.field_behavior) = OPTIONAL];
}

// Sharing environment is a behavior model for sharing data within a
// data exchange. This option is configurable for a data exchange.
message SharingEnvironmentConfig {
  // Default Analytics Hub data exchange, used for secured data sharing.
  message DefaultExchangeConfig {}

  // Data Clean Room (DCR), used for privacy-safe and secured data sharing.
  message DcrExchangeConfig {
    // Output only. If True, this DCR restricts the contributors to sharing
    // only a single resource in a Listing. And no two resources should have the
    // same IDs. So if a contributor adds a view with a conflicting name, the
    // CreateListing API will reject the request. if False, the data contributor
    // can publish an entire dataset (as before). This is not configurable, and
    // by default, all new DCRs will have the restriction set to True.
    optional bool single_selected_resource_sharing_restriction = 1
        [(google.api.field_behavior) = OUTPUT_ONLY];

    // Output only. If True, when subscribing to this DCR, it will create only
    // one linked dataset containing all resources shared within the
    // cleanroom. If False, when subscribing to this DCR, it will
    // create 1 linked dataset per listing. This is not configurable, and by
    // default, all new DCRs will have the restriction set to True.
    optional bool single_linked_dataset_per_cleanroom = 2
        [(google.api.field_behavior) = OUTPUT_ONLY];
  }

  oneof environment {
    // Default Analytics Hub data exchange, used for secured data sharing.
    DefaultExchangeConfig default_exchange_config = 1;

    // Data Clean Room (DCR), used for privacy-safe and secured data sharing.
    DcrExchangeConfig dcr_exchange_config = 2;
  }
}

// Contains details of the data provider.
message DataProvider {
  // Optional. Name of the data provider.
  string name = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Email or URL of the data provider.
  // Max Length: 1000 bytes.
  string primary_contact = 2 [(google.api.field_behavior) = OPTIONAL];
}

// Contains details of the listing publisher.
message Publisher {
  // Optional. Name of the listing publisher.
  string name = 1 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Email or URL of the listing publisher.
  // Max Length: 1000 bytes.
  string primary_contact = 2 [(google.api.field_behavior) = OPTIONAL];
}

message DestinationDatasetReference {
  // Required. A unique ID for this dataset, without the project name. The ID
  // must contain only letters (a-z, A-Z), numbers (0-9), or underscores (_).
  // The maximum length is 1,024 characters.
  string dataset_id = 1 [(google.api.field_behavior) = REQUIRED];

  // Required. The ID of the project containing this dataset.
  string project_id = 2 [(google.api.field_behavior) = REQUIRED];
}

// Defines the destination bigquery dataset.
message DestinationDataset {
  // Required. A reference that identifies the destination dataset.
  DestinationDatasetReference dataset_reference = 1
      [(google.api.field_behavior) = REQUIRED];

  // Optional. A descriptive name for the dataset.
  google.protobuf.StringValue friendly_name = 2
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. A user-friendly description of the dataset.
  google.protobuf.StringValue description = 3
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. The labels associated with this dataset. You can use these
  // to organize and group your datasets.
  // You can set this property when inserting or updating a dataset.
  // See https://cloud.google.com/resource-manager/docs/creating-managing-labels
  // for more information.
  map<string, string> labels = 4 [(google.api.field_behavior) = OPTIONAL];

  // Required. The geographic location where the dataset should reside. See
  // https://cloud.google.com/bigquery/docs/locations for supported
  // locations.
  string location = 5 [(google.api.field_behavior) = REQUIRED];
}

// Defines the destination Pub/Sub subscription.
message DestinationPubSubSubscription {
  // Required. Destination Pub/Sub subscription resource.
  PubSubSubscription pubsub_subscription = 1
      [(google.api.field_behavior) = REQUIRED];
}

// A listing is what gets published into a data exchange that a subscriber can
// subscribe to. It contains a reference to the data source along with
// descriptive information that will help subscribers find and subscribe the
// data.
message Listing {
  option (google.api.resource) = {
    type: "analyticshub.googleapis.com/Listing"
    pattern: "projects/{project}/locations/{location}/dataExchanges/{data_exchange}/listings/{listing}"
  };

  // A reference to a shared dataset. It is an existing BigQuery dataset with a
  // collection of objects such as tables and views that you want to share
  // with subscribers.
  // When subscriber's subscribe to a listing, Analytics Hub creates a linked
  // dataset in
  // the subscriber's project. A Linked dataset is an opaque, read-only BigQuery
  // dataset that serves as a _symbolic link_ to a shared dataset.
  message BigQueryDatasetSource {
    // Resource in this dataset that is selectively shared.
    message SelectedResource {
      oneof resource {
        // Optional. Format:
        // For table:
        // `projects/{projectId}/datasets/{datasetId}/tables/{tableId}`
        // Example:"projects/test_project/datasets/test_dataset/tables/test_table"
        string table = 1 [
          (google.api.field_behavior) = OPTIONAL,
          (google.api.resource_reference) = {
            type: "bigquery.googleapis.com/Table"
          }
        ];

        // Optional. Format:
        // For routine:
        // `projects/{projectId}/datasets/{datasetId}/routines/{routineId}`
        // Example:"projects/test_project/datasets/test_dataset/routines/test_routine"
        string routine = 2 [
          (google.api.field_behavior) = OPTIONAL,
          (google.api.resource_reference) = {
            type: "bigquery.googleapis.com/Routine"
          }
        ];
      }
    }

    // Restricted export policy used to configure restricted export on linked
    // dataset.
    message RestrictedExportPolicy {
      // Optional. If true, enable restricted export.
      google.protobuf.BoolValue enabled = 1
          [(google.api.field_behavior) = OPTIONAL];

      // Optional. If true, restrict direct table access (read
      // api/tabledata.list) on linked table.
      google.protobuf.BoolValue restrict_direct_table_access = 2
          [(google.api.field_behavior) = OPTIONAL];

      // Optional. If true, restrict export of query result derived from
      // restricted linked dataset table.
      google.protobuf.BoolValue restrict_query_result = 3
          [(google.api.field_behavior) = OPTIONAL];
    }

    // Optional. Resource name of the dataset source for this listing.
    // e.g. `projects/myproject/datasets/123`
    string dataset = 1 [
      (google.api.field_behavior) = OPTIONAL,
      (google.api.resource_reference) = {
        type: "bigquery.googleapis.com/Dataset"
      }
    ];

    // Optional. Resource in this dataset that is selectively shared.
    // This field is required for data clean room exchanges.
    repeated SelectedResource selected_resources = 2
        [(google.api.field_behavior) = OPTIONAL];

    // Optional. If set, restricted export policy will be propagated and
    // enforced on the linked dataset.
    RestrictedExportPolicy restricted_export_policy = 3
        [(google.api.field_behavior) = OPTIONAL];
  }

  // Pub/Sub topic source.
  message PubSubTopicSource {
    // Required. Resource name of the Pub/Sub topic source for this listing.
    // e.g. projects/myproject/topics/topicId
    string topic = 1 [
      (google.api.field_behavior) = REQUIRED,
      (google.api.resource_reference) = { type: "pubsub.googleapis.com/Topic" }
    ];

    // Optional. Region hint on where the data might be published. Data affinity
    // regions are modifiable. See https://cloud.google.com/about/locations for
    // full listing of possible Cloud regions.
    repeated string data_affinity_regions = 2
        [(google.api.field_behavior) = OPTIONAL];
  }

  // Restricted export config, used to configure restricted export on linked
  // dataset.
  message RestrictedExportConfig {
    // Optional. If true, enable restricted export.
    bool enabled = 3 [(google.api.field_behavior) = OPTIONAL];

    // Output only. If true, restrict direct table access(read
    // api/tabledata.list) on linked table.
    bool restrict_direct_table_access = 1
        [(google.api.field_behavior) = OUTPUT_ONLY];

    // Optional. If true, restrict export of query result derived from
    // restricted linked dataset table.
    bool restrict_query_result = 2 [(google.api.field_behavior) = OPTIONAL];
  }

  // Commercial info contains the information about the commercial data products
  // associated with the listing.
  message CommercialInfo {
    // Specifies the details of the Marketplace Data Product associated with the
    // Listing.
    message GoogleCloudMarketplaceInfo {
      // Indicates whether this commercial access is currently active.
      enum CommercialState {
        // Commercialization is incomplete and cannot be used.
        COMMERCIAL_STATE_UNSPECIFIED = 0;

        // Commercialization has been initialized.
        ONBOARDING = 1;

        // Commercialization is complete and available for use.
        ACTIVE = 2;
      }

      // Output only. Resource name of the commercial service associated with
      // the Marketplace Data Product. e.g. example.com
      optional string service = 1 [
        (google.api.field_behavior) = OUTPUT_ONLY,
        (google.api.resource_reference) = {
          type: "servicemanagement.googleapis.com/ManagedService"
        }
      ];

      // Output only. Commercial state of the Marketplace Data Product.
      optional CommercialState commercial_state = 3
          [(google.api.field_behavior) = OUTPUT_ONLY];
    }

    // Output only. Details of the Marketplace Data Product associated with the
    // Listing.
    optional GoogleCloudMarketplaceInfo cloud_marketplace = 1
        [(google.api.field_behavior) = OUTPUT_ONLY];
  }

  // State of the listing.
  enum State {
    // Default value. This value is unused.
    STATE_UNSPECIFIED = 0;

    // Subscribable state. Users with dataexchange.listings.subscribe permission
    // can subscribe to this listing.
    ACTIVE = 1;
  }

  // Listing categories.
  enum Category {
    CATEGORY_UNSPECIFIED = 0;

    CATEGORY_OTHERS = 1;

    CATEGORY_ADVERTISING_AND_MARKETING = 2;

    CATEGORY_COMMERCE = 3;

    CATEGORY_CLIMATE_AND_ENVIRONMENT = 4;

    CATEGORY_DEMOGRAPHICS = 5;

    CATEGORY_ECONOMICS = 6;

    CATEGORY_EDUCATION = 7;

    CATEGORY_ENERGY = 8;

    CATEGORY_FINANCIAL = 9;

    CATEGORY_GAMING = 10;

    CATEGORY_GEOSPATIAL = 11;

    CATEGORY_HEALTHCARE_AND_LIFE_SCIENCE = 12;

    CATEGORY_MEDIA = 13;

    CATEGORY_PUBLIC_SECTOR = 14;

    CATEGORY_RETAIL = 15;

    CATEGORY_SPORTS = 16;

    CATEGORY_SCIENCE_AND_RESEARCH = 17;

    CATEGORY_TRANSPORTATION_AND_LOGISTICS = 18;

    CATEGORY_TRAVEL_AND_TOURISM = 19;
  }

  // Listing source.
  oneof source {
    // Shared dataset i.e. BigQuery dataset source.
    BigQueryDatasetSource bigquery_dataset = 6;

    // Pub/Sub topic source.
    PubSubTopicSource pubsub_topic = 16;
  }

  // Output only. The resource name of the listing.
  // e.g. `projects/myproject/locations/us/dataExchanges/123/listings/456`
  string name = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Required. Human-readable display name of the listing. The display name must
  // contain only Unicode letters, numbers (0-9), underscores (_), dashes (-),
  // spaces ( ), ampersands (&) and can't start or end with spaces. Default
  // value is an empty string. Max length: 63 bytes.
  string display_name = 2 [(google.api.field_behavior) = REQUIRED];

  // Optional. Short description of the listing. The description must not
  // contain Unicode non-characters and C0 and C1 control codes except tabs
  // (HT), new lines (LF), carriage returns (CR), and page breaks (FF). Default
  // value is an empty string. Max length: 2000 bytes.
  string description = 3 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Email or URL of the primary point of contact of the listing.
  // Max Length: 1000 bytes.
  string primary_contact = 4 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Documentation describing the listing.
  string documentation = 5 [(google.api.field_behavior) = OPTIONAL];

  // Output only. Current state of the listing.
  State state = 7 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. Base64 encoded image representing the listing. Max Size: 3.0MiB
  // Expected image dimensions are 512x512 pixels, however the API only
  // performs validation on size of the encoded data.
  // Note: For byte fields, the contents of the field are base64-encoded (which
  // increases the size of the data by 33-36%) when using JSON on the wire.
  bytes icon = 8 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Details of the data provider who owns the source data.
  DataProvider data_provider = 9 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Categories of the listing. Up to two categories are allowed.
  repeated Category categories = 10 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Details of the publisher who owns the listing and who can share
  // the source data.
  Publisher publisher = 11 [(google.api.field_behavior) = OPTIONAL];

  // Optional. Email or URL of the request access of the listing.
  // Subscribers can use this reference to request access.
  // Max Length: 1000 bytes.
  string request_access = 12 [(google.api.field_behavior) = OPTIONAL];

  // Optional. If set, restricted export configuration will be propagated and
  // enforced on the linked dataset.
  RestrictedExportConfig restricted_export_config = 13
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. Type of discovery of the listing on the discovery page.
  optional DiscoveryType discovery_type = 14
      [(google.api.field_behavior) = OPTIONAL];

  // Output only. Listing shared asset type.
  SharedResourceType resource_type = 15
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Commercial info contains the information about the commercial
  // data products associated with the listing.
  optional CommercialInfo commercial_info = 17
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. By default, false.
  // If true, the Listing has an email sharing mandate enabled.
  optional bool log_linked_dataset_query_user_email = 18
      [(google.api.field_behavior) = OPTIONAL];

  // Optional. If true, the listing is only available to get the resource
  // metadata. Listing is non subscribable.
  optional bool allow_only_metadata_sharing = 19
      [(google.api.field_behavior) = OPTIONAL];
}

// A subscription represents a subscribers' access to a particular set of
// published data. It contains references to associated listings,
// data exchanges, and linked datasets.
message Subscription {
  option (google.api.resource) = {
    type: "analyticshub.googleapis.com/Subscription"
    pattern: "projects/{project}/locations/{location}/subscriptions/{subscription}"
  };

  // Reference to a linked resource tracked by this Subscription.
  message LinkedResource {
    oneof reference {
      // Output only. Name of the linked dataset, e.g.
      // projects/subscriberproject/datasets/linked_dataset
      string linked_dataset = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

      // Output only. Name of the Pub/Sub subscription, e.g.
      // projects/subscriberproject/subscriptions/subscriptions/sub_id
      string linked_pubsub_subscription = 3
          [(google.api.field_behavior) = OUTPUT_ONLY];
    }

    // Output only. Listing for which linked resource is created.
    string listing = 2 [(google.api.field_behavior) = OUTPUT_ONLY];
  }

  // Commercial info metadata for this subscription.
  message CommercialInfo {
    // Cloud Marketplace commercial metadata for this subscription.
    message GoogleCloudMarketplaceInfo {
      // Resource name of the Marketplace Order.
      string order = 1 [(google.api.resource_reference) = {
        type: "cloudcommerceconsumerprocurement.googleapis.com/Order"
      }];
    }

    // Output only. This is set when the subscription is commercialised via
    // Cloud Marketplace.
    GoogleCloudMarketplaceInfo cloud_marketplace = 1
        [(google.api.field_behavior) = OUTPUT_ONLY];
  }

  // State of the subscription.
  enum State {
    // Default value. This value is unused.
    STATE_UNSPECIFIED = 0;

    // This subscription is active and the data is accessible.
    STATE_ACTIVE = 1;

    // The data referenced by this subscription is out of date and should be
    // refreshed. This can happen when a data provider adds or removes datasets.
    STATE_STALE = 2;

    // This subscription has been cancelled or revoked and the data is no longer
    // accessible.
    STATE_INACTIVE = 3;
  }

  oneof resource_name {
    // Output only. Resource name of the source Listing.
    // e.g. projects/123/locations/us/dataExchanges/456/listings/789
    string listing = 5 [(google.api.field_behavior) = OUTPUT_ONLY];

    // Output only. Resource name of the source Data Exchange.
    // e.g. projects/123/locations/us/dataExchanges/456
    string data_exchange = 6 [(google.api.field_behavior) = OUTPUT_ONLY];
  }

  // Output only. The resource name of the subscription.
  // e.g. `projects/myproject/locations/us/subscriptions/123`.
  string name = 1 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Timestamp when the subscription was created.
  google.protobuf.Timestamp creation_time = 2
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Timestamp when the subscription was last modified.
  google.protobuf.Timestamp last_modify_time = 3
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Organization of the project this subscription belongs to.
  string organization_id = 4 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Display name of the project of this subscription.
  string organization_display_name = 10
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Current state of the subscription.
  State state = 7 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Map of listing resource names to associated linked resource,
  // e.g. projects/123/locations/us/dataExchanges/456/listings/789
  // ->
  // projects/123/datasets/my_dataset
  //
  // For listing-level subscriptions, this is a map of size 1.
  // Only contains values if state == STATE_ACTIVE.
  map<string, LinkedResource> linked_dataset_map = 8
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Email of the subscriber.
  string subscriber_contact = 9 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Linked resources created in the subscription. Only contains
  // values if state = STATE_ACTIVE.
  repeated LinkedResource linked_resources = 11
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Listing shared asset type.
  SharedResourceType resource_type = 12
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. This is set if this is a commercial subscription i.e. if this
  // subscription was created from subscribing to a commercial listing.
  CommercialInfo commercial_info = 13
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. By default, false.
  // If true, the Subscriber agreed to the email sharing mandate
  // that is enabled for DataExchange/Listing.
  optional bool log_linked_dataset_query_user_email = 14
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Optional. BigQuery destination dataset to create for the subscriber.
  DestinationDataset destination_dataset = 15
      [(google.api.field_behavior) = OPTIONAL];
}

// Message for requesting the list of data exchanges.
message ListDataExchangesRequest {
  // Required. The parent resource path of the data exchanges.
  // e.g. `projects/myproject/locations/us`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "analyticshub.googleapis.com/DataExchange"
    }
  ];

  // The maximum number of results to return in a single response page. Leverage
  // the page tokens to iterate through the entire collection.
  int32 page_size = 2;

  // Page token, returned by a previous call, to request the next page of
  // results.
  string page_token = 3;
}

// Message for response to the list of data exchanges.
message ListDataExchangesResponse {
  // The list of data exchanges.
  repeated DataExchange data_exchanges = 1;

  // A token to request the next page of results.
  string next_page_token = 2;
}

// Message for requesting the list of data exchanges from projects in an
// organization and location.
message ListOrgDataExchangesRequest {
  // Required. The organization resource path of the projects containing
  // DataExchanges. e.g. `organizations/myorg/locations/us`.
  string organization = 1 [(google.api.field_behavior) = REQUIRED];

  // The maximum number of results to return in a single response page. Leverage
  // the page tokens to iterate through the entire collection.
  int32 page_size = 2;

  // Page token, returned by a previous call, to request the next page of
  // results.
  string page_token = 3;
}

// Message for response to listing data exchanges in an organization and
// location.
message ListOrgDataExchangesResponse {
  // The list of data exchanges.
  repeated DataExchange data_exchanges = 1;

  // A token to request the next page of results.
  string next_page_token = 2;
}

// Message for getting a data exchange.
message GetDataExchangeRequest {
  // Required. The resource name of the data exchange.
  // e.g. `projects/myproject/locations/us/dataExchanges/123`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "analyticshub.googleapis.com/DataExchange"
    }
  ];
}

// Message for creating a data exchange.
message CreateDataExchangeRequest {
  // Required. The parent resource path of the data exchange.
  // e.g. `projects/myproject/locations/us`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "analyticshub.googleapis.com/DataExchange"
    }
  ];

  // Required. The ID of the data exchange.
  // Must contain only Unicode letters, numbers (0-9), underscores (_).
  // Max length: 100 bytes.
  string data_exchange_id = 2 [(google.api.field_behavior) = REQUIRED];

  // Required. The data exchange to create.
  DataExchange data_exchange = 3 [(google.api.field_behavior) = REQUIRED];
}

// Message for updating a data exchange.
message UpdateDataExchangeRequest {
  // Required. Field mask specifies the fields to update in the data exchange
  // resource. The fields specified in the
  // `updateMask` are relative to the resource and are not a full request.
  google.protobuf.FieldMask update_mask = 1
      [(google.api.field_behavior) = REQUIRED];

  // Required. The data exchange to update.
  DataExchange data_exchange = 2 [(google.api.field_behavior) = REQUIRED];
}

// Message for deleting a data exchange.
message DeleteDataExchangeRequest {
  // Required. The full name of the data exchange resource that you want to
  // delete. For example, `projects/myproject/locations/us/dataExchanges/123`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "analyticshub.googleapis.com/DataExchange"
    }
  ];
}

// Message for requesting the list of listings.
message ListListingsRequest {
  // Required. The parent resource path of the listing.
  // e.g. `projects/myproject/locations/us/dataExchanges/123`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "analyticshub.googleapis.com/DataExchange"
    }
  ];

  // The maximum number of results to return in a single response page. Leverage
  // the page tokens to iterate through the entire collection.
  int32 page_size = 2;

  // Page token, returned by a previous call, to request the next page of
  // results.
  string page_token = 3;
}

// Message for response to the list of Listings.
message ListListingsResponse {
  // The list of Listing.
  repeated Listing listings = 1;

  // A token to request the next page of results.
  string next_page_token = 2;
}

// Message for getting a listing.
message GetListingRequest {
  // Required. The resource name of the listing.
  // e.g. `projects/myproject/locations/us/dataExchanges/123/listings/456`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "analyticshub.googleapis.com/Listing"
    }
  ];
}

// Message for creating a listing.
message CreateListingRequest {
  // Required. The parent resource path of the listing.
  // e.g. `projects/myproject/locations/us/dataExchanges/123`.
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "analyticshub.googleapis.com/DataExchange"
    }
  ];

  // Required. The ID of the listing to create.
  // Must contain only Unicode letters, numbers (0-9), underscores (_).
  // Max length: 100 bytes.
  string listing_id = 2 [(google.api.field_behavior) = REQUIRED];

  // Required. The listing to create.
  Listing listing = 3 [(google.api.field_behavior) = REQUIRED];
}

// Message for updating a Listing.
message UpdateListingRequest {
  // Required. Field mask specifies the fields to update in the listing
  // resource. The fields specified in the `updateMask` are relative to the
  // resource and are not a full request.
  google.protobuf.FieldMask update_mask = 1
      [(google.api.field_behavior) = REQUIRED];

  // Required. The listing to update.
  Listing listing = 2 [(google.api.field_behavior) = REQUIRED];
}

// Message for deleting a listing.
message DeleteListingRequest {
  // Required. Resource name of the listing to delete.
  // e.g. `projects/myproject/locations/us/dataExchanges/123/listings/456`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "analyticshub.googleapis.com/Listing"
    }
  ];

  // Optional. If the listing is commercial then this field must be set to true,
  // otherwise a failure is thrown. This acts as a safety guard to avoid
  // deleting commercial listings accidentally.
  bool delete_commercial = 2 [(google.api.field_behavior) = OPTIONAL];
}

// Message for subscribing to a listing.
message SubscribeListingRequest {
  // Resulting destination of the listing that you subscribed to.
  oneof destination {
    // Input only. BigQuery destination dataset to create for the subscriber.
    DestinationDataset destination_dataset = 3
        [(google.api.field_behavior) = INPUT_ONLY];

    // Input only. Destination Pub/Sub subscription to create for the
    // subscriber.
    DestinationPubSubSubscription destination_pubsub_subscription = 5
        [(google.api.field_behavior) = INPUT_ONLY];
  }

  // Required. Resource name of the listing that you want to subscribe to.
  // e.g. `projects/myproject/locations/us/dataExchanges/123/listings/456`.
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "analyticshub.googleapis.com/Listing"
    }
  ];
}

// Message for response when you subscribe to a listing.
message SubscribeListingResponse {
  // Subscription object created from this subscribe action.
  Subscription subscription = 1;
}

// Message for subscribing to a Data Exchange.
message SubscribeDataExchangeRequest {
  // Required. Resource name of the Data Exchange.
  // e.g. `projects/publisherproject/locations/us/dataExchanges/123`
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "analyticshub.googleapis.com/DataExchange"
    }
  ];

  // Required. The parent resource path of the Subscription.
  // e.g. `projects/subscriberproject/locations/us`
  string destination = 2 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "locations.googleapis.com/Location"
    }
  ];

  // Optional. BigQuery destination dataset to create for the subscriber.
  DestinationDataset destination_dataset = 5
      [(google.api.field_behavior) = OPTIONAL];

  // Required. Name of the subscription to create.
  // e.g. `subscription1`
  string subscription = 4 [(google.api.field_behavior) = REQUIRED];

  // Email of the subscriber.
  string subscriber_contact = 3;
}

// Message for response when you subscribe to a Data Exchange.
message SubscribeDataExchangeResponse {
  // Subscription object created from this subscribe action.
  Subscription subscription = 1;
}

// Message for refreshing a subscription.
message RefreshSubscriptionRequest {
  // Required. Resource name of the Subscription to refresh.
  // e.g. `projects/subscriberproject/locations/us/subscriptions/123`
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "analyticshub.googleapis.com/Subscription"
    }
  ];
}

// Message for response when you refresh a subscription.
message RefreshSubscriptionResponse {
  // The refreshed subscription resource.
  Subscription subscription = 1;
}

// Message for getting a subscription.
message GetSubscriptionRequest {
  // Required. Resource name of the subscription.
  // e.g. projects/123/locations/us/subscriptions/456
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "analyticshub.googleapis.com/Subscription"
    }
  ];
}

// Message for listing subscriptions.
message ListSubscriptionsRequest {
  // Required. The parent resource path of the subscription.
  // e.g. projects/myproject/locations/us
  string parent = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      child_type: "analyticshub.googleapis.com/Subscription"
    }
  ];

  // An expression for filtering the results of the request. Eligible
  // fields for filtering are:
  //
  //  + `listing`
  //  + `data_exchange`
  //
  // Alternatively, a literal wrapped in double quotes may be provided.
  // This will be checked for an exact match against both fields above.
  //
  // In all cases, the full Data Exchange or Listing resource name must
  // be provided. Some example of using filters:
  //
  //  + data_exchange="projects/myproject/locations/us/dataExchanges/123"
  //  + listing="projects/123/locations/us/dataExchanges/456/listings/789"
  //  + "projects/myproject/locations/us/dataExchanges/123"
  string filter = 2;

  // The maximum number of results to return in a single response page.
  int32 page_size = 3;

  // Page token, returned by a previous call.
  string page_token = 4;
}

// Message for response to the listing of subscriptions.
message ListSubscriptionsResponse {
  // The list of subscriptions.
  repeated Subscription subscriptions = 1;

  // Next page token.
  string next_page_token = 2;
}

// Message for listing subscriptions of a shared resource.
message ListSharedResourceSubscriptionsRequest {
  // Required. Resource name of the requested target. This resource may be
  // either a Listing or a DataExchange. e.g.
  // projects/123/locations/us/dataExchanges/456 OR e.g.
  // projects/123/locations/us/dataExchanges/456/listings/789
  string resource = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = { type: "*" }
  ];

  // If selected, includes deleted subscriptions in the response
  // (up to 63 days after deletion).
  bool include_deleted_subscriptions = 2;

  // The maximum number of results to return in a single response page.
  int32 page_size = 3;

  // Page token, returned by a previous call.
  string page_token = 4;
}

// Message for response to the listing of shared resource subscriptions.
message ListSharedResourceSubscriptionsResponse {
  // The list of subscriptions.
  repeated Subscription shared_resource_subscriptions = 1;

  // Next page token.
  string next_page_token = 2;
}

// Message for revoking a subscription.
message RevokeSubscriptionRequest {
  // Required. Resource name of the subscription to revoke.
  // e.g. projects/123/locations/us/subscriptions/456
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "analyticshub.googleapis.com/Subscription"
    }
  ];

  // Optional. If the subscription is commercial then this field must be set to
  // true, otherwise a failure is thrown. This acts as a safety guard to avoid
  // revoking commercial subscriptions accidentally.
  bool revoke_commercial = 2 [(google.api.field_behavior) = OPTIONAL];
}

// Message for response when you revoke a subscription.
// Empty for now.
message RevokeSubscriptionResponse {}

// Message for deleting a subscription.
message DeleteSubscriptionRequest {
  // Required. Resource name of the subscription to delete.
  // e.g. projects/123/locations/us/subscriptions/456
  string name = 1 [
    (google.api.field_behavior) = REQUIRED,
    (google.api.resource_reference) = {
      type: "analyticshub.googleapis.com/Subscription"
    }
  ];
}

// Represents the metadata of a long-running operation in Analytics Hub.
message OperationMetadata {
  // Output only. The time the operation was created.
  google.protobuf.Timestamp create_time = 1
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. The time the operation finished running.
  google.protobuf.Timestamp end_time = 2
      [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Server-defined resource path for the target of the operation.
  string target = 3 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Name of the verb executed by the operation.
  string verb = 4 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Human-readable status of the operation, if any.
  string status_message = 5 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. Identifies whether the user has requested cancellation
  // of the operation. Operations that have successfully been cancelled
  // have [Operation.error][] value with a
  // [google.rpc.Status.code][google.rpc.Status.code] of 1, corresponding to
  // `Code.CANCELLED`.
  bool requested_cancellation = 6 [(google.api.field_behavior) = OUTPUT_ONLY];

  // Output only. API version used to start the operation.
  string api_version = 7 [(google.api.field_behavior) = OUTPUT_ONLY];
}
