add a script to update the vendored protos (#1004)

diff --git a/protoc_plugin/lib/src/gen/google/api/routing.pb.dart b/protoc_plugin/lib/src/gen/google/api/routing.pb.dart
new file mode 100644
index 0000000..5ce422e
--- /dev/null
+++ b/protoc_plugin/lib/src/gen/google/api/routing.pb.dart
@@ -0,0 +1,577 @@
+//
+//  Generated code. Do not modify.
+//  source: google/api/routing.proto
+//
+// @dart = 3.3
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
+
+import 'dart:core' as $core;
+
+import 'package:protobuf/protobuf.dart' as $pb;
+
+export 'package:protobuf/protobuf.dart' show GeneratedMessageGenericExtensions;
+
+/// Specifies the routing information that should be sent along with the request
+/// in the form of routing header.
+/// **NOTE:** All service configuration rules follow the "last one wins" order.
+///
+/// The examples below will apply to an RPC which has the following request type:
+///
+/// Message Definition:
+///
+///     message Request {
+///       // The name of the Table
+///       // Values can be of the following formats:
+///       // - `projects/<project>/tables/<table>`
+///       // - `projects/<project>/instances/<instance>/tables/<table>`
+///       // - `region/<region>/zones/<zone>/tables/<table>`
+///       string table_name = 1;
+///
+///       // This value specifies routing for replication.
+///       // It can be in the following formats:
+///       // - `profiles/<profile_id>`
+///       // - a legacy `profile_id` that can be any string
+///       string app_profile_id = 2;
+///     }
+///
+/// Example message:
+///
+///     {
+///       table_name: projects/proj_foo/instances/instance_bar/table/table_baz,
+///       app_profile_id: profiles/prof_qux
+///     }
+///
+/// The routing header consists of one or multiple key-value pairs. Every key
+/// and value must be percent-encoded, and joined together in the format of
+/// `key1=value1&key2=value2`.
+/// The examples below skip the percent-encoding for readability.
+///
+/// Example 1
+///
+/// Extracting a field from the request to put into the routing header
+/// unchanged, with the key equal to the field name.
+///
+/// annotation:
+///
+///     option (google.api.routing) = {
+///       // Take the `app_profile_id`.
+///       routing_parameters {
+///         field: "app_profile_id"
+///       }
+///     };
+///
+/// result:
+///
+///     x-goog-request-params: app_profile_id=profiles/prof_qux
+///
+/// Example 2
+///
+/// Extracting a field from the request to put into the routing header
+/// unchanged, with the key different from the field name.
+///
+/// annotation:
+///
+///     option (google.api.routing) = {
+///       // Take the `app_profile_id`, but name it `routing_id` in the header.
+///       routing_parameters {
+///         field: "app_profile_id"
+///         path_template: "{routing_id=**}"
+///       }
+///     };
+///
+/// result:
+///
+///     x-goog-request-params: routing_id=profiles/prof_qux
+///
+/// Example 3
+///
+/// Extracting a field from the request to put into the routing
+/// header, while matching a path template syntax on the field's value.
+///
+/// NB: it is more useful to send nothing than to send garbage for the purpose
+/// of dynamic routing, since garbage pollutes cache. Thus the matching.
+///
+/// Sub-example 3a
+///
+/// The field matches the template.
+///
+/// annotation:
+///
+///     option (google.api.routing) = {
+///       // Take the `table_name`, if it's well-formed (with project-based
+///       // syntax).
+///       routing_parameters {
+///         field: "table_name"
+///         path_template: "{table_name=projects/*/instances/*/**}"
+///       }
+///     };
+///
+/// result:
+///
+///     x-goog-request-params:
+///     table_name=projects/proj_foo/instances/instance_bar/table/table_baz
+///
+/// Sub-example 3b
+///
+/// The field does not match the template.
+///
+/// annotation:
+///
+///     option (google.api.routing) = {
+///       // Take the `table_name`, if it's well-formed (with region-based
+///       // syntax).
+///       routing_parameters {
+///         field: "table_name"
+///         path_template: "{table_name=regions/*/zones/*/**}"
+///       }
+///     };
+///
+/// result:
+///
+///     <no routing header will be sent>
+///
+/// Sub-example 3c
+///
+/// Multiple alternative conflictingly named path templates are
+/// specified. The one that matches is used to construct the header.
+///
+/// annotation:
+///
+///     option (google.api.routing) = {
+///       // Take the `table_name`, if it's well-formed, whether
+///       // using the region- or projects-based syntax.
+///
+///       routing_parameters {
+///         field: "table_name"
+///         path_template: "{table_name=regions/*/zones/*/**}"
+///       }
+///       routing_parameters {
+///         field: "table_name"
+///         path_template: "{table_name=projects/*/instances/*/**}"
+///       }
+///     };
+///
+/// result:
+///
+///     x-goog-request-params:
+///     table_name=projects/proj_foo/instances/instance_bar/table/table_baz
+///
+/// Example 4
+///
+/// Extracting a single routing header key-value pair by matching a
+/// template syntax on (a part of) a single request field.
+///
+/// annotation:
+///
+///     option (google.api.routing) = {
+///       // Take just the project id from the `table_name` field.
+///       routing_parameters {
+///         field: "table_name"
+///         path_template: "{routing_id=projects/*}/**"
+///       }
+///     };
+///
+/// result:
+///
+///     x-goog-request-params: routing_id=projects/proj_foo
+///
+/// Example 5
+///
+/// Extracting a single routing header key-value pair by matching
+/// several conflictingly named path templates on (parts of) a single request
+/// field. The last template to match "wins" the conflict.
+///
+/// annotation:
+///
+///     option (google.api.routing) = {
+///       // If the `table_name` does not have instances information,
+///       // take just the project id for routing.
+///       // Otherwise take project + instance.
+///
+///       routing_parameters {
+///         field: "table_name"
+///         path_template: "{routing_id=projects/*}/**"
+///       }
+///       routing_parameters {
+///         field: "table_name"
+///         path_template: "{routing_id=projects/*/instances/*}/**"
+///       }
+///     };
+///
+/// result:
+///
+///     x-goog-request-params:
+///     routing_id=projects/proj_foo/instances/instance_bar
+///
+/// Example 6
+///
+/// Extracting multiple routing header key-value pairs by matching
+/// several non-conflicting path templates on (parts of) a single request field.
+///
+/// Sub-example 6a
+///
+/// Make the templates strict, so that if the `table_name` does not
+/// have an instance information, nothing is sent.
+///
+/// annotation:
+///
+///     option (google.api.routing) = {
+///       // The routing code needs two keys instead of one composite
+///       // but works only for the tables with the "project-instance" name
+///       // syntax.
+///
+///       routing_parameters {
+///         field: "table_name"
+///         path_template: "{project_id=projects/*}/instances/*/**"
+///       }
+///       routing_parameters {
+///         field: "table_name"
+///         path_template: "projects/*/{instance_id=instances/*}/**"
+///       }
+///     };
+///
+/// result:
+///
+///     x-goog-request-params:
+///     project_id=projects/proj_foo&instance_id=instances/instance_bar
+///
+/// Sub-example 6b
+///
+/// Make the templates loose, so that if the `table_name` does not
+/// have an instance information, just the project id part is sent.
+///
+/// annotation:
+///
+///     option (google.api.routing) = {
+///       // The routing code wants two keys instead of one composite
+///       // but will work with just the `project_id` for tables without
+///       // an instance in the `table_name`.
+///
+///       routing_parameters {
+///         field: "table_name"
+///         path_template: "{project_id=projects/*}/**"
+///       }
+///       routing_parameters {
+///         field: "table_name"
+///         path_template: "projects/*/{instance_id=instances/*}/**"
+///       }
+///     };
+///
+/// result (is the same as 6a for our example message because it has the instance
+/// information):
+///
+///     x-goog-request-params:
+///     project_id=projects/proj_foo&instance_id=instances/instance_bar
+///
+/// Example 7
+///
+/// Extracting multiple routing header key-value pairs by matching
+/// several path templates on multiple request fields.
+///
+/// NB: note that here there is no way to specify sending nothing if one of the
+/// fields does not match its template. E.g. if the `table_name` is in the wrong
+/// format, the `project_id` will not be sent, but the `routing_id` will be.
+/// The backend routing code has to be aware of that and be prepared to not
+/// receive a full complement of keys if it expects multiple.
+///
+/// annotation:
+///
+///     option (google.api.routing) = {
+///       // The routing needs both `project_id` and `routing_id`
+///       // (from the `app_profile_id` field) for routing.
+///
+///       routing_parameters {
+///         field: "table_name"
+///         path_template: "{project_id=projects/*}/**"
+///       }
+///       routing_parameters {
+///         field: "app_profile_id"
+///         path_template: "{routing_id=**}"
+///       }
+///     };
+///
+/// result:
+///
+///     x-goog-request-params:
+///     project_id=projects/proj_foo&routing_id=profiles/prof_qux
+///
+/// Example 8
+///
+/// Extracting a single routing header key-value pair by matching
+/// several conflictingly named path templates on several request fields. The
+/// last template to match "wins" the conflict.
+///
+/// annotation:
+///
+///     option (google.api.routing) = {
+///       // The `routing_id` can be a project id or a region id depending on
+///       // the table name format, but only if the `app_profile_id` is not set.
+///       // If `app_profile_id` is set it should be used instead.
+///
+///       routing_parameters {
+///         field: "table_name"
+///         path_template: "{routing_id=projects/*}/**"
+///       }
+///       routing_parameters {
+///          field: "table_name"
+///          path_template: "{routing_id=regions/*}/**"
+///       }
+///       routing_parameters {
+///         field: "app_profile_id"
+///         path_template: "{routing_id=**}"
+///       }
+///     };
+///
+/// result:
+///
+///     x-goog-request-params: routing_id=profiles/prof_qux
+///
+/// Example 9
+///
+/// Bringing it all together.
+///
+/// annotation:
+///
+///     option (google.api.routing) = {
+///       // For routing both `table_location` and a `routing_id` are needed.
+///       //
+///       // table_location can be either an instance id or a region+zone id.
+///       //
+///       // For `routing_id`, take the value of `app_profile_id`
+///       // - If it's in the format `profiles/<profile_id>`, send
+///       // just the `<profile_id>` part.
+///       // - If it's any other literal, send it as is.
+///       // If the `app_profile_id` is empty, and the `table_name` starts with
+///       // the project_id, send that instead.
+///
+///       routing_parameters {
+///         field: "table_name"
+///         path_template: "projects/*/{table_location=instances/*}/tables/*"
+///       }
+///       routing_parameters {
+///         field: "table_name"
+///         path_template: "{table_location=regions/*/zones/*}/tables/*"
+///       }
+///       routing_parameters {
+///         field: "table_name"
+///         path_template: "{routing_id=projects/*}/**"
+///       }
+///       routing_parameters {
+///         field: "app_profile_id"
+///         path_template: "{routing_id=**}"
+///       }
+///       routing_parameters {
+///         field: "app_profile_id"
+///         path_template: "profiles/{routing_id=*}"
+///       }
+///     };
+///
+/// result:
+///
+///     x-goog-request-params:
+///     table_location=instances/instance_bar&routing_id=prof_qux
+class RoutingRule extends $pb.GeneratedMessage {
+  factory RoutingRule({
+    $core.Iterable<RoutingParameter>? routingParameters,
+  }) {
+    final $result = create();
+    if (routingParameters != null) {
+      $result.routingParameters.addAll(routingParameters);
+    }
+    return $result;
+  }
+  RoutingRule._() : super();
+  factory RoutingRule.fromBuffer($core.List<$core.int> i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromBuffer(i, r);
+  factory RoutingRule.fromJson($core.String i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(
+      _omitMessageNames ? '' : 'RoutingRule',
+      package: const $pb.PackageName(_omitMessageNames ? '' : 'google.api'),
+      createEmptyInstance: create)
+    ..pc<RoutingParameter>(
+        2, _omitFieldNames ? '' : 'routingParameters', $pb.PbFieldType.PM,
+        subBuilder: RoutingParameter.create)
+    ..hasRequiredFields = false;
+
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  RoutingRule clone() => RoutingRule()..mergeFromMessage(this);
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  RoutingRule copyWith(void Function(RoutingRule) updates) =>
+      super.copyWith((message) => updates(message as RoutingRule))
+          as RoutingRule;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static RoutingRule create() => RoutingRule._();
+  RoutingRule createEmptyInstance() => create();
+  static $pb.PbList<RoutingRule> createRepeated() => $pb.PbList<RoutingRule>();
+  @$core.pragma('dart2js:noInline')
+  static RoutingRule getDefault() => _defaultInstance ??=
+      $pb.GeneratedMessage.$_defaultFor<RoutingRule>(create);
+  static RoutingRule? _defaultInstance;
+
+  /// A collection of Routing Parameter specifications.
+  /// **NOTE:** If multiple Routing Parameters describe the same key
+  /// (via the `path_template` field or via the `field` field when
+  /// `path_template` is not provided), "last one wins" rule
+  /// determines which Parameter gets used.
+  /// See the examples for more details.
+  @$pb.TagNumber(2)
+  $pb.PbList<RoutingParameter> get routingParameters => $_getList(0);
+}
+
+/// A projection from an input message to the GRPC or REST header.
+class RoutingParameter extends $pb.GeneratedMessage {
+  factory RoutingParameter({
+    $core.String? field_1,
+    $core.String? pathTemplate,
+  }) {
+    final $result = create();
+    if (field_1 != null) {
+      $result.field_1 = field_1;
+    }
+    if (pathTemplate != null) {
+      $result.pathTemplate = pathTemplate;
+    }
+    return $result;
+  }
+  RoutingParameter._() : super();
+  factory RoutingParameter.fromBuffer($core.List<$core.int> i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromBuffer(i, r);
+  factory RoutingParameter.fromJson($core.String i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(
+      _omitMessageNames ? '' : 'RoutingParameter',
+      package: const $pb.PackageName(_omitMessageNames ? '' : 'google.api'),
+      createEmptyInstance: create)
+    ..aOS(1, _omitFieldNames ? '' : 'field')
+    ..aOS(2, _omitFieldNames ? '' : 'pathTemplate')
+    ..hasRequiredFields = false;
+
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  RoutingParameter clone() => RoutingParameter()..mergeFromMessage(this);
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  RoutingParameter copyWith(void Function(RoutingParameter) updates) =>
+      super.copyWith((message) => updates(message as RoutingParameter))
+          as RoutingParameter;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static RoutingParameter create() => RoutingParameter._();
+  RoutingParameter createEmptyInstance() => create();
+  static $pb.PbList<RoutingParameter> createRepeated() =>
+      $pb.PbList<RoutingParameter>();
+  @$core.pragma('dart2js:noInline')
+  static RoutingParameter getDefault() => _defaultInstance ??=
+      $pb.GeneratedMessage.$_defaultFor<RoutingParameter>(create);
+  static RoutingParameter? _defaultInstance;
+
+  /// A request field to extract the header key-value pair from.
+  @$pb.TagNumber(1)
+  $core.String get field_1 => $_getSZ(0);
+  @$pb.TagNumber(1)
+  set field_1($core.String v) {
+    $_setString(0, v);
+  }
+
+  @$pb.TagNumber(1)
+  $core.bool hasField_1() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearField_1() => $_clearField(1);
+
+  /// A pattern matching the key-value field. Optional.
+  /// If not specified, the whole field specified in the `field` field will be
+  /// taken as value, and its name used as key. If specified, it MUST contain
+  /// exactly one named segment (along with any number of unnamed segments) The
+  /// pattern will be matched over the field specified in the `field` field, then
+  /// if the match is successful:
+  /// - the name of the single named segment will be used as a header name,
+  /// - the match value of the segment will be used as a header value;
+  /// if the match is NOT successful, nothing will be sent.
+  ///
+  /// Example:
+  ///
+  ///               -- This is a field in the request message
+  ///              |   that the header value will be extracted from.
+  ///              |
+  ///              |                     -- This is the key name in the
+  ///              |                    |   routing header.
+  ///              V                    |
+  ///     field: "table_name"           v
+  ///     path_template: "projects/*/{table_location=instances/*}/tables/*"
+  ///                                                ^            ^
+  ///                                                |            |
+  ///       In the {} brackets is the pattern that --             |
+  ///       specifies what to extract from the                    |
+  ///       field as a value to be sent.                          |
+  ///                                                             |
+  ///      The string in the field must match the whole pattern --
+  ///      before brackets, inside brackets, after brackets.
+  ///
+  /// When looking at this specific example, we can see that:
+  /// - A key-value pair with the key `table_location`
+  ///   and the value matching `instances/*` should be added
+  ///   to the x-goog-request-params routing header.
+  /// - The value is extracted from the request message's `table_name` field
+  ///   if it matches the full pattern specified:
+  ///   `projects/*/instances/*/tables/*`.
+  ///
+  /// **NB:** If the `path_template` field is not provided, the key name is
+  /// equal to the field name, and the whole field should be sent as a value.
+  /// This makes the pattern for the field and the value functionally equivalent
+  /// to `**`, and the configuration
+  ///
+  ///     {
+  ///       field: "table_name"
+  ///     }
+  ///
+  /// is a functionally equivalent shorthand to:
+  ///
+  ///     {
+  ///       field: "table_name"
+  ///       path_template: "{table_name=**}"
+  ///     }
+  ///
+  /// See Example 1 for more details.
+  @$pb.TagNumber(2)
+  $core.String get pathTemplate => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set pathTemplate($core.String v) {
+    $_setString(1, v);
+  }
+
+  @$pb.TagNumber(2)
+  $core.bool hasPathTemplate() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearPathTemplate() => $_clearField(2);
+}
+
+class Routing {
+  static final routing = $pb.Extension<RoutingRule>(
+      _omitMessageNames ? '' : 'google.protobuf.MethodOptions',
+      _omitFieldNames ? '' : 'routing',
+      72295729,
+      $pb.PbFieldType.OM,
+      defaultOrMaker: RoutingRule.getDefault,
+      subBuilder: RoutingRule.create);
+  static void registerAllExtensions($pb.ExtensionRegistry registry) {
+    registry.add(routing);
+  }
+}
+
+const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
+const _omitMessageNames =
+    $core.bool.fromEnvironment('protobuf.omit_message_names');
diff --git a/protoc_plugin/lib/src/gen/google/api/routing.pbenum.dart b/protoc_plugin/lib/src/gen/google/api/routing.pbenum.dart
new file mode 100644
index 0000000..dd574e5
--- /dev/null
+++ b/protoc_plugin/lib/src/gen/google/api/routing.pbenum.dart
@@ -0,0 +1,10 @@
+//
+//  Generated code. Do not modify.
+//  source: google/api/routing.proto
+//
+// @dart = 3.3
+
+// ignore_for_file: annotate_overrides, camel_case_types, comment_references
+// ignore_for_file: constant_identifier_names, library_prefixes
+// ignore_for_file: non_constant_identifier_names, prefer_final_fields
+// ignore_for_file: unnecessary_import, unnecessary_this, unused_import
diff --git a/protoc_plugin/lib/src/gen/google/protobuf/compiler/plugin.pb.dart b/protoc_plugin/lib/src/gen/google/protobuf/compiler/plugin.pb.dart
index 07da1c3..56ccb3d 100644
--- a/protoc_plugin/lib/src/gen/google/protobuf/compiler/plugin.pb.dart
+++ b/protoc_plugin/lib/src/gen/google/protobuf/compiler/plugin.pb.dart
@@ -137,6 +137,7 @@
     $core.String? parameter,
     Version? compilerVersion,
     $core.Iterable<$2.FileDescriptorProto>? protoFile,
+    $core.Iterable<$2.FileDescriptorProto>? sourceFileDescriptors,
   }) {
     final $result = create();
     if (fileToGenerate != null) {
@@ -151,6 +152,9 @@
     if (protoFile != null) {
       $result.protoFile.addAll(protoFile);
     }
+    if (sourceFileDescriptors != null) {
+      $result.sourceFileDescriptors.addAll(sourceFileDescriptors);
+    }
     return $result;
   }
   CodeGeneratorRequest._() : super();
@@ -172,6 +176,9 @@
         subBuilder: Version.create)
     ..pc<$2.FileDescriptorProto>(
         15, _omitFieldNames ? '' : 'protoFile', $pb.PbFieldType.PM,
+        subBuilder: $2.FileDescriptorProto.create)
+    ..pc<$2.FileDescriptorProto>(
+        17, _omitFieldNames ? '' : 'sourceFileDescriptors', $pb.PbFieldType.PM,
         subBuilder: $2.FileDescriptorProto.create);
 
   @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
@@ -232,6 +239,11 @@
   /// they import.  The files will appear in topological order, so each file
   /// appears before any file that imports it.
   ///
+  /// Note: the files listed in files_to_generate will include runtime-retention
+  /// options only, but all other files will include source-retention options.
+  /// The source_file_descriptors field below is available in case you need
+  /// source-retention options for files_to_generate.
+  ///
   /// protoc guarantees that all proto_files will be written after
   /// the fields above, even though this is not technically guaranteed by the
   /// protobuf wire format.  This theoretically could allow a plugin to stream
@@ -244,6 +256,12 @@
   /// fully qualified.
   @$pb.TagNumber(15)
   $pb.PbList<$2.FileDescriptorProto> get protoFile => $_getList(3);
+
+  /// File descriptors with all options, including source-retention options.
+  /// These descriptors are only provided for the files listed in
+  /// files_to_generate.
+  @$pb.TagNumber(17)
+  $pb.PbList<$2.FileDescriptorProto> get sourceFileDescriptors => $_getList(4);
 }
 
 /// Represents a single generated file.
@@ -419,6 +437,8 @@
   factory CodeGeneratorResponse({
     $core.String? error,
     $fixnum.Int64? supportedFeatures,
+    $core.int? minimumEdition,
+    $core.int? maximumEdition,
     $core.Iterable<CodeGeneratorResponse_File>? file,
   }) {
     final $result = create();
@@ -428,6 +448,12 @@
     if (supportedFeatures != null) {
       $result.supportedFeatures = supportedFeatures;
     }
+    if (minimumEdition != null) {
+      $result.minimumEdition = minimumEdition;
+    }
+    if (maximumEdition != null) {
+      $result.maximumEdition = maximumEdition;
+    }
     if (file != null) {
       $result.file.addAll(file);
     }
@@ -450,6 +476,10 @@
     ..a<$fixnum.Int64>(
         2, _omitFieldNames ? '' : 'supportedFeatures', $pb.PbFieldType.OU6,
         defaultOrMaker: $fixnum.Int64.ZERO)
+    ..a<$core.int>(
+        3, _omitFieldNames ? '' : 'minimumEdition', $pb.PbFieldType.O3)
+    ..a<$core.int>(
+        4, _omitFieldNames ? '' : 'maximumEdition', $pb.PbFieldType.O3)
     ..pc<CodeGeneratorResponse_File>(
         15, _omitFieldNames ? '' : 'file', $pb.PbFieldType.PM,
         subBuilder: CodeGeneratorResponse_File.create)
@@ -510,8 +540,40 @@
   @$pb.TagNumber(2)
   void clearSupportedFeatures() => $_clearField(2);
 
+  /// The minimum edition this plugin supports.  This will be treated as an
+  /// Edition enum, but we want to allow unknown values.  It should be specified
+  /// according the edition enum value, *not* the edition number.  Only takes
+  /// effect for plugins that have FEATURE_SUPPORTS_EDITIONS set.
+  @$pb.TagNumber(3)
+  $core.int get minimumEdition => $_getIZ(2);
+  @$pb.TagNumber(3)
+  set minimumEdition($core.int v) {
+    $_setSignedInt32(2, v);
+  }
+
+  @$pb.TagNumber(3)
+  $core.bool hasMinimumEdition() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearMinimumEdition() => $_clearField(3);
+
+  /// The maximum edition this plugin supports.  This will be treated as an
+  /// Edition enum, but we want to allow unknown values.  It should be specified
+  /// according the edition enum value, *not* the edition number.  Only takes
+  /// effect for plugins that have FEATURE_SUPPORTS_EDITIONS set.
+  @$pb.TagNumber(4)
+  $core.int get maximumEdition => $_getIZ(3);
+  @$pb.TagNumber(4)
+  set maximumEdition($core.int v) {
+    $_setSignedInt32(3, v);
+  }
+
+  @$pb.TagNumber(4)
+  $core.bool hasMaximumEdition() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearMaximumEdition() => $_clearField(4);
+
   @$pb.TagNumber(15)
-  $pb.PbList<CodeGeneratorResponse_File> get file => $_getList(2);
+  $pb.PbList<CodeGeneratorResponse_File> get file => $_getList(4);
 }
 
 const _omitFieldNames = $core.bool.fromEnvironment('protobuf.omit_field_names');
diff --git a/protoc_plugin/lib/src/gen/google/protobuf/compiler/plugin.pbenum.dart b/protoc_plugin/lib/src/gen/google/protobuf/compiler/plugin.pbenum.dart
index c4ef32e..7e1fa58 100644
--- a/protoc_plugin/lib/src/gen/google/protobuf/compiler/plugin.pbenum.dart
+++ b/protoc_plugin/lib/src/gen/google/protobuf/compiler/plugin.pbenum.dart
@@ -20,15 +20,19 @@
   static const CodeGeneratorResponse_Feature FEATURE_PROTO3_OPTIONAL =
       CodeGeneratorResponse_Feature._(
           1, _omitEnumNames ? '' : 'FEATURE_PROTO3_OPTIONAL');
+  static const CodeGeneratorResponse_Feature FEATURE_SUPPORTS_EDITIONS =
+      CodeGeneratorResponse_Feature._(
+          2, _omitEnumNames ? '' : 'FEATURE_SUPPORTS_EDITIONS');
 
   static const $core.List<CodeGeneratorResponse_Feature> values =
       <CodeGeneratorResponse_Feature>[
     FEATURE_NONE,
     FEATURE_PROTO3_OPTIONAL,
+    FEATURE_SUPPORTS_EDITIONS,
   ];
 
   static final $core.List<CodeGeneratorResponse_Feature?> _byValue =
-      $pb.ProtobufEnum.$_initByValueList(values, 1);
+      $pb.ProtobufEnum.$_initByValueList(values, 2);
   static CodeGeneratorResponse_Feature? valueOf($core.int value) =>
       value < 0 || value >= _byValue.length ? null : _byValue[value];
 
diff --git a/protoc_plugin/lib/src/gen/google/protobuf/descriptor.pb.dart b/protoc_plugin/lib/src/gen/google/protobuf/descriptor.pb.dart
index 45f178a..dfd990f 100644
--- a/protoc_plugin/lib/src/gen/google/protobuf/descriptor.pb.dart
+++ b/protoc_plugin/lib/src/gen/google/protobuf/descriptor.pb.dart
@@ -47,7 +47,8 @@
       createEmptyInstance: create)
     ..pc<FileDescriptorProto>(
         1, _omitFieldNames ? '' : 'file', $pb.PbFieldType.PM,
-        subBuilder: FileDescriptorProto.create);
+        subBuilder: FileDescriptorProto.create)
+    ..hasExtensions = true;
 
   @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
   FileDescriptorSet clone() => FileDescriptorSet()..mergeFromMessage(this);
@@ -87,6 +88,8 @@
     $core.Iterable<$core.int>? publicDependency,
     $core.Iterable<$core.int>? weakDependency,
     $core.String? syntax,
+    Edition? edition,
+    $core.Iterable<$core.String>? optionDependency,
   }) {
     final $result = create();
     if (name != null) {
@@ -125,6 +128,12 @@
     if (syntax != null) {
       $result.syntax = syntax;
     }
+    if (edition != null) {
+      $result.edition = edition;
+    }
+    if (optionDependency != null) {
+      $result.optionDependency.addAll(optionDependency);
+    }
     return $result;
   }
   FileDescriptorProto._() : super();
@@ -163,7 +172,12 @@
         10, _omitFieldNames ? '' : 'publicDependency', $pb.PbFieldType.P3)
     ..p<$core.int>(
         11, _omitFieldNames ? '' : 'weakDependency', $pb.PbFieldType.P3)
-    ..aOS(12, _omitFieldNames ? '' : 'syntax');
+    ..aOS(12, _omitFieldNames ? '' : 'syntax')
+    ..e<Edition>(14, _omitFieldNames ? '' : 'edition', $pb.PbFieldType.OE,
+        defaultOrMaker: Edition.EDITION_UNKNOWN,
+        valueOf: Edition.valueOf,
+        enumValues: Edition.values)
+    ..pPS(15, _omitFieldNames ? '' : 'optionDependency');
 
   @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
   FileDescriptorProto clone() => FileDescriptorProto()..mergeFromMessage(this);
@@ -267,7 +281,12 @@
   $pb.PbList<$core.int> get weakDependency => $_getList(10);
 
   /// The syntax of the proto file.
-  /// The supported values are "proto2" and "proto3".
+  /// The supported values are "proto2", "proto3", and "editions".
+  ///
+  /// If `edition` is present, this value must be "editions".
+  /// WARNING: This field should only be used by protobuf plugins or special
+  /// cases like the proto compiler. Other uses are discouraged and
+  /// developers should rely on the protoreflect APIs for their client language.
   @$pb.TagNumber(12)
   $core.String get syntax => $_getSZ(11);
   @$pb.TagNumber(12)
@@ -279,6 +298,27 @@
   $core.bool hasSyntax() => $_has(11);
   @$pb.TagNumber(12)
   void clearSyntax() => $_clearField(12);
+
+  /// The edition of the proto file.
+  /// WARNING: This field should only be used by protobuf plugins or special
+  /// cases like the proto compiler. Other uses are discouraged and
+  /// developers should rely on the protoreflect APIs for their client language.
+  @$pb.TagNumber(14)
+  Edition get edition => $_getN(12);
+  @$pb.TagNumber(14)
+  set edition(Edition v) {
+    $_setField(14, v);
+  }
+
+  @$pb.TagNumber(14)
+  $core.bool hasEdition() => $_has(12);
+  @$pb.TagNumber(14)
+  void clearEdition() => $_clearField(14);
+
+  /// Names of files imported by this file purely for the purpose of providing
+  /// option extensions. These are excluded from the dependency list above.
+  @$pb.TagNumber(15)
+  $pb.PbList<$core.String> get optionDependency => $_getList(13);
 }
 
 class DescriptorProto_ExtensionRange extends $pb.GeneratedMessage {
@@ -474,6 +514,7 @@
     $core.Iterable<OneofDescriptorProto>? oneofDecl,
     $core.Iterable<DescriptorProto_ReservedRange>? reservedRange,
     $core.Iterable<$core.String>? reservedName,
+    SymbolVisibility? visibility,
   }) {
     final $result = create();
     if (name != null) {
@@ -506,6 +547,9 @@
     if (reservedName != null) {
       $result.reservedName.addAll(reservedName);
     }
+    if (visibility != null) {
+      $result.visibility = visibility;
+    }
     return $result;
   }
   DescriptorProto._() : super();
@@ -545,7 +589,12 @@
     ..pc<DescriptorProto_ReservedRange>(
         9, _omitFieldNames ? '' : 'reservedRange', $pb.PbFieldType.PM,
         subBuilder: DescriptorProto_ReservedRange.create)
-    ..pPS(10, _omitFieldNames ? '' : 'reservedName');
+    ..pPS(10, _omitFieldNames ? '' : 'reservedName')
+    ..e<SymbolVisibility>(
+        11, _omitFieldNames ? '' : 'visibility', $pb.PbFieldType.OE,
+        defaultOrMaker: SymbolVisibility.VISIBILITY_UNSET,
+        valueOf: SymbolVisibility.valueOf,
+        enumValues: SymbolVisibility.values);
 
   @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
   DescriptorProto clone() => DescriptorProto()..mergeFromMessage(this);
@@ -617,13 +666,180 @@
   /// A given name may only be reserved once.
   @$pb.TagNumber(10)
   $pb.PbList<$core.String> get reservedName => $_getList(9);
+
+  /// Support for `export` and `local` keywords on enums.
+  @$pb.TagNumber(11)
+  SymbolVisibility get visibility => $_getN(10);
+  @$pb.TagNumber(11)
+  set visibility(SymbolVisibility v) {
+    $_setField(11, v);
+  }
+
+  @$pb.TagNumber(11)
+  $core.bool hasVisibility() => $_has(10);
+  @$pb.TagNumber(11)
+  void clearVisibility() => $_clearField(11);
+}
+
+class ExtensionRangeOptions_Declaration extends $pb.GeneratedMessage {
+  factory ExtensionRangeOptions_Declaration({
+    $core.int? number,
+    $core.String? fullName,
+    $core.String? type,
+    $core.bool? reserved,
+    $core.bool? repeated,
+  }) {
+    final $result = create();
+    if (number != null) {
+      $result.number = number;
+    }
+    if (fullName != null) {
+      $result.fullName = fullName;
+    }
+    if (type != null) {
+      $result.type = type;
+    }
+    if (reserved != null) {
+      $result.reserved = reserved;
+    }
+    if (repeated != null) {
+      $result.repeated = repeated;
+    }
+    return $result;
+  }
+  ExtensionRangeOptions_Declaration._() : super();
+  factory ExtensionRangeOptions_Declaration.fromBuffer($core.List<$core.int> i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromBuffer(i, r);
+  factory ExtensionRangeOptions_Declaration.fromJson($core.String i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(
+      _omitMessageNames ? '' : 'ExtensionRangeOptions.Declaration',
+      package:
+          const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'),
+      createEmptyInstance: create)
+    ..a<$core.int>(1, _omitFieldNames ? '' : 'number', $pb.PbFieldType.O3)
+    ..aOS(2, _omitFieldNames ? '' : 'fullName')
+    ..aOS(3, _omitFieldNames ? '' : 'type')
+    ..aOB(5, _omitFieldNames ? '' : 'reserved')
+    ..aOB(6, _omitFieldNames ? '' : 'repeated')
+    ..hasRequiredFields = false;
+
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  ExtensionRangeOptions_Declaration clone() =>
+      ExtensionRangeOptions_Declaration()..mergeFromMessage(this);
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  ExtensionRangeOptions_Declaration copyWith(
+          void Function(ExtensionRangeOptions_Declaration) updates) =>
+      super.copyWith((message) =>
+              updates(message as ExtensionRangeOptions_Declaration))
+          as ExtensionRangeOptions_Declaration;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static ExtensionRangeOptions_Declaration create() =>
+      ExtensionRangeOptions_Declaration._();
+  ExtensionRangeOptions_Declaration createEmptyInstance() => create();
+  static $pb.PbList<ExtensionRangeOptions_Declaration> createRepeated() =>
+      $pb.PbList<ExtensionRangeOptions_Declaration>();
+  @$core.pragma('dart2js:noInline')
+  static ExtensionRangeOptions_Declaration getDefault() => _defaultInstance ??=
+      $pb.GeneratedMessage.$_defaultFor<ExtensionRangeOptions_Declaration>(
+          create);
+  static ExtensionRangeOptions_Declaration? _defaultInstance;
+
+  /// The extension number declared within the extension range.
+  @$pb.TagNumber(1)
+  $core.int get number => $_getIZ(0);
+  @$pb.TagNumber(1)
+  set number($core.int v) {
+    $_setSignedInt32(0, v);
+  }
+
+  @$pb.TagNumber(1)
+  $core.bool hasNumber() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearNumber() => $_clearField(1);
+
+  /// The fully-qualified name of the extension field. There must be a leading
+  /// dot in front of the full name.
+  @$pb.TagNumber(2)
+  $core.String get fullName => $_getSZ(1);
+  @$pb.TagNumber(2)
+  set fullName($core.String v) {
+    $_setString(1, v);
+  }
+
+  @$pb.TagNumber(2)
+  $core.bool hasFullName() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearFullName() => $_clearField(2);
+
+  /// The fully-qualified type name of the extension field. Unlike
+  /// Metadata.type, Declaration.type must have a leading dot for messages
+  /// and enums.
+  @$pb.TagNumber(3)
+  $core.String get type => $_getSZ(2);
+  @$pb.TagNumber(3)
+  set type($core.String v) {
+    $_setString(2, v);
+  }
+
+  @$pb.TagNumber(3)
+  $core.bool hasType() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearType() => $_clearField(3);
+
+  /// If true, indicates that the number is reserved in the extension range,
+  /// and any extension field with the number will fail to compile. Set this
+  /// when a declared extension field is deleted.
+  @$pb.TagNumber(5)
+  $core.bool get reserved => $_getBF(3);
+  @$pb.TagNumber(5)
+  set reserved($core.bool v) {
+    $_setBool(3, v);
+  }
+
+  @$pb.TagNumber(5)
+  $core.bool hasReserved() => $_has(3);
+  @$pb.TagNumber(5)
+  void clearReserved() => $_clearField(5);
+
+  /// If true, indicates that the extension must be defined as repeated.
+  /// Otherwise the extension must be defined as optional.
+  @$pb.TagNumber(6)
+  $core.bool get repeated => $_getBF(4);
+  @$pb.TagNumber(6)
+  set repeated($core.bool v) {
+    $_setBool(4, v);
+  }
+
+  @$pb.TagNumber(6)
+  $core.bool hasRepeated() => $_has(4);
+  @$pb.TagNumber(6)
+  void clearRepeated() => $_clearField(6);
 }
 
 class ExtensionRangeOptions extends $pb.GeneratedMessage {
   factory ExtensionRangeOptions({
+    $core.Iterable<ExtensionRangeOptions_Declaration>? declaration,
+    ExtensionRangeOptions_VerificationState? verification,
+    FeatureSet? features,
     $core.Iterable<UninterpretedOption>? uninterpretedOption,
   }) {
     final $result = create();
+    if (declaration != null) {
+      $result.declaration.addAll(declaration);
+    }
+    if (verification != null) {
+      $result.verification = verification;
+    }
+    if (features != null) {
+      $result.features = features;
+    }
     if (uninterpretedOption != null) {
       $result.uninterpretedOption.addAll(uninterpretedOption);
     }
@@ -642,6 +858,16 @@
       package:
           const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'),
       createEmptyInstance: create)
+    ..pc<ExtensionRangeOptions_Declaration>(
+        2, _omitFieldNames ? '' : 'declaration', $pb.PbFieldType.PM,
+        subBuilder: ExtensionRangeOptions_Declaration.create)
+    ..e<ExtensionRangeOptions_VerificationState>(
+        3, _omitFieldNames ? '' : 'verification', $pb.PbFieldType.OE,
+        defaultOrMaker: ExtensionRangeOptions_VerificationState.UNVERIFIED,
+        valueOf: ExtensionRangeOptions_VerificationState.valueOf,
+        enumValues: ExtensionRangeOptions_VerificationState.values)
+    ..aOM<FeatureSet>(50, _omitFieldNames ? '' : 'features',
+        subBuilder: FeatureSet.create)
     ..pc<UninterpretedOption>(
         999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM,
         subBuilder: UninterpretedOption.create)
@@ -668,9 +894,45 @@
       $pb.GeneratedMessage.$_defaultFor<ExtensionRangeOptions>(create);
   static ExtensionRangeOptions? _defaultInstance;
 
+  /// For external users: DO NOT USE. We are in the process of open sourcing
+  /// extension declaration and executing internal cleanups before it can be
+  /// used externally.
+  @$pb.TagNumber(2)
+  $pb.PbList<ExtensionRangeOptions_Declaration> get declaration => $_getList(0);
+
+  /// The verification state of the range.
+  /// TODO: flip the default to DECLARATION once all empty ranges
+  /// are marked as UNVERIFIED.
+  @$pb.TagNumber(3)
+  ExtensionRangeOptions_VerificationState get verification => $_getN(1);
+  @$pb.TagNumber(3)
+  set verification(ExtensionRangeOptions_VerificationState v) {
+    $_setField(3, v);
+  }
+
+  @$pb.TagNumber(3)
+  $core.bool hasVerification() => $_has(1);
+  @$pb.TagNumber(3)
+  void clearVerification() => $_clearField(3);
+
+  /// Any features defined in the specific edition.
+  @$pb.TagNumber(50)
+  FeatureSet get features => $_getN(2);
+  @$pb.TagNumber(50)
+  set features(FeatureSet v) {
+    $_setField(50, v);
+  }
+
+  @$pb.TagNumber(50)
+  $core.bool hasFeatures() => $_has(2);
+  @$pb.TagNumber(50)
+  void clearFeatures() => $_clearField(50);
+  @$pb.TagNumber(50)
+  FeatureSet ensureFeatures() => $_ensure(2);
+
   /// The parser stores options it doesn't recognize here. See above.
   @$pb.TagNumber(999)
-  $pb.PbList<UninterpretedOption> get uninterpretedOption => $_getList(0);
+  $pb.PbList<UninterpretedOption> get uninterpretedOption => $_getList(3);
 }
 
 /// Describes a field within a message.
@@ -863,7 +1125,6 @@
   /// For booleans, "true" or "false".
   /// For strings, contains the default text contents (not escaped in any way).
   /// For bytes, contains the C escaped value.  All bytes >= 128 are escaped.
-  /// TODO(kenton):  Base-64 encode?
   @$pb.TagNumber(7)
   $core.String get defaultValue => $_getSZ(6);
   @$pb.TagNumber(7)
@@ -923,12 +1184,12 @@
   /// If true, this is a proto3 "optional". When a proto3 field is optional, it
   /// tracks presence regardless of field type.
   ///
-  /// When proto3_optional is true, this field must be belong to a oneof to
-  /// signal to old proto3 clients that presence is tracked for this field. This
-  /// oneof is known as a "synthetic" oneof, and this field must be its sole
-  /// member (each proto3 optional field gets its own synthetic oneof). Synthetic
-  /// oneofs exist in the descriptor only, and do not generate any API. Synthetic
-  /// oneofs must be ordered after all "real" oneofs.
+  /// When proto3_optional is true, this field must belong to a oneof to signal
+  /// to old proto3 clients that presence is tracked for this field. This oneof
+  /// is known as a "synthetic" oneof, and this field must be its sole member
+  /// (each proto3 optional field gets its own synthetic oneof). Synthetic oneofs
+  /// exist in the descriptor only, and do not generate any API. Synthetic oneofs
+  /// must be ordered after all "real" oneofs.
   ///
   /// For message fields, proto3_optional doesn't create any semantic change,
   /// since non-repeated message fields always track presence. However it still
@@ -1128,6 +1389,7 @@
     EnumOptions? options,
     $core.Iterable<EnumDescriptorProto_EnumReservedRange>? reservedRange,
     $core.Iterable<$core.String>? reservedName,
+    SymbolVisibility? visibility,
   }) {
     final $result = create();
     if (name != null) {
@@ -1145,6 +1407,9 @@
     if (reservedName != null) {
       $result.reservedName.addAll(reservedName);
     }
+    if (visibility != null) {
+      $result.visibility = visibility;
+    }
     return $result;
   }
   EnumDescriptorProto._() : super();
@@ -1169,7 +1434,12 @@
     ..pc<EnumDescriptorProto_EnumReservedRange>(
         4, _omitFieldNames ? '' : 'reservedRange', $pb.PbFieldType.PM,
         subBuilder: EnumDescriptorProto_EnumReservedRange.create)
-    ..pPS(5, _omitFieldNames ? '' : 'reservedName');
+    ..pPS(5, _omitFieldNames ? '' : 'reservedName')
+    ..e<SymbolVisibility>(
+        6, _omitFieldNames ? '' : 'visibility', $pb.PbFieldType.OE,
+        defaultOrMaker: SymbolVisibility.VISIBILITY_UNSET,
+        valueOf: SymbolVisibility.valueOf,
+        enumValues: SymbolVisibility.values);
 
   @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
   EnumDescriptorProto clone() => EnumDescriptorProto()..mergeFromMessage(this);
@@ -1230,6 +1500,19 @@
   /// be reserved once.
   @$pb.TagNumber(5)
   $pb.PbList<$core.String> get reservedName => $_getList(4);
+
+  /// Support for `export` and `local` keywords on enums.
+  @$pb.TagNumber(6)
+  SymbolVisibility get visibility => $_getN(5);
+  @$pb.TagNumber(6)
+  set visibility(SymbolVisibility v) {
+    $_setField(6, v);
+  }
+
+  @$pb.TagNumber(6)
+  $core.bool hasVisibility() => $_has(5);
+  @$pb.TagNumber(6)
+  void clearVisibility() => $_clearField(6);
 }
 
 /// Describes a value within an enum.
@@ -1591,9 +1874,9 @@
     $core.String? swiftPrefix,
     $core.String? phpClassPrefix,
     $core.String? phpNamespace,
-    $core.bool? phpGenericServices,
     $core.String? phpMetadataNamespace,
     $core.String? rubyPackage,
+    FeatureSet? features,
     $core.Iterable<UninterpretedOption>? uninterpretedOption,
   }) {
     final $result = create();
@@ -1649,15 +1932,15 @@
     if (phpNamespace != null) {
       $result.phpNamespace = phpNamespace;
     }
-    if (phpGenericServices != null) {
-      $result.phpGenericServices = phpGenericServices;
-    }
     if (phpMetadataNamespace != null) {
       $result.phpMetadataNamespace = phpMetadataNamespace;
     }
     if (rubyPackage != null) {
       $result.rubyPackage = rubyPackage;
     }
+    if (features != null) {
+      $result.features = features;
+    }
     if (uninterpretedOption != null) {
       $result.uninterpretedOption.addAll(uninterpretedOption);
     }
@@ -1699,9 +1982,10 @@
     ..aOS(39, _omitFieldNames ? '' : 'swiftPrefix')
     ..aOS(40, _omitFieldNames ? '' : 'phpClassPrefix')
     ..aOS(41, _omitFieldNames ? '' : 'phpNamespace')
-    ..aOB(42, _omitFieldNames ? '' : 'phpGenericServices')
     ..aOS(44, _omitFieldNames ? '' : 'phpMetadataNamespace')
     ..aOS(45, _omitFieldNames ? '' : 'rubyPackage')
+    ..aOM<FeatureSet>(50, _omitFieldNames ? '' : 'features',
+        subBuilder: FeatureSet.create)
     ..pc<UninterpretedOption>(
         999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM,
         subBuilder: UninterpretedOption.create)
@@ -1741,11 +2025,11 @@
   @$pb.TagNumber(1)
   void clearJavaPackage() => $_clearField(1);
 
-  /// If set, all the classes from the .proto file are wrapped in a single
-  /// outer class with the given name.  This applies to both Proto1
-  /// (equivalent to the old "--one_java_file" option) and Proto2 (where
-  /// a .proto always translates to a single class, but you may want to
-  /// explicitly choose the class name).
+  /// Controls the name of the wrapper Java class generated for the .proto file.
+  /// That class will always contain the .proto file's getDescriptor() method as
+  /// well as any top-level extensions defined in the .proto file.
+  /// If java_multiple_files is disabled, then all the other classes from the
+  /// .proto file will be nested inside the single wrapper outer class.
   @$pb.TagNumber(8)
   $core.String get javaOuterClassname => $_getSZ(1);
   @$pb.TagNumber(8)
@@ -1770,10 +2054,10 @@
   @$pb.TagNumber(9)
   void clearOptimizeFor() => $_clearField(9);
 
-  /// If set true, then the Java code generator will generate a separate .java
+  /// If enabled, then the Java code generator will generate a separate .java
   /// file for each top-level message, enum, and service defined in the .proto
-  /// file.  Thus, these types will *not* be nested inside the outer class
-  /// named by java_outer_classname.  However, the outer class will still be
+  /// file.  Thus, these types will *not* be nested inside the wrapper class
+  /// named by java_outer_classname.  However, the wrapper class will still be
   /// generated to contain the file's getDescriptor() method as well as any
   /// top-level extensions defined in the file.
   @$pb.TagNumber(10)
@@ -1884,12 +2168,16 @@
   @$pb.TagNumber(23)
   void clearDeprecated() => $_clearField(23);
 
-  /// If set true, then the Java2 code generator will generate code that
-  /// throws an exception whenever an attempt is made to assign a non-UTF-8
-  /// byte sequence to a string field.
-  /// Message reflection will do the same.
-  /// However, an extension field still accepts non-UTF-8 byte sequences.
-  /// This option has no effect on when used with the lite runtime.
+  /// A proto2 file can set this to true to opt in to UTF-8 checking for Java,
+  /// which will throw an exception if invalid UTF-8 is parsed from the wire or
+  /// assigned to a string field.
+  ///
+  /// TODO: clarify exactly what kinds of field types this option
+  /// applies to, and update these docs accordingly.
+  ///
+  /// Proto3 files already perform these checks. Setting the option explicitly to
+  /// false has no effect: it cannot be used to opt proto3 files out of UTF-8
+  /// checks.
   @$pb.TagNumber(27)
   $core.bool get javaStringCheckUtf8 => $_getBF(10);
   @$pb.TagNumber(27)
@@ -1988,30 +2276,18 @@
   @$pb.TagNumber(41)
   void clearPhpNamespace() => $_clearField(41);
 
-  @$pb.TagNumber(42)
-  $core.bool get phpGenericServices => $_getBF(17);
-  @$pb.TagNumber(42)
-  set phpGenericServices($core.bool v) {
-    $_setBool(17, v);
-  }
-
-  @$pb.TagNumber(42)
-  $core.bool hasPhpGenericServices() => $_has(17);
-  @$pb.TagNumber(42)
-  void clearPhpGenericServices() => $_clearField(42);
-
   /// Use this option to change the namespace of php generated metadata classes.
   /// Default is empty. When this option is empty, the proto file name will be
   /// used for determining the namespace.
   @$pb.TagNumber(44)
-  $core.String get phpMetadataNamespace => $_getSZ(18);
+  $core.String get phpMetadataNamespace => $_getSZ(17);
   @$pb.TagNumber(44)
   set phpMetadataNamespace($core.String v) {
-    $_setString(18, v);
+    $_setString(17, v);
   }
 
   @$pb.TagNumber(44)
-  $core.bool hasPhpMetadataNamespace() => $_has(18);
+  $core.bool hasPhpMetadataNamespace() => $_has(17);
   @$pb.TagNumber(44)
   void clearPhpMetadataNamespace() => $_clearField(44);
 
@@ -2019,17 +2295,35 @@
   /// is empty. When this option is not set, the package name will be used for
   /// determining the ruby package.
   @$pb.TagNumber(45)
-  $core.String get rubyPackage => $_getSZ(19);
+  $core.String get rubyPackage => $_getSZ(18);
   @$pb.TagNumber(45)
   set rubyPackage($core.String v) {
-    $_setString(19, v);
+    $_setString(18, v);
   }
 
   @$pb.TagNumber(45)
-  $core.bool hasRubyPackage() => $_has(19);
+  $core.bool hasRubyPackage() => $_has(18);
   @$pb.TagNumber(45)
   void clearRubyPackage() => $_clearField(45);
 
+  /// Any features defined in the specific edition.
+  /// WARNING: This field should only be used by protobuf plugins or special
+  /// cases like the proto compiler. Other uses are discouraged and
+  /// developers should rely on the protoreflect APIs for their client language.
+  @$pb.TagNumber(50)
+  FeatureSet get features => $_getN(19);
+  @$pb.TagNumber(50)
+  set features(FeatureSet v) {
+    $_setField(50, v);
+  }
+
+  @$pb.TagNumber(50)
+  $core.bool hasFeatures() => $_has(19);
+  @$pb.TagNumber(50)
+  void clearFeatures() => $_clearField(50);
+  @$pb.TagNumber(50)
+  FeatureSet ensureFeatures() => $_ensure(19);
+
   /// The parser stores options it doesn't recognize here.
   /// See the documentation for the "Options" section above.
   @$pb.TagNumber(999)
@@ -2042,6 +2336,9 @@
     $core.bool? noStandardDescriptorAccessor,
     $core.bool? deprecated,
     $core.bool? mapEntry,
+    @$core.Deprecated('This field is deprecated.')
+    $core.bool? deprecatedLegacyJsonFieldConflicts,
+    FeatureSet? features,
     $core.Iterable<UninterpretedOption>? uninterpretedOption,
   }) {
     final $result = create();
@@ -2057,6 +2354,14 @@
     if (mapEntry != null) {
       $result.mapEntry = mapEntry;
     }
+    if (deprecatedLegacyJsonFieldConflicts != null) {
+      // ignore: deprecated_member_use_from_same_package
+      $result.deprecatedLegacyJsonFieldConflicts =
+          deprecatedLegacyJsonFieldConflicts;
+    }
+    if (features != null) {
+      $result.features = features;
+    }
     if (uninterpretedOption != null) {
       $result.uninterpretedOption.addAll(uninterpretedOption);
     }
@@ -2079,6 +2384,9 @@
     ..aOB(2, _omitFieldNames ? '' : 'noStandardDescriptorAccessor')
     ..aOB(3, _omitFieldNames ? '' : 'deprecated')
     ..aOB(7, _omitFieldNames ? '' : 'mapEntry')
+    ..aOB(11, _omitFieldNames ? '' : 'deprecatedLegacyJsonFieldConflicts')
+    ..aOM<FeatureSet>(12, _omitFieldNames ? '' : 'features',
+        subBuilder: FeatureSet.create)
     ..pc<UninterpretedOption>(
         999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM,
         subBuilder: UninterpretedOption.create)
@@ -2197,9 +2505,270 @@
   @$pb.TagNumber(7)
   void clearMapEntry() => $_clearField(7);
 
+  /// Enable the legacy handling of JSON field name conflicts.  This lowercases
+  /// and strips underscored from the fields before comparison in proto3 only.
+  /// The new behavior takes `json_name` into account and applies to proto2 as
+  /// well.
+  ///
+  /// This should only be used as a temporary measure against broken builds due
+  /// to the change in behavior for JSON field name conflicts.
+  ///
+  /// TODO This is legacy behavior we plan to remove once downstream
+  /// teams have had time to migrate.
+  @$core.Deprecated('This field is deprecated.')
+  @$pb.TagNumber(11)
+  $core.bool get deprecatedLegacyJsonFieldConflicts => $_getBF(4);
+  @$core.Deprecated('This field is deprecated.')
+  @$pb.TagNumber(11)
+  set deprecatedLegacyJsonFieldConflicts($core.bool v) {
+    $_setBool(4, v);
+  }
+
+  @$core.Deprecated('This field is deprecated.')
+  @$pb.TagNumber(11)
+  $core.bool hasDeprecatedLegacyJsonFieldConflicts() => $_has(4);
+  @$core.Deprecated('This field is deprecated.')
+  @$pb.TagNumber(11)
+  void clearDeprecatedLegacyJsonFieldConflicts() => $_clearField(11);
+
+  /// Any features defined in the specific edition.
+  /// WARNING: This field should only be used by protobuf plugins or special
+  /// cases like the proto compiler. Other uses are discouraged and
+  /// developers should rely on the protoreflect APIs for their client language.
+  @$pb.TagNumber(12)
+  FeatureSet get features => $_getN(5);
+  @$pb.TagNumber(12)
+  set features(FeatureSet v) {
+    $_setField(12, v);
+  }
+
+  @$pb.TagNumber(12)
+  $core.bool hasFeatures() => $_has(5);
+  @$pb.TagNumber(12)
+  void clearFeatures() => $_clearField(12);
+  @$pb.TagNumber(12)
+  FeatureSet ensureFeatures() => $_ensure(5);
+
   /// The parser stores options it doesn't recognize here. See above.
   @$pb.TagNumber(999)
-  $pb.PbList<UninterpretedOption> get uninterpretedOption => $_getList(4);
+  $pb.PbList<UninterpretedOption> get uninterpretedOption => $_getList(6);
+}
+
+class FieldOptions_EditionDefault extends $pb.GeneratedMessage {
+  factory FieldOptions_EditionDefault({
+    $core.String? value,
+    Edition? edition,
+  }) {
+    final $result = create();
+    if (value != null) {
+      $result.value = value;
+    }
+    if (edition != null) {
+      $result.edition = edition;
+    }
+    return $result;
+  }
+  FieldOptions_EditionDefault._() : super();
+  factory FieldOptions_EditionDefault.fromBuffer($core.List<$core.int> i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromBuffer(i, r);
+  factory FieldOptions_EditionDefault.fromJson($core.String i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(
+      _omitMessageNames ? '' : 'FieldOptions.EditionDefault',
+      package:
+          const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'),
+      createEmptyInstance: create)
+    ..aOS(2, _omitFieldNames ? '' : 'value')
+    ..e<Edition>(3, _omitFieldNames ? '' : 'edition', $pb.PbFieldType.OE,
+        defaultOrMaker: Edition.EDITION_UNKNOWN,
+        valueOf: Edition.valueOf,
+        enumValues: Edition.values)
+    ..hasRequiredFields = false;
+
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  FieldOptions_EditionDefault clone() =>
+      FieldOptions_EditionDefault()..mergeFromMessage(this);
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  FieldOptions_EditionDefault copyWith(
+          void Function(FieldOptions_EditionDefault) updates) =>
+      super.copyWith(
+              (message) => updates(message as FieldOptions_EditionDefault))
+          as FieldOptions_EditionDefault;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static FieldOptions_EditionDefault create() =>
+      FieldOptions_EditionDefault._();
+  FieldOptions_EditionDefault createEmptyInstance() => create();
+  static $pb.PbList<FieldOptions_EditionDefault> createRepeated() =>
+      $pb.PbList<FieldOptions_EditionDefault>();
+  @$core.pragma('dart2js:noInline')
+  static FieldOptions_EditionDefault getDefault() => _defaultInstance ??=
+      $pb.GeneratedMessage.$_defaultFor<FieldOptions_EditionDefault>(create);
+  static FieldOptions_EditionDefault? _defaultInstance;
+
+  @$pb.TagNumber(2)
+  $core.String get value => $_getSZ(0);
+  @$pb.TagNumber(2)
+  set value($core.String v) {
+    $_setString(0, v);
+  }
+
+  @$pb.TagNumber(2)
+  $core.bool hasValue() => $_has(0);
+  @$pb.TagNumber(2)
+  void clearValue() => $_clearField(2);
+
+  @$pb.TagNumber(3)
+  Edition get edition => $_getN(1);
+  @$pb.TagNumber(3)
+  set edition(Edition v) {
+    $_setField(3, v);
+  }
+
+  @$pb.TagNumber(3)
+  $core.bool hasEdition() => $_has(1);
+  @$pb.TagNumber(3)
+  void clearEdition() => $_clearField(3);
+}
+
+/// Information about the support window of a feature.
+class FieldOptions_FeatureSupport extends $pb.GeneratedMessage {
+  factory FieldOptions_FeatureSupport({
+    Edition? editionIntroduced,
+    Edition? editionDeprecated,
+    $core.String? deprecationWarning,
+    Edition? editionRemoved,
+  }) {
+    final $result = create();
+    if (editionIntroduced != null) {
+      $result.editionIntroduced = editionIntroduced;
+    }
+    if (editionDeprecated != null) {
+      $result.editionDeprecated = editionDeprecated;
+    }
+    if (deprecationWarning != null) {
+      $result.deprecationWarning = deprecationWarning;
+    }
+    if (editionRemoved != null) {
+      $result.editionRemoved = editionRemoved;
+    }
+    return $result;
+  }
+  FieldOptions_FeatureSupport._() : super();
+  factory FieldOptions_FeatureSupport.fromBuffer($core.List<$core.int> i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromBuffer(i, r);
+  factory FieldOptions_FeatureSupport.fromJson($core.String i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(
+      _omitMessageNames ? '' : 'FieldOptions.FeatureSupport',
+      package:
+          const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'),
+      createEmptyInstance: create)
+    ..e<Edition>(
+        1, _omitFieldNames ? '' : 'editionIntroduced', $pb.PbFieldType.OE,
+        defaultOrMaker: Edition.EDITION_UNKNOWN,
+        valueOf: Edition.valueOf,
+        enumValues: Edition.values)
+    ..e<Edition>(
+        2, _omitFieldNames ? '' : 'editionDeprecated', $pb.PbFieldType.OE,
+        defaultOrMaker: Edition.EDITION_UNKNOWN,
+        valueOf: Edition.valueOf,
+        enumValues: Edition.values)
+    ..aOS(3, _omitFieldNames ? '' : 'deprecationWarning')
+    ..e<Edition>(4, _omitFieldNames ? '' : 'editionRemoved', $pb.PbFieldType.OE,
+        defaultOrMaker: Edition.EDITION_UNKNOWN,
+        valueOf: Edition.valueOf,
+        enumValues: Edition.values)
+    ..hasRequiredFields = false;
+
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  FieldOptions_FeatureSupport clone() =>
+      FieldOptions_FeatureSupport()..mergeFromMessage(this);
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  FieldOptions_FeatureSupport copyWith(
+          void Function(FieldOptions_FeatureSupport) updates) =>
+      super.copyWith(
+              (message) => updates(message as FieldOptions_FeatureSupport))
+          as FieldOptions_FeatureSupport;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static FieldOptions_FeatureSupport create() =>
+      FieldOptions_FeatureSupport._();
+  FieldOptions_FeatureSupport createEmptyInstance() => create();
+  static $pb.PbList<FieldOptions_FeatureSupport> createRepeated() =>
+      $pb.PbList<FieldOptions_FeatureSupport>();
+  @$core.pragma('dart2js:noInline')
+  static FieldOptions_FeatureSupport getDefault() => _defaultInstance ??=
+      $pb.GeneratedMessage.$_defaultFor<FieldOptions_FeatureSupport>(create);
+  static FieldOptions_FeatureSupport? _defaultInstance;
+
+  /// The edition that this feature was first available in.  In editions
+  /// earlier than this one, the default assigned to EDITION_LEGACY will be
+  /// used, and proto files will not be able to override it.
+  @$pb.TagNumber(1)
+  Edition get editionIntroduced => $_getN(0);
+  @$pb.TagNumber(1)
+  set editionIntroduced(Edition v) {
+    $_setField(1, v);
+  }
+
+  @$pb.TagNumber(1)
+  $core.bool hasEditionIntroduced() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearEditionIntroduced() => $_clearField(1);
+
+  /// The edition this feature becomes deprecated in.  Using this after this
+  /// edition may trigger warnings.
+  @$pb.TagNumber(2)
+  Edition get editionDeprecated => $_getN(1);
+  @$pb.TagNumber(2)
+  set editionDeprecated(Edition v) {
+    $_setField(2, v);
+  }
+
+  @$pb.TagNumber(2)
+  $core.bool hasEditionDeprecated() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearEditionDeprecated() => $_clearField(2);
+
+  /// The deprecation warning text if this feature is used after the edition it
+  /// was marked deprecated in.
+  @$pb.TagNumber(3)
+  $core.String get deprecationWarning => $_getSZ(2);
+  @$pb.TagNumber(3)
+  set deprecationWarning($core.String v) {
+    $_setString(2, v);
+  }
+
+  @$pb.TagNumber(3)
+  $core.bool hasDeprecationWarning() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearDeprecationWarning() => $_clearField(3);
+
+  /// The edition this feature is no longer available in.  In editions after
+  /// this one, the last default assigned will be used, and proto files will
+  /// not be able to override it.
+  @$pb.TagNumber(4)
+  Edition get editionRemoved => $_getN(3);
+  @$pb.TagNumber(4)
+  set editionRemoved(Edition v) {
+    $_setField(4, v);
+  }
+
+  @$pb.TagNumber(4)
+  $core.bool hasEditionRemoved() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearEditionRemoved() => $_clearField(4);
 }
 
 class FieldOptions extends $pb.GeneratedMessage {
@@ -2210,6 +2779,13 @@
     $core.bool? lazy,
     FieldOptions_JSType? jstype,
     $core.bool? weak,
+    $core.bool? unverifiedLazy,
+    $core.bool? debugRedact,
+    FieldOptions_OptionRetention? retention,
+    $core.Iterable<FieldOptions_OptionTargetType>? targets,
+    $core.Iterable<FieldOptions_EditionDefault>? editionDefaults,
+    FeatureSet? features,
+    FieldOptions_FeatureSupport? featureSupport,
     $core.Iterable<UninterpretedOption>? uninterpretedOption,
   }) {
     final $result = create();
@@ -2231,6 +2807,27 @@
     if (weak != null) {
       $result.weak = weak;
     }
+    if (unverifiedLazy != null) {
+      $result.unverifiedLazy = unverifiedLazy;
+    }
+    if (debugRedact != null) {
+      $result.debugRedact = debugRedact;
+    }
+    if (retention != null) {
+      $result.retention = retention;
+    }
+    if (targets != null) {
+      $result.targets.addAll(targets);
+    }
+    if (editionDefaults != null) {
+      $result.editionDefaults.addAll(editionDefaults);
+    }
+    if (features != null) {
+      $result.features = features;
+    }
+    if (featureSupport != null) {
+      $result.featureSupport = featureSupport;
+    }
     if (uninterpretedOption != null) {
       $result.uninterpretedOption.addAll(uninterpretedOption);
     }
@@ -2263,6 +2860,26 @@
         valueOf: FieldOptions_JSType.valueOf,
         enumValues: FieldOptions_JSType.values)
     ..aOB(10, _omitFieldNames ? '' : 'weak')
+    ..aOB(15, _omitFieldNames ? '' : 'unverifiedLazy')
+    ..aOB(16, _omitFieldNames ? '' : 'debugRedact')
+    ..e<FieldOptions_OptionRetention>(
+        17, _omitFieldNames ? '' : 'retention', $pb.PbFieldType.OE,
+        defaultOrMaker: FieldOptions_OptionRetention.RETENTION_UNKNOWN,
+        valueOf: FieldOptions_OptionRetention.valueOf,
+        enumValues: FieldOptions_OptionRetention.values)
+    ..pc<FieldOptions_OptionTargetType>(
+        19, _omitFieldNames ? '' : 'targets', $pb.PbFieldType.PE,
+        valueOf: FieldOptions_OptionTargetType.valueOf,
+        enumValues: FieldOptions_OptionTargetType.values,
+        defaultEnumValue: FieldOptions_OptionTargetType.TARGET_TYPE_UNKNOWN)
+    ..pc<FieldOptions_EditionDefault>(
+        20, _omitFieldNames ? '' : 'editionDefaults', $pb.PbFieldType.PM,
+        subBuilder: FieldOptions_EditionDefault.create)
+    ..aOM<FeatureSet>(21, _omitFieldNames ? '' : 'features',
+        subBuilder: FeatureSet.create)
+    ..aOM<FieldOptions_FeatureSupport>(
+        22, _omitFieldNames ? '' : 'featureSupport',
+        subBuilder: FieldOptions_FeatureSupport.create)
     ..pc<UninterpretedOption>(
         999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM,
         subBuilder: UninterpretedOption.create)
@@ -2287,10 +2904,13 @@
       $pb.GeneratedMessage.$_defaultFor<FieldOptions>(create);
   static FieldOptions? _defaultInstance;
 
+  /// NOTE: ctype is deprecated. Use `features.(pb.cpp).string_type` instead.
   /// The ctype option instructs the C++ code generator to use a different
   /// representation of the field than it normally would.  See the specific
-  /// options below.  This option is not yet implemented in the open source
-  /// release -- sorry, we'll try to include it in a future version!
+  /// options below.  This option is only implemented to support use of
+  /// [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of
+  /// type "bytes" in the open source release.
+  /// TODO: make ctype actually deprecated.
   @$pb.TagNumber(1)
   FieldOptions_CType get ctype => $_getN(0);
   @$pb.TagNumber(1)
@@ -2307,7 +2927,9 @@
   /// a more efficient representation on the wire. Rather than repeatedly
   /// writing the tag and type for each element, the entire array is encoded as
   /// a single length-delimited blob. In proto3, only explicit setting it to
-  /// false will avoid using packed encoding.
+  /// false will avoid using packed encoding.  This option is prohibited in
+  /// Editions, but the `repeated_field_encoding` feature can be used to control
+  /// the behavior.
   @$pb.TagNumber(2)
   $core.bool get packed => $_getBF(1);
   @$pb.TagNumber(2)
@@ -2353,17 +2975,11 @@
   /// call from multiple threads concurrently, while non-const methods continue
   /// to require exclusive access.
   ///
-  ///
-  /// Note that implementations may choose not to check required fields within
-  /// a lazy sub-message.  That is, calling IsInitialized() on the outer message
-  /// may return true even if the inner message has missing required fields.
-  /// This is necessary because otherwise the inner message would have to be
-  /// parsed in order to perform the check, defeating the purpose of lazy
-  /// parsing.  An implementation which chooses not to check required fields
-  /// must be consistent about it.  That is, for any particular sub-message, the
-  /// implementation must either *always* check its required fields, or *never*
-  /// check its required fields, regardless of whether or not the message has
-  /// been parsed.
+  /// Note that lazy message fields are still eagerly verified to check
+  /// ill-formed wireformat or missing required fields. Calling IsInitialized()
+  /// on the outer message would fail if the inner message has missing required
+  /// fields. Failed verification would result in parsing failure (except when
+  /// uninitialized messages are acceptable).
   @$pb.TagNumber(5)
   $core.bool get lazy => $_getBF(3);
   @$pb.TagNumber(5)
@@ -2412,16 +3028,99 @@
   @$pb.TagNumber(10)
   void clearWeak() => $_clearField(10);
 
+  /// unverified_lazy does no correctness checks on the byte stream. This should
+  /// only be used where lazy with verification is prohibitive for performance
+  /// reasons.
+  @$pb.TagNumber(15)
+  $core.bool get unverifiedLazy => $_getBF(6);
+  @$pb.TagNumber(15)
+  set unverifiedLazy($core.bool v) {
+    $_setBool(6, v);
+  }
+
+  @$pb.TagNumber(15)
+  $core.bool hasUnverifiedLazy() => $_has(6);
+  @$pb.TagNumber(15)
+  void clearUnverifiedLazy() => $_clearField(15);
+
+  /// Indicate that the field value should not be printed out when using debug
+  /// formats, e.g. when the field contains sensitive credentials.
+  @$pb.TagNumber(16)
+  $core.bool get debugRedact => $_getBF(7);
+  @$pb.TagNumber(16)
+  set debugRedact($core.bool v) {
+    $_setBool(7, v);
+  }
+
+  @$pb.TagNumber(16)
+  $core.bool hasDebugRedact() => $_has(7);
+  @$pb.TagNumber(16)
+  void clearDebugRedact() => $_clearField(16);
+
+  @$pb.TagNumber(17)
+  FieldOptions_OptionRetention get retention => $_getN(8);
+  @$pb.TagNumber(17)
+  set retention(FieldOptions_OptionRetention v) {
+    $_setField(17, v);
+  }
+
+  @$pb.TagNumber(17)
+  $core.bool hasRetention() => $_has(8);
+  @$pb.TagNumber(17)
+  void clearRetention() => $_clearField(17);
+
+  @$pb.TagNumber(19)
+  $pb.PbList<FieldOptions_OptionTargetType> get targets => $_getList(9);
+
+  @$pb.TagNumber(20)
+  $pb.PbList<FieldOptions_EditionDefault> get editionDefaults => $_getList(10);
+
+  /// Any features defined in the specific edition.
+  /// WARNING: This field should only be used by protobuf plugins or special
+  /// cases like the proto compiler. Other uses are discouraged and
+  /// developers should rely on the protoreflect APIs for their client language.
+  @$pb.TagNumber(21)
+  FeatureSet get features => $_getN(11);
+  @$pb.TagNumber(21)
+  set features(FeatureSet v) {
+    $_setField(21, v);
+  }
+
+  @$pb.TagNumber(21)
+  $core.bool hasFeatures() => $_has(11);
+  @$pb.TagNumber(21)
+  void clearFeatures() => $_clearField(21);
+  @$pb.TagNumber(21)
+  FeatureSet ensureFeatures() => $_ensure(11);
+
+  @$pb.TagNumber(22)
+  FieldOptions_FeatureSupport get featureSupport => $_getN(12);
+  @$pb.TagNumber(22)
+  set featureSupport(FieldOptions_FeatureSupport v) {
+    $_setField(22, v);
+  }
+
+  @$pb.TagNumber(22)
+  $core.bool hasFeatureSupport() => $_has(12);
+  @$pb.TagNumber(22)
+  void clearFeatureSupport() => $_clearField(22);
+  @$pb.TagNumber(22)
+  FieldOptions_FeatureSupport ensureFeatureSupport() => $_ensure(12);
+
   /// The parser stores options it doesn't recognize here. See above.
   @$pb.TagNumber(999)
-  $pb.PbList<UninterpretedOption> get uninterpretedOption => $_getList(6);
+  $pb.PbList<UninterpretedOption> get uninterpretedOption => $_getList(13);
 }
 
 class OneofOptions extends $pb.GeneratedMessage {
   factory OneofOptions({
+    FeatureSet? features,
     $core.Iterable<UninterpretedOption>? uninterpretedOption,
   }) {
     final $result = create();
+    if (features != null) {
+      $result.features = features;
+    }
     if (uninterpretedOption != null) {
       $result.uninterpretedOption.addAll(uninterpretedOption);
     }
@@ -2440,6 +3139,8 @@
       package:
           const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'),
       createEmptyInstance: create)
+    ..aOM<FeatureSet>(1, _omitFieldNames ? '' : 'features',
+        subBuilder: FeatureSet.create)
     ..pc<UninterpretedOption>(
         999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM,
         subBuilder: UninterpretedOption.create)
@@ -2464,15 +3165,36 @@
       $pb.GeneratedMessage.$_defaultFor<OneofOptions>(create);
   static OneofOptions? _defaultInstance;
 
+  /// Any features defined in the specific edition.
+  /// WARNING: This field should only be used by protobuf plugins or special
+  /// cases like the proto compiler. Other uses are discouraged and
+  /// developers should rely on the protoreflect APIs for their client language.
+  @$pb.TagNumber(1)
+  FeatureSet get features => $_getN(0);
+  @$pb.TagNumber(1)
+  set features(FeatureSet v) {
+    $_setField(1, v);
+  }
+
+  @$pb.TagNumber(1)
+  $core.bool hasFeatures() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearFeatures() => $_clearField(1);
+  @$pb.TagNumber(1)
+  FeatureSet ensureFeatures() => $_ensure(0);
+
   /// The parser stores options it doesn't recognize here. See above.
   @$pb.TagNumber(999)
-  $pb.PbList<UninterpretedOption> get uninterpretedOption => $_getList(0);
+  $pb.PbList<UninterpretedOption> get uninterpretedOption => $_getList(1);
 }
 
 class EnumOptions extends $pb.GeneratedMessage {
   factory EnumOptions({
     $core.bool? allowAlias,
     $core.bool? deprecated,
+    @$core.Deprecated('This field is deprecated.')
+    $core.bool? deprecatedLegacyJsonFieldConflicts,
+    FeatureSet? features,
     $core.Iterable<UninterpretedOption>? uninterpretedOption,
   }) {
     final $result = create();
@@ -2482,6 +3204,14 @@
     if (deprecated != null) {
       $result.deprecated = deprecated;
     }
+    if (deprecatedLegacyJsonFieldConflicts != null) {
+      // ignore: deprecated_member_use_from_same_package
+      $result.deprecatedLegacyJsonFieldConflicts =
+          deprecatedLegacyJsonFieldConflicts;
+    }
+    if (features != null) {
+      $result.features = features;
+    }
     if (uninterpretedOption != null) {
       $result.uninterpretedOption.addAll(uninterpretedOption);
     }
@@ -2502,6 +3232,9 @@
       createEmptyInstance: create)
     ..aOB(2, _omitFieldNames ? '' : 'allowAlias')
     ..aOB(3, _omitFieldNames ? '' : 'deprecated')
+    ..aOB(6, _omitFieldNames ? '' : 'deprecatedLegacyJsonFieldConflicts')
+    ..aOM<FeatureSet>(7, _omitFieldNames ? '' : 'features',
+        subBuilder: FeatureSet.create)
     ..pc<UninterpretedOption>(
         999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM,
         subBuilder: UninterpretedOption.create)
@@ -2555,20 +3288,72 @@
   @$pb.TagNumber(3)
   void clearDeprecated() => $_clearField(3);
 
+  /// Enable the legacy handling of JSON field name conflicts.  This lowercases
+  /// and strips underscored from the fields before comparison in proto3 only.
+  /// The new behavior takes `json_name` into account and applies to proto2 as
+  /// well.
+  /// TODO Remove this legacy behavior once downstream teams have
+  /// had time to migrate.
+  @$core.Deprecated('This field is deprecated.')
+  @$pb.TagNumber(6)
+  $core.bool get deprecatedLegacyJsonFieldConflicts => $_getBF(2);
+  @$core.Deprecated('This field is deprecated.')
+  @$pb.TagNumber(6)
+  set deprecatedLegacyJsonFieldConflicts($core.bool v) {
+    $_setBool(2, v);
+  }
+
+  @$core.Deprecated('This field is deprecated.')
+  @$pb.TagNumber(6)
+  $core.bool hasDeprecatedLegacyJsonFieldConflicts() => $_has(2);
+  @$core.Deprecated('This field is deprecated.')
+  @$pb.TagNumber(6)
+  void clearDeprecatedLegacyJsonFieldConflicts() => $_clearField(6);
+
+  /// Any features defined in the specific edition.
+  /// WARNING: This field should only be used by protobuf plugins or special
+  /// cases like the proto compiler. Other uses are discouraged and
+  /// developers should rely on the protoreflect APIs for their client language.
+  @$pb.TagNumber(7)
+  FeatureSet get features => $_getN(3);
+  @$pb.TagNumber(7)
+  set features(FeatureSet v) {
+    $_setField(7, v);
+  }
+
+  @$pb.TagNumber(7)
+  $core.bool hasFeatures() => $_has(3);
+  @$pb.TagNumber(7)
+  void clearFeatures() => $_clearField(7);
+  @$pb.TagNumber(7)
+  FeatureSet ensureFeatures() => $_ensure(3);
+
   /// The parser stores options it doesn't recognize here. See above.
   @$pb.TagNumber(999)
-  $pb.PbList<UninterpretedOption> get uninterpretedOption => $_getList(2);
+  $pb.PbList<UninterpretedOption> get uninterpretedOption => $_getList(4);
 }
 
 class EnumValueOptions extends $pb.GeneratedMessage {
   factory EnumValueOptions({
     $core.bool? deprecated,
+    FeatureSet? features,
+    $core.bool? debugRedact,
+    FieldOptions_FeatureSupport? featureSupport,
     $core.Iterable<UninterpretedOption>? uninterpretedOption,
   }) {
     final $result = create();
     if (deprecated != null) {
       $result.deprecated = deprecated;
     }
+    if (features != null) {
+      $result.features = features;
+    }
+    if (debugRedact != null) {
+      $result.debugRedact = debugRedact;
+    }
+    if (featureSupport != null) {
+      $result.featureSupport = featureSupport;
+    }
     if (uninterpretedOption != null) {
       $result.uninterpretedOption.addAll(uninterpretedOption);
     }
@@ -2588,6 +3373,12 @@
           const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'),
       createEmptyInstance: create)
     ..aOB(1, _omitFieldNames ? '' : 'deprecated')
+    ..aOM<FeatureSet>(2, _omitFieldNames ? '' : 'features',
+        subBuilder: FeatureSet.create)
+    ..aOB(3, _omitFieldNames ? '' : 'debugRedact')
+    ..aOM<FieldOptions_FeatureSupport>(
+        4, _omitFieldNames ? '' : 'featureSupport',
+        subBuilder: FieldOptions_FeatureSupport.create)
     ..pc<UninterpretedOption>(
         999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM,
         subBuilder: UninterpretedOption.create)
@@ -2628,20 +3419,72 @@
   @$pb.TagNumber(1)
   void clearDeprecated() => $_clearField(1);
 
+  /// Any features defined in the specific edition.
+  /// WARNING: This field should only be used by protobuf plugins or special
+  /// cases like the proto compiler. Other uses are discouraged and
+  /// developers should rely on the protoreflect APIs for their client language.
+  @$pb.TagNumber(2)
+  FeatureSet get features => $_getN(1);
+  @$pb.TagNumber(2)
+  set features(FeatureSet v) {
+    $_setField(2, v);
+  }
+
+  @$pb.TagNumber(2)
+  $core.bool hasFeatures() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearFeatures() => $_clearField(2);
+  @$pb.TagNumber(2)
+  FeatureSet ensureFeatures() => $_ensure(1);
+
+  /// Indicate that fields annotated with this enum value should not be printed
+  /// out when using debug formats, e.g. when the field contains sensitive
+  /// credentials.
+  @$pb.TagNumber(3)
+  $core.bool get debugRedact => $_getBF(2);
+  @$pb.TagNumber(3)
+  set debugRedact($core.bool v) {
+    $_setBool(2, v);
+  }
+
+  @$pb.TagNumber(3)
+  $core.bool hasDebugRedact() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearDebugRedact() => $_clearField(3);
+
+  /// Information about the support window of a feature value.
+  @$pb.TagNumber(4)
+  FieldOptions_FeatureSupport get featureSupport => $_getN(3);
+  @$pb.TagNumber(4)
+  set featureSupport(FieldOptions_FeatureSupport v) {
+    $_setField(4, v);
+  }
+
+  @$pb.TagNumber(4)
+  $core.bool hasFeatureSupport() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearFeatureSupport() => $_clearField(4);
+  @$pb.TagNumber(4)
+  FieldOptions_FeatureSupport ensureFeatureSupport() => $_ensure(3);
+
   /// The parser stores options it doesn't recognize here. See above.
   @$pb.TagNumber(999)
-  $pb.PbList<UninterpretedOption> get uninterpretedOption => $_getList(1);
+  $pb.PbList<UninterpretedOption> get uninterpretedOption => $_getList(4);
 }
 
 class ServiceOptions extends $pb.GeneratedMessage {
   factory ServiceOptions({
     $core.bool? deprecated,
+    FeatureSet? features,
     $core.Iterable<UninterpretedOption>? uninterpretedOption,
   }) {
     final $result = create();
     if (deprecated != null) {
       $result.deprecated = deprecated;
     }
+    if (features != null) {
+      $result.features = features;
+    }
     if (uninterpretedOption != null) {
       $result.uninterpretedOption.addAll(uninterpretedOption);
     }
@@ -2661,6 +3504,8 @@
           const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'),
       createEmptyInstance: create)
     ..aOB(33, _omitFieldNames ? '' : 'deprecated')
+    ..aOM<FeatureSet>(34, _omitFieldNames ? '' : 'features',
+        subBuilder: FeatureSet.create)
     ..pc<UninterpretedOption>(
         999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM,
         subBuilder: UninterpretedOption.create)
@@ -2701,15 +3546,34 @@
   @$pb.TagNumber(33)
   void clearDeprecated() => $_clearField(33);
 
+  /// Any features defined in the specific edition.
+  /// WARNING: This field should only be used by protobuf plugins or special
+  /// cases like the proto compiler. Other uses are discouraged and
+  /// developers should rely on the protoreflect APIs for their client language.
+  @$pb.TagNumber(34)
+  FeatureSet get features => $_getN(1);
+  @$pb.TagNumber(34)
+  set features(FeatureSet v) {
+    $_setField(34, v);
+  }
+
+  @$pb.TagNumber(34)
+  $core.bool hasFeatures() => $_has(1);
+  @$pb.TagNumber(34)
+  void clearFeatures() => $_clearField(34);
+  @$pb.TagNumber(34)
+  FeatureSet ensureFeatures() => $_ensure(1);
+
   /// The parser stores options it doesn't recognize here. See above.
   @$pb.TagNumber(999)
-  $pb.PbList<UninterpretedOption> get uninterpretedOption => $_getList(1);
+  $pb.PbList<UninterpretedOption> get uninterpretedOption => $_getList(2);
 }
 
 class MethodOptions extends $pb.GeneratedMessage {
   factory MethodOptions({
     $core.bool? deprecated,
     MethodOptions_IdempotencyLevel? idempotencyLevel,
+    FeatureSet? features,
     $core.Iterable<UninterpretedOption>? uninterpretedOption,
   }) {
     final $result = create();
@@ -2719,6 +3583,9 @@
     if (idempotencyLevel != null) {
       $result.idempotencyLevel = idempotencyLevel;
     }
+    if (features != null) {
+      $result.features = features;
+    }
     if (uninterpretedOption != null) {
       $result.uninterpretedOption.addAll(uninterpretedOption);
     }
@@ -2743,6 +3610,8 @@
         defaultOrMaker: MethodOptions_IdempotencyLevel.IDEMPOTENCY_UNKNOWN,
         valueOf: MethodOptions_IdempotencyLevel.valueOf,
         enumValues: MethodOptions_IdempotencyLevel.values)
+    ..aOM<FeatureSet>(35, _omitFieldNames ? '' : 'features',
+        subBuilder: FeatureSet.create)
     ..pc<UninterpretedOption>(
         999, _omitFieldNames ? '' : 'uninterpretedOption', $pb.PbFieldType.PM,
         subBuilder: UninterpretedOption.create)
@@ -2795,16 +3664,34 @@
   @$pb.TagNumber(34)
   void clearIdempotencyLevel() => $_clearField(34);
 
+  /// Any features defined in the specific edition.
+  /// WARNING: This field should only be used by protobuf plugins or special
+  /// cases like the proto compiler. Other uses are discouraged and
+  /// developers should rely on the protoreflect APIs for their client language.
+  @$pb.TagNumber(35)
+  FeatureSet get features => $_getN(2);
+  @$pb.TagNumber(35)
+  set features(FeatureSet v) {
+    $_setField(35, v);
+  }
+
+  @$pb.TagNumber(35)
+  $core.bool hasFeatures() => $_has(2);
+  @$pb.TagNumber(35)
+  void clearFeatures() => $_clearField(35);
+  @$pb.TagNumber(35)
+  FeatureSet ensureFeatures() => $_ensure(2);
+
   /// The parser stores options it doesn't recognize here. See above.
   @$pb.TagNumber(999)
-  $pb.PbList<UninterpretedOption> get uninterpretedOption => $_getList(2);
+  $pb.PbList<UninterpretedOption> get uninterpretedOption => $_getList(3);
 }
 
 /// The name of the uninterpreted option.  Each string represents a segment in
 /// a dot-separated name.  is_extension is true iff a segment represents an
 /// extension (denoted with parentheses in options specs in .proto files).
-/// E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
-/// "foo.(bar.baz).qux".
+/// E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents
+/// "foo.(bar.baz).moo".
 class UninterpretedOption_NamePart extends $pb.GeneratedMessage {
   factory UninterpretedOption_NamePart({
     $core.String? namePart,
@@ -3048,6 +3935,478 @@
   void clearAggregateValue() => $_clearField(8);
 }
 
+class FeatureSet_VisibilityFeature extends $pb.GeneratedMessage {
+  factory FeatureSet_VisibilityFeature() => create();
+  FeatureSet_VisibilityFeature._() : super();
+  factory FeatureSet_VisibilityFeature.fromBuffer($core.List<$core.int> i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromBuffer(i, r);
+  factory FeatureSet_VisibilityFeature.fromJson($core.String i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(
+      _omitMessageNames ? '' : 'FeatureSet.VisibilityFeature',
+      package:
+          const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'),
+      createEmptyInstance: create)
+    ..hasRequiredFields = false;
+
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  FeatureSet_VisibilityFeature clone() =>
+      FeatureSet_VisibilityFeature()..mergeFromMessage(this);
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  FeatureSet_VisibilityFeature copyWith(
+          void Function(FeatureSet_VisibilityFeature) updates) =>
+      super.copyWith(
+              (message) => updates(message as FeatureSet_VisibilityFeature))
+          as FeatureSet_VisibilityFeature;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static FeatureSet_VisibilityFeature create() =>
+      FeatureSet_VisibilityFeature._();
+  FeatureSet_VisibilityFeature createEmptyInstance() => create();
+  static $pb.PbList<FeatureSet_VisibilityFeature> createRepeated() =>
+      $pb.PbList<FeatureSet_VisibilityFeature>();
+  @$core.pragma('dart2js:noInline')
+  static FeatureSet_VisibilityFeature getDefault() => _defaultInstance ??=
+      $pb.GeneratedMessage.$_defaultFor<FeatureSet_VisibilityFeature>(create);
+  static FeatureSet_VisibilityFeature? _defaultInstance;
+}
+
+/// TODO Enums in C++ gencode (and potentially other languages) are
+/// not well scoped.  This means that each of the feature enums below can clash
+/// with each other.  The short names we've chosen maximize call-site
+/// readability, but leave us very open to this scenario.  A future feature will
+/// be designed and implemented to handle this, hopefully before we ever hit a
+/// conflict here.
+class FeatureSet extends $pb.GeneratedMessage {
+  factory FeatureSet({
+    FeatureSet_FieldPresence? fieldPresence,
+    FeatureSet_EnumType? enumType,
+    FeatureSet_RepeatedFieldEncoding? repeatedFieldEncoding,
+    FeatureSet_Utf8Validation? utf8Validation,
+    FeatureSet_MessageEncoding? messageEncoding,
+    FeatureSet_JsonFormat? jsonFormat,
+    FeatureSet_EnforceNamingStyle? enforceNamingStyle,
+    FeatureSet_VisibilityFeature_DefaultSymbolVisibility?
+        defaultSymbolVisibility,
+  }) {
+    final $result = create();
+    if (fieldPresence != null) {
+      $result.fieldPresence = fieldPresence;
+    }
+    if (enumType != null) {
+      $result.enumType = enumType;
+    }
+    if (repeatedFieldEncoding != null) {
+      $result.repeatedFieldEncoding = repeatedFieldEncoding;
+    }
+    if (utf8Validation != null) {
+      $result.utf8Validation = utf8Validation;
+    }
+    if (messageEncoding != null) {
+      $result.messageEncoding = messageEncoding;
+    }
+    if (jsonFormat != null) {
+      $result.jsonFormat = jsonFormat;
+    }
+    if (enforceNamingStyle != null) {
+      $result.enforceNamingStyle = enforceNamingStyle;
+    }
+    if (defaultSymbolVisibility != null) {
+      $result.defaultSymbolVisibility = defaultSymbolVisibility;
+    }
+    return $result;
+  }
+  FeatureSet._() : super();
+  factory FeatureSet.fromBuffer($core.List<$core.int> i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromBuffer(i, r);
+  factory FeatureSet.fromJson($core.String i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(
+      _omitMessageNames ? '' : 'FeatureSet',
+      package:
+          const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'),
+      createEmptyInstance: create)
+    ..e<FeatureSet_FieldPresence>(
+        1, _omitFieldNames ? '' : 'fieldPresence', $pb.PbFieldType.OE,
+        defaultOrMaker: FeatureSet_FieldPresence.FIELD_PRESENCE_UNKNOWN,
+        valueOf: FeatureSet_FieldPresence.valueOf,
+        enumValues: FeatureSet_FieldPresence.values)
+    ..e<FeatureSet_EnumType>(
+        2, _omitFieldNames ? '' : 'enumType', $pb.PbFieldType.OE,
+        defaultOrMaker: FeatureSet_EnumType.ENUM_TYPE_UNKNOWN,
+        valueOf: FeatureSet_EnumType.valueOf,
+        enumValues: FeatureSet_EnumType.values)
+    ..e<FeatureSet_RepeatedFieldEncoding>(
+        3, _omitFieldNames ? '' : 'repeatedFieldEncoding', $pb.PbFieldType.OE,
+        defaultOrMaker:
+            FeatureSet_RepeatedFieldEncoding.REPEATED_FIELD_ENCODING_UNKNOWN,
+        valueOf: FeatureSet_RepeatedFieldEncoding.valueOf,
+        enumValues: FeatureSet_RepeatedFieldEncoding.values)
+    ..e<FeatureSet_Utf8Validation>(
+        4, _omitFieldNames ? '' : 'utf8Validation', $pb.PbFieldType.OE,
+        defaultOrMaker: FeatureSet_Utf8Validation.UTF8_VALIDATION_UNKNOWN,
+        valueOf: FeatureSet_Utf8Validation.valueOf,
+        enumValues: FeatureSet_Utf8Validation.values)
+    ..e<FeatureSet_MessageEncoding>(
+        5, _omitFieldNames ? '' : 'messageEncoding', $pb.PbFieldType.OE,
+        defaultOrMaker: FeatureSet_MessageEncoding.MESSAGE_ENCODING_UNKNOWN,
+        valueOf: FeatureSet_MessageEncoding.valueOf,
+        enumValues: FeatureSet_MessageEncoding.values)
+    ..e<FeatureSet_JsonFormat>(
+        6, _omitFieldNames ? '' : 'jsonFormat', $pb.PbFieldType.OE,
+        defaultOrMaker: FeatureSet_JsonFormat.JSON_FORMAT_UNKNOWN,
+        valueOf: FeatureSet_JsonFormat.valueOf,
+        enumValues: FeatureSet_JsonFormat.values)
+    ..e<FeatureSet_EnforceNamingStyle>(
+        7, _omitFieldNames ? '' : 'enforceNamingStyle', $pb.PbFieldType.OE,
+        defaultOrMaker:
+            FeatureSet_EnforceNamingStyle.ENFORCE_NAMING_STYLE_UNKNOWN,
+        valueOf: FeatureSet_EnforceNamingStyle.valueOf,
+        enumValues: FeatureSet_EnforceNamingStyle.values)
+    ..e<FeatureSet_VisibilityFeature_DefaultSymbolVisibility>(
+        8, _omitFieldNames ? '' : 'defaultSymbolVisibility', $pb.PbFieldType.OE,
+        defaultOrMaker: FeatureSet_VisibilityFeature_DefaultSymbolVisibility
+            .DEFAULT_SYMBOL_VISIBILITY_UNKNOWN,
+        valueOf: FeatureSet_VisibilityFeature_DefaultSymbolVisibility.valueOf,
+        enumValues: FeatureSet_VisibilityFeature_DefaultSymbolVisibility.values)
+    ..hasExtensions = true;
+
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  FeatureSet clone() => FeatureSet()..mergeFromMessage(this);
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  FeatureSet copyWith(void Function(FeatureSet) updates) =>
+      super.copyWith((message) => updates(message as FeatureSet)) as FeatureSet;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static FeatureSet create() => FeatureSet._();
+  FeatureSet createEmptyInstance() => create();
+  static $pb.PbList<FeatureSet> createRepeated() => $pb.PbList<FeatureSet>();
+  @$core.pragma('dart2js:noInline')
+  static FeatureSet getDefault() => _defaultInstance ??=
+      $pb.GeneratedMessage.$_defaultFor<FeatureSet>(create);
+  static FeatureSet? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  FeatureSet_FieldPresence get fieldPresence => $_getN(0);
+  @$pb.TagNumber(1)
+  set fieldPresence(FeatureSet_FieldPresence v) {
+    $_setField(1, v);
+  }
+
+  @$pb.TagNumber(1)
+  $core.bool hasFieldPresence() => $_has(0);
+  @$pb.TagNumber(1)
+  void clearFieldPresence() => $_clearField(1);
+
+  @$pb.TagNumber(2)
+  FeatureSet_EnumType get enumType => $_getN(1);
+  @$pb.TagNumber(2)
+  set enumType(FeatureSet_EnumType v) {
+    $_setField(2, v);
+  }
+
+  @$pb.TagNumber(2)
+  $core.bool hasEnumType() => $_has(1);
+  @$pb.TagNumber(2)
+  void clearEnumType() => $_clearField(2);
+
+  @$pb.TagNumber(3)
+  FeatureSet_RepeatedFieldEncoding get repeatedFieldEncoding => $_getN(2);
+  @$pb.TagNumber(3)
+  set repeatedFieldEncoding(FeatureSet_RepeatedFieldEncoding v) {
+    $_setField(3, v);
+  }
+
+  @$pb.TagNumber(3)
+  $core.bool hasRepeatedFieldEncoding() => $_has(2);
+  @$pb.TagNumber(3)
+  void clearRepeatedFieldEncoding() => $_clearField(3);
+
+  @$pb.TagNumber(4)
+  FeatureSet_Utf8Validation get utf8Validation => $_getN(3);
+  @$pb.TagNumber(4)
+  set utf8Validation(FeatureSet_Utf8Validation v) {
+    $_setField(4, v);
+  }
+
+  @$pb.TagNumber(4)
+  $core.bool hasUtf8Validation() => $_has(3);
+  @$pb.TagNumber(4)
+  void clearUtf8Validation() => $_clearField(4);
+
+  @$pb.TagNumber(5)
+  FeatureSet_MessageEncoding get messageEncoding => $_getN(4);
+  @$pb.TagNumber(5)
+  set messageEncoding(FeatureSet_MessageEncoding v) {
+    $_setField(5, v);
+  }
+
+  @$pb.TagNumber(5)
+  $core.bool hasMessageEncoding() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearMessageEncoding() => $_clearField(5);
+
+  @$pb.TagNumber(6)
+  FeatureSet_JsonFormat get jsonFormat => $_getN(5);
+  @$pb.TagNumber(6)
+  set jsonFormat(FeatureSet_JsonFormat v) {
+    $_setField(6, v);
+  }
+
+  @$pb.TagNumber(6)
+  $core.bool hasJsonFormat() => $_has(5);
+  @$pb.TagNumber(6)
+  void clearJsonFormat() => $_clearField(6);
+
+  @$pb.TagNumber(7)
+  FeatureSet_EnforceNamingStyle get enforceNamingStyle => $_getN(6);
+  @$pb.TagNumber(7)
+  set enforceNamingStyle(FeatureSet_EnforceNamingStyle v) {
+    $_setField(7, v);
+  }
+
+  @$pb.TagNumber(7)
+  $core.bool hasEnforceNamingStyle() => $_has(6);
+  @$pb.TagNumber(7)
+  void clearEnforceNamingStyle() => $_clearField(7);
+
+  @$pb.TagNumber(8)
+  FeatureSet_VisibilityFeature_DefaultSymbolVisibility
+      get defaultSymbolVisibility => $_getN(7);
+  @$pb.TagNumber(8)
+  set defaultSymbolVisibility(
+      FeatureSet_VisibilityFeature_DefaultSymbolVisibility v) {
+    $_setField(8, v);
+  }
+
+  @$pb.TagNumber(8)
+  $core.bool hasDefaultSymbolVisibility() => $_has(7);
+  @$pb.TagNumber(8)
+  void clearDefaultSymbolVisibility() => $_clearField(8);
+}
+
+/// A map from every known edition with a unique set of defaults to its
+/// defaults. Not all editions may be contained here.  For a given edition,
+/// the defaults at the closest matching edition ordered at or before it should
+/// be used.  This field must be in strict ascending order by edition.
+class FeatureSetDefaults_FeatureSetEditionDefault extends $pb.GeneratedMessage {
+  factory FeatureSetDefaults_FeatureSetEditionDefault({
+    Edition? edition,
+    FeatureSet? overridableFeatures,
+    FeatureSet? fixedFeatures,
+  }) {
+    final $result = create();
+    if (edition != null) {
+      $result.edition = edition;
+    }
+    if (overridableFeatures != null) {
+      $result.overridableFeatures = overridableFeatures;
+    }
+    if (fixedFeatures != null) {
+      $result.fixedFeatures = fixedFeatures;
+    }
+    return $result;
+  }
+  FeatureSetDefaults_FeatureSetEditionDefault._() : super();
+  factory FeatureSetDefaults_FeatureSetEditionDefault.fromBuffer(
+          $core.List<$core.int> i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromBuffer(i, r);
+  factory FeatureSetDefaults_FeatureSetEditionDefault.fromJson($core.String i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(
+      _omitMessageNames ? '' : 'FeatureSetDefaults.FeatureSetEditionDefault',
+      package:
+          const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'),
+      createEmptyInstance: create)
+    ..e<Edition>(3, _omitFieldNames ? '' : 'edition', $pb.PbFieldType.OE,
+        defaultOrMaker: Edition.EDITION_UNKNOWN,
+        valueOf: Edition.valueOf,
+        enumValues: Edition.values)
+    ..aOM<FeatureSet>(4, _omitFieldNames ? '' : 'overridableFeatures',
+        subBuilder: FeatureSet.create)
+    ..aOM<FeatureSet>(5, _omitFieldNames ? '' : 'fixedFeatures',
+        subBuilder: FeatureSet.create);
+
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  FeatureSetDefaults_FeatureSetEditionDefault clone() =>
+      FeatureSetDefaults_FeatureSetEditionDefault()..mergeFromMessage(this);
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  FeatureSetDefaults_FeatureSetEditionDefault copyWith(
+          void Function(FeatureSetDefaults_FeatureSetEditionDefault) updates) =>
+      super.copyWith((message) =>
+              updates(message as FeatureSetDefaults_FeatureSetEditionDefault))
+          as FeatureSetDefaults_FeatureSetEditionDefault;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static FeatureSetDefaults_FeatureSetEditionDefault create() =>
+      FeatureSetDefaults_FeatureSetEditionDefault._();
+  FeatureSetDefaults_FeatureSetEditionDefault createEmptyInstance() => create();
+  static $pb.PbList<FeatureSetDefaults_FeatureSetEditionDefault>
+      createRepeated() =>
+          $pb.PbList<FeatureSetDefaults_FeatureSetEditionDefault>();
+  @$core.pragma('dart2js:noInline')
+  static FeatureSetDefaults_FeatureSetEditionDefault getDefault() =>
+      _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<
+          FeatureSetDefaults_FeatureSetEditionDefault>(create);
+  static FeatureSetDefaults_FeatureSetEditionDefault? _defaultInstance;
+
+  @$pb.TagNumber(3)
+  Edition get edition => $_getN(0);
+  @$pb.TagNumber(3)
+  set edition(Edition v) {
+    $_setField(3, v);
+  }
+
+  @$pb.TagNumber(3)
+  $core.bool hasEdition() => $_has(0);
+  @$pb.TagNumber(3)
+  void clearEdition() => $_clearField(3);
+
+  /// Defaults of features that can be overridden in this edition.
+  @$pb.TagNumber(4)
+  FeatureSet get overridableFeatures => $_getN(1);
+  @$pb.TagNumber(4)
+  set overridableFeatures(FeatureSet v) {
+    $_setField(4, v);
+  }
+
+  @$pb.TagNumber(4)
+  $core.bool hasOverridableFeatures() => $_has(1);
+  @$pb.TagNumber(4)
+  void clearOverridableFeatures() => $_clearField(4);
+  @$pb.TagNumber(4)
+  FeatureSet ensureOverridableFeatures() => $_ensure(1);
+
+  /// Defaults of features that can't be overridden in this edition.
+  @$pb.TagNumber(5)
+  FeatureSet get fixedFeatures => $_getN(2);
+  @$pb.TagNumber(5)
+  set fixedFeatures(FeatureSet v) {
+    $_setField(5, v);
+  }
+
+  @$pb.TagNumber(5)
+  $core.bool hasFixedFeatures() => $_has(2);
+  @$pb.TagNumber(5)
+  void clearFixedFeatures() => $_clearField(5);
+  @$pb.TagNumber(5)
+  FeatureSet ensureFixedFeatures() => $_ensure(2);
+}
+
+/// A compiled specification for the defaults of a set of features.  These
+/// messages are generated from FeatureSet extensions and can be used to seed
+/// feature resolution. The resolution with this object becomes a simple search
+/// for the closest matching edition, followed by proto merges.
+class FeatureSetDefaults extends $pb.GeneratedMessage {
+  factory FeatureSetDefaults({
+    $core.Iterable<FeatureSetDefaults_FeatureSetEditionDefault>? defaults,
+    Edition? minimumEdition,
+    Edition? maximumEdition,
+  }) {
+    final $result = create();
+    if (defaults != null) {
+      $result.defaults.addAll(defaults);
+    }
+    if (minimumEdition != null) {
+      $result.minimumEdition = minimumEdition;
+    }
+    if (maximumEdition != null) {
+      $result.maximumEdition = maximumEdition;
+    }
+    return $result;
+  }
+  FeatureSetDefaults._() : super();
+  factory FeatureSetDefaults.fromBuffer($core.List<$core.int> i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromBuffer(i, r);
+  factory FeatureSetDefaults.fromJson($core.String i,
+          [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) =>
+      create()..mergeFromJson(i, r);
+
+  static final $pb.BuilderInfo _i = $pb.BuilderInfo(
+      _omitMessageNames ? '' : 'FeatureSetDefaults',
+      package:
+          const $pb.PackageName(_omitMessageNames ? '' : 'google.protobuf'),
+      createEmptyInstance: create)
+    ..pc<FeatureSetDefaults_FeatureSetEditionDefault>(
+        1, _omitFieldNames ? '' : 'defaults', $pb.PbFieldType.PM,
+        subBuilder: FeatureSetDefaults_FeatureSetEditionDefault.create)
+    ..e<Edition>(4, _omitFieldNames ? '' : 'minimumEdition', $pb.PbFieldType.OE,
+        defaultOrMaker: Edition.EDITION_UNKNOWN,
+        valueOf: Edition.valueOf,
+        enumValues: Edition.values)
+    ..e<Edition>(5, _omitFieldNames ? '' : 'maximumEdition', $pb.PbFieldType.OE,
+        defaultOrMaker: Edition.EDITION_UNKNOWN,
+        valueOf: Edition.valueOf,
+        enumValues: Edition.values);
+
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  FeatureSetDefaults clone() => FeatureSetDefaults()..mergeFromMessage(this);
+  @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
+  FeatureSetDefaults copyWith(void Function(FeatureSetDefaults) updates) =>
+      super.copyWith((message) => updates(message as FeatureSetDefaults))
+          as FeatureSetDefaults;
+
+  $pb.BuilderInfo get info_ => _i;
+
+  @$core.pragma('dart2js:noInline')
+  static FeatureSetDefaults create() => FeatureSetDefaults._();
+  FeatureSetDefaults createEmptyInstance() => create();
+  static $pb.PbList<FeatureSetDefaults> createRepeated() =>
+      $pb.PbList<FeatureSetDefaults>();
+  @$core.pragma('dart2js:noInline')
+  static FeatureSetDefaults getDefault() => _defaultInstance ??=
+      $pb.GeneratedMessage.$_defaultFor<FeatureSetDefaults>(create);
+  static FeatureSetDefaults? _defaultInstance;
+
+  @$pb.TagNumber(1)
+  $pb.PbList<FeatureSetDefaults_FeatureSetEditionDefault> get defaults =>
+      $_getList(0);
+
+  /// The minimum supported edition (inclusive) when this was constructed.
+  /// Editions before this will not have defaults.
+  @$pb.TagNumber(4)
+  Edition get minimumEdition => $_getN(1);
+  @$pb.TagNumber(4)
+  set minimumEdition(Edition v) {
+    $_setField(4, v);
+  }
+
+  @$pb.TagNumber(4)
+  $core.bool hasMinimumEdition() => $_has(1);
+  @$pb.TagNumber(4)
+  void clearMinimumEdition() => $_clearField(4);
+
+  /// The maximum known edition (inclusive) when this was constructed. Editions
+  /// after this will not have reliable defaults.
+  @$pb.TagNumber(5)
+  Edition get maximumEdition => $_getN(2);
+  @$pb.TagNumber(5)
+  set maximumEdition(Edition v) {
+    $_setField(5, v);
+  }
+
+  @$pb.TagNumber(5)
+  $core.bool hasMaximumEdition() => $_has(2);
+  @$pb.TagNumber(5)
+  void clearMaximumEdition() => $_clearField(5);
+}
+
 class SourceCodeInfo_Location extends $pb.GeneratedMessage {
   factory SourceCodeInfo_Location({
     $core.Iterable<$core.int>? path,
@@ -3119,8 +4478,8 @@
   /// location.
   ///
   /// Each element is a field number or an index.  They form a path from
-  /// the root FileDescriptorProto to the place where the definition.  For
-  /// example, this path:
+  /// the root FileDescriptorProto to the place where the definition appears.
+  /// For example, this path:
   ///   [ 4, 3, 2, 7, 1 ]
   /// refers to:
   ///   file.message_type(3)  // 4, 3
@@ -3176,13 +4535,13 @@
   ///   // Comment attached to baz.
   ///   // Another line attached to baz.
   ///
-  ///   // Comment attached to qux.
+  ///   // Comment attached to moo.
   ///   //
-  ///   // Another line attached to qux.
-  ///   optional double qux = 4;
+  ///   // Another line attached to moo.
+  ///   optional double moo = 4;
   ///
   ///   // Detached comment for corge. This is not leading or trailing comments
-  ///   // to qux or corge because there are blank lines separating it from
+  ///   // to moo or corge because there are blank lines separating it from
   ///   // both.
   ///
   ///   // Detached comment for corge paragraph 2.
@@ -3252,7 +4611,7 @@
     ..pc<SourceCodeInfo_Location>(
         1, _omitFieldNames ? '' : 'location', $pb.PbFieldType.PM,
         subBuilder: SourceCodeInfo_Location.create)
-    ..hasRequiredFields = false;
+    ..hasExtensions = true;
 
   @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
   SourceCodeInfo clone() => SourceCodeInfo()..mergeFromMessage(this);
@@ -3326,6 +4685,7 @@
     $core.String? sourceFile,
     $core.int? begin,
     $core.int? end,
+    GeneratedCodeInfo_Annotation_Semantic? semantic,
   }) {
     final $result = create();
     if (path != null) {
@@ -3340,6 +4700,9 @@
     if (end != null) {
       $result.end = end;
     }
+    if (semantic != null) {
+      $result.semantic = semantic;
+    }
     return $result;
   }
   GeneratedCodeInfo_Annotation._() : super();
@@ -3359,6 +4722,11 @@
     ..aOS(2, _omitFieldNames ? '' : 'sourceFile')
     ..a<$core.int>(3, _omitFieldNames ? '' : 'begin', $pb.PbFieldType.O3)
     ..a<$core.int>(4, _omitFieldNames ? '' : 'end', $pb.PbFieldType.O3)
+    ..e<GeneratedCodeInfo_Annotation_Semantic>(
+        5, _omitFieldNames ? '' : 'semantic', $pb.PbFieldType.OE,
+        defaultOrMaker: GeneratedCodeInfo_Annotation_Semantic.NONE,
+        valueOf: GeneratedCodeInfo_Annotation_Semantic.valueOf,
+        enumValues: GeneratedCodeInfo_Annotation_Semantic.values)
     ..hasRequiredFields = false;
 
   @$core.Deprecated('See https://github.com/google/protobuf.dart/issues/998.')
@@ -3417,7 +4785,7 @@
   void clearBegin() => $_clearField(3);
 
   /// Identifies the ending offset in bytes in the generated code that
-  /// relates to the identified offset. The end offset should be one past
+  /// relates to the identified object. The end offset should be one past
   /// the last relevant byte (so the length of the text = end - begin).
   @$pb.TagNumber(4)
   $core.int get end => $_getIZ(3);
@@ -3430,6 +4798,18 @@
   $core.bool hasEnd() => $_has(3);
   @$pb.TagNumber(4)
   void clearEnd() => $_clearField(4);
+
+  @$pb.TagNumber(5)
+  GeneratedCodeInfo_Annotation_Semantic get semantic => $_getN(4);
+  @$pb.TagNumber(5)
+  set semantic(GeneratedCodeInfo_Annotation_Semantic v) {
+    $_setField(5, v);
+  }
+
+  @$pb.TagNumber(5)
+  $core.bool hasSemantic() => $_has(4);
+  @$pb.TagNumber(5)
+  void clearSemantic() => $_clearField(5);
 }
 
 /// Describes the relationship between generated code and its original source
diff --git a/protoc_plugin/lib/src/gen/google/protobuf/descriptor.pbenum.dart b/protoc_plugin/lib/src/gen/google/protobuf/descriptor.pbenum.dart
index f7ca7b8..362e0c3 100644
--- a/protoc_plugin/lib/src/gen/google/protobuf/descriptor.pbenum.dart
+++ b/protoc_plugin/lib/src/gen/google/protobuf/descriptor.pbenum.dart
@@ -13,6 +13,126 @@
 
 import 'package:protobuf/protobuf.dart' as $pb;
 
+/// The full set of known editions.
+class Edition extends $pb.ProtobufEnum {
+  /// A placeholder for an unknown edition value.
+  static const Edition EDITION_UNKNOWN =
+      Edition._(0, _omitEnumNames ? '' : 'EDITION_UNKNOWN');
+
+  /// A placeholder edition for specifying default behaviors *before* a feature
+  /// was first introduced.  This is effectively an "infinite past".
+  static const Edition EDITION_LEGACY =
+      Edition._(900, _omitEnumNames ? '' : 'EDITION_LEGACY');
+
+  /// Legacy syntax "editions".  These pre-date editions, but behave much like
+  /// distinct editions.  These can't be used to specify the edition of proto
+  /// files, but feature definitions must supply proto2/proto3 defaults for
+  /// backwards compatibility.
+  static const Edition EDITION_PROTO2 =
+      Edition._(998, _omitEnumNames ? '' : 'EDITION_PROTO2');
+  static const Edition EDITION_PROTO3 =
+      Edition._(999, _omitEnumNames ? '' : 'EDITION_PROTO3');
+
+  /// Editions that have been released.  The specific values are arbitrary and
+  /// should not be depended on, but they will always be time-ordered for easy
+  /// comparison.
+  static const Edition EDITION_2023 =
+      Edition._(1000, _omitEnumNames ? '' : 'EDITION_2023');
+  static const Edition EDITION_2024 =
+      Edition._(1001, _omitEnumNames ? '' : 'EDITION_2024');
+
+  /// Placeholder editions for testing feature resolution.  These should not be
+  /// used or relied on outside of tests.
+  static const Edition EDITION_1_TEST_ONLY =
+      Edition._(1, _omitEnumNames ? '' : 'EDITION_1_TEST_ONLY');
+  static const Edition EDITION_2_TEST_ONLY =
+      Edition._(2, _omitEnumNames ? '' : 'EDITION_2_TEST_ONLY');
+  static const Edition EDITION_99997_TEST_ONLY =
+      Edition._(99997, _omitEnumNames ? '' : 'EDITION_99997_TEST_ONLY');
+  static const Edition EDITION_99998_TEST_ONLY =
+      Edition._(99998, _omitEnumNames ? '' : 'EDITION_99998_TEST_ONLY');
+  static const Edition EDITION_99999_TEST_ONLY =
+      Edition._(99999, _omitEnumNames ? '' : 'EDITION_99999_TEST_ONLY');
+
+  /// Placeholder for specifying unbounded edition support.  This should only
+  /// ever be used by plugins that can expect to never require any changes to
+  /// support a new edition.
+  static const Edition EDITION_MAX =
+      Edition._(2147483647, _omitEnumNames ? '' : 'EDITION_MAX');
+
+  static const $core.List<Edition> values = <Edition>[
+    EDITION_UNKNOWN,
+    EDITION_LEGACY,
+    EDITION_PROTO2,
+    EDITION_PROTO3,
+    EDITION_2023,
+    EDITION_2024,
+    EDITION_1_TEST_ONLY,
+    EDITION_2_TEST_ONLY,
+    EDITION_99997_TEST_ONLY,
+    EDITION_99998_TEST_ONLY,
+    EDITION_99999_TEST_ONLY,
+    EDITION_MAX,
+  ];
+
+  static final $core.Map<$core.int, Edition> _byValue =
+      $pb.ProtobufEnum.initByValue(values);
+  static Edition? valueOf($core.int value) => _byValue[value];
+
+  const Edition._(super.v, super.n);
+}
+
+/// Describes the 'visibility' of a symbol with respect to the proto import
+/// system. Symbols can only be imported when the visibility rules do not prevent
+/// it (ex: local symbols cannot be imported).  Visibility modifiers can only set
+/// on `message` and `enum` as they are the only types available to be referenced
+/// from other files.
+class SymbolVisibility extends $pb.ProtobufEnum {
+  static const SymbolVisibility VISIBILITY_UNSET =
+      SymbolVisibility._(0, _omitEnumNames ? '' : 'VISIBILITY_UNSET');
+  static const SymbolVisibility VISIBILITY_LOCAL =
+      SymbolVisibility._(1, _omitEnumNames ? '' : 'VISIBILITY_LOCAL');
+  static const SymbolVisibility VISIBILITY_EXPORT =
+      SymbolVisibility._(2, _omitEnumNames ? '' : 'VISIBILITY_EXPORT');
+
+  static const $core.List<SymbolVisibility> values = <SymbolVisibility>[
+    VISIBILITY_UNSET,
+    VISIBILITY_LOCAL,
+    VISIBILITY_EXPORT,
+  ];
+
+  static final $core.List<SymbolVisibility?> _byValue =
+      $pb.ProtobufEnum.$_initByValueList(values, 2);
+  static SymbolVisibility? valueOf($core.int value) =>
+      value < 0 || value >= _byValue.length ? null : _byValue[value];
+
+  const SymbolVisibility._(super.v, super.n);
+}
+
+/// The verification state of the extension range.
+class ExtensionRangeOptions_VerificationState extends $pb.ProtobufEnum {
+  /// All the extensions of the range must be declared.
+  static const ExtensionRangeOptions_VerificationState DECLARATION =
+      ExtensionRangeOptions_VerificationState._(
+          0, _omitEnumNames ? '' : 'DECLARATION');
+  static const ExtensionRangeOptions_VerificationState UNVERIFIED =
+      ExtensionRangeOptions_VerificationState._(
+          1, _omitEnumNames ? '' : 'UNVERIFIED');
+
+  static const $core.List<ExtensionRangeOptions_VerificationState> values =
+      <ExtensionRangeOptions_VerificationState>[
+    DECLARATION,
+    UNVERIFIED,
+  ];
+
+  static final $core.List<ExtensionRangeOptions_VerificationState?> _byValue =
+      $pb.ProtobufEnum.$_initByValueList(values, 1);
+  static ExtensionRangeOptions_VerificationState? valueOf($core.int value) =>
+      value < 0 || value >= _byValue.length ? null : _byValue[value];
+
+  const ExtensionRangeOptions_VerificationState._(super.v, super.n);
+}
+
 class FieldDescriptorProto_Type extends $pb.ProtobufEnum {
   /// 0 is reserved for errors.
   /// Order is weird for historical reasons.
@@ -42,9 +162,10 @@
       FieldDescriptorProto_Type._(9, _omitEnumNames ? '' : 'TYPE_STRING');
 
   /// Tag-delimited aggregate.
-  /// Group type is deprecated and not supported in proto3. However, Proto3
+  /// Group type is deprecated and not supported after google.protobuf. However, Proto3
   /// implementations should still be able to parse the group wire format and
-  /// treat group fields as unknown fields.
+  /// treat group fields as unknown fields.  In Editions, the group wire format
+  /// can be enabled via the `message_encoding` feature.
   static const FieldDescriptorProto_Type TYPE_GROUP =
       FieldDescriptorProto_Type._(10, _omitEnumNames ? '' : 'TYPE_GROUP');
   static const FieldDescriptorProto_Type TYPE_MESSAGE =
@@ -100,16 +221,20 @@
   /// 0 is reserved for errors
   static const FieldDescriptorProto_Label LABEL_OPTIONAL =
       FieldDescriptorProto_Label._(1, _omitEnumNames ? '' : 'LABEL_OPTIONAL');
-  static const FieldDescriptorProto_Label LABEL_REQUIRED =
-      FieldDescriptorProto_Label._(2, _omitEnumNames ? '' : 'LABEL_REQUIRED');
   static const FieldDescriptorProto_Label LABEL_REPEATED =
       FieldDescriptorProto_Label._(3, _omitEnumNames ? '' : 'LABEL_REPEATED');
 
+  /// The required label is only allowed in google.protobuf.  In proto3 and Editions
+  /// it's explicitly prohibited.  In Editions, the `field_presence` feature
+  /// can be used to get this behavior.
+  static const FieldDescriptorProto_Label LABEL_REQUIRED =
+      FieldDescriptorProto_Label._(2, _omitEnumNames ? '' : 'LABEL_REQUIRED');
+
   static const $core.List<FieldDescriptorProto_Label> values =
       <FieldDescriptorProto_Label>[
     LABEL_OPTIONAL,
-    LABEL_REQUIRED,
     LABEL_REPEATED,
+    LABEL_REQUIRED,
   ];
 
   static final $core.List<FieldDescriptorProto_Label?> _byValue =
@@ -150,6 +275,13 @@
   /// Default mode.
   static const FieldOptions_CType STRING =
       FieldOptions_CType._(0, _omitEnumNames ? '' : 'STRING');
+
+  /// The option [ctype=CORD] may be applied to a non-repeated field of type
+  /// "bytes". It indicates that in C++, the data should be stored in a Cord
+  /// instead of a string.  For very large strings, this may reduce memory
+  /// fragmentation. It may also allow better performance when parsing from a
+  /// Cord, or when parsing with aliasing enabled, as the parsed Cord may then
+  /// alias the original buffer.
   static const FieldOptions_CType CORD =
       FieldOptions_CType._(1, _omitEnumNames ? '' : 'CORD');
   static const FieldOptions_CType STRING_PIECE =
@@ -196,6 +328,90 @@
   const FieldOptions_JSType._(super.v, super.n);
 }
 
+/// If set to RETENTION_SOURCE, the option will be omitted from the binary.
+class FieldOptions_OptionRetention extends $pb.ProtobufEnum {
+  static const FieldOptions_OptionRetention RETENTION_UNKNOWN =
+      FieldOptions_OptionRetention._(
+          0, _omitEnumNames ? '' : 'RETENTION_UNKNOWN');
+  static const FieldOptions_OptionRetention RETENTION_RUNTIME =
+      FieldOptions_OptionRetention._(
+          1, _omitEnumNames ? '' : 'RETENTION_RUNTIME');
+  static const FieldOptions_OptionRetention RETENTION_SOURCE =
+      FieldOptions_OptionRetention._(
+          2, _omitEnumNames ? '' : 'RETENTION_SOURCE');
+
+  static const $core.List<FieldOptions_OptionRetention> values =
+      <FieldOptions_OptionRetention>[
+    RETENTION_UNKNOWN,
+    RETENTION_RUNTIME,
+    RETENTION_SOURCE,
+  ];
+
+  static final $core.List<FieldOptions_OptionRetention?> _byValue =
+      $pb.ProtobufEnum.$_initByValueList(values, 2);
+  static FieldOptions_OptionRetention? valueOf($core.int value) =>
+      value < 0 || value >= _byValue.length ? null : _byValue[value];
+
+  const FieldOptions_OptionRetention._(super.v, super.n);
+}
+
+/// This indicates the types of entities that the field may apply to when used
+/// as an option. If it is unset, then the field may be freely used as an
+/// option on any kind of entity.
+class FieldOptions_OptionTargetType extends $pb.ProtobufEnum {
+  static const FieldOptions_OptionTargetType TARGET_TYPE_UNKNOWN =
+      FieldOptions_OptionTargetType._(
+          0, _omitEnumNames ? '' : 'TARGET_TYPE_UNKNOWN');
+  static const FieldOptions_OptionTargetType TARGET_TYPE_FILE =
+      FieldOptions_OptionTargetType._(
+          1, _omitEnumNames ? '' : 'TARGET_TYPE_FILE');
+  static const FieldOptions_OptionTargetType TARGET_TYPE_EXTENSION_RANGE =
+      FieldOptions_OptionTargetType._(
+          2, _omitEnumNames ? '' : 'TARGET_TYPE_EXTENSION_RANGE');
+  static const FieldOptions_OptionTargetType TARGET_TYPE_MESSAGE =
+      FieldOptions_OptionTargetType._(
+          3, _omitEnumNames ? '' : 'TARGET_TYPE_MESSAGE');
+  static const FieldOptions_OptionTargetType TARGET_TYPE_FIELD =
+      FieldOptions_OptionTargetType._(
+          4, _omitEnumNames ? '' : 'TARGET_TYPE_FIELD');
+  static const FieldOptions_OptionTargetType TARGET_TYPE_ONEOF =
+      FieldOptions_OptionTargetType._(
+          5, _omitEnumNames ? '' : 'TARGET_TYPE_ONEOF');
+  static const FieldOptions_OptionTargetType TARGET_TYPE_ENUM =
+      FieldOptions_OptionTargetType._(
+          6, _omitEnumNames ? '' : 'TARGET_TYPE_ENUM');
+  static const FieldOptions_OptionTargetType TARGET_TYPE_ENUM_ENTRY =
+      FieldOptions_OptionTargetType._(
+          7, _omitEnumNames ? '' : 'TARGET_TYPE_ENUM_ENTRY');
+  static const FieldOptions_OptionTargetType TARGET_TYPE_SERVICE =
+      FieldOptions_OptionTargetType._(
+          8, _omitEnumNames ? '' : 'TARGET_TYPE_SERVICE');
+  static const FieldOptions_OptionTargetType TARGET_TYPE_METHOD =
+      FieldOptions_OptionTargetType._(
+          9, _omitEnumNames ? '' : 'TARGET_TYPE_METHOD');
+
+  static const $core.List<FieldOptions_OptionTargetType> values =
+      <FieldOptions_OptionTargetType>[
+    TARGET_TYPE_UNKNOWN,
+    TARGET_TYPE_FILE,
+    TARGET_TYPE_EXTENSION_RANGE,
+    TARGET_TYPE_MESSAGE,
+    TARGET_TYPE_FIELD,
+    TARGET_TYPE_ONEOF,
+    TARGET_TYPE_ENUM,
+    TARGET_TYPE_ENUM_ENTRY,
+    TARGET_TYPE_SERVICE,
+    TARGET_TYPE_METHOD,
+  ];
+
+  static final $core.List<FieldOptions_OptionTargetType?> _byValue =
+      $pb.ProtobufEnum.$_initByValueList(values, 9);
+  static FieldOptions_OptionTargetType? valueOf($core.int value) =>
+      value < 0 || value >= _byValue.length ? null : _byValue[value];
+
+  const FieldOptions_OptionTargetType._(super.v, super.n);
+}
+
 /// Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
 /// or neither? HTTP based RPC implementation may choose GET verb for safe
 /// methods, and PUT verb for idempotent methods instead of the default POST.
@@ -224,4 +440,250 @@
   const MethodOptions_IdempotencyLevel._(super.v, super.n);
 }
 
+class FeatureSet_FieldPresence extends $pb.ProtobufEnum {
+  static const FeatureSet_FieldPresence FIELD_PRESENCE_UNKNOWN =
+      FeatureSet_FieldPresence._(
+          0, _omitEnumNames ? '' : 'FIELD_PRESENCE_UNKNOWN');
+  static const FeatureSet_FieldPresence EXPLICIT =
+      FeatureSet_FieldPresence._(1, _omitEnumNames ? '' : 'EXPLICIT');
+  static const FeatureSet_FieldPresence IMPLICIT =
+      FeatureSet_FieldPresence._(2, _omitEnumNames ? '' : 'IMPLICIT');
+  static const FeatureSet_FieldPresence LEGACY_REQUIRED =
+      FeatureSet_FieldPresence._(3, _omitEnumNames ? '' : 'LEGACY_REQUIRED');
+
+  static const $core.List<FeatureSet_FieldPresence> values =
+      <FeatureSet_FieldPresence>[
+    FIELD_PRESENCE_UNKNOWN,
+    EXPLICIT,
+    IMPLICIT,
+    LEGACY_REQUIRED,
+  ];
+
+  static final $core.List<FeatureSet_FieldPresence?> _byValue =
+      $pb.ProtobufEnum.$_initByValueList(values, 3);
+  static FeatureSet_FieldPresence? valueOf($core.int value) =>
+      value < 0 || value >= _byValue.length ? null : _byValue[value];
+
+  const FeatureSet_FieldPresence._(super.v, super.n);
+}
+
+class FeatureSet_EnumType extends $pb.ProtobufEnum {
+  static const FeatureSet_EnumType ENUM_TYPE_UNKNOWN =
+      FeatureSet_EnumType._(0, _omitEnumNames ? '' : 'ENUM_TYPE_UNKNOWN');
+  static const FeatureSet_EnumType OPEN =
+      FeatureSet_EnumType._(1, _omitEnumNames ? '' : 'OPEN');
+  static const FeatureSet_EnumType CLOSED =
+      FeatureSet_EnumType._(2, _omitEnumNames ? '' : 'CLOSED');
+
+  static const $core.List<FeatureSet_EnumType> values = <FeatureSet_EnumType>[
+    ENUM_TYPE_UNKNOWN,
+    OPEN,
+    CLOSED,
+  ];
+
+  static final $core.List<FeatureSet_EnumType?> _byValue =
+      $pb.ProtobufEnum.$_initByValueList(values, 2);
+  static FeatureSet_EnumType? valueOf($core.int value) =>
+      value < 0 || value >= _byValue.length ? null : _byValue[value];
+
+  const FeatureSet_EnumType._(super.v, super.n);
+}
+
+class FeatureSet_RepeatedFieldEncoding extends $pb.ProtobufEnum {
+  static const FeatureSet_RepeatedFieldEncoding
+      REPEATED_FIELD_ENCODING_UNKNOWN = FeatureSet_RepeatedFieldEncoding._(
+          0, _omitEnumNames ? '' : 'REPEATED_FIELD_ENCODING_UNKNOWN');
+  static const FeatureSet_RepeatedFieldEncoding PACKED =
+      FeatureSet_RepeatedFieldEncoding._(1, _omitEnumNames ? '' : 'PACKED');
+  static const FeatureSet_RepeatedFieldEncoding EXPANDED =
+      FeatureSet_RepeatedFieldEncoding._(2, _omitEnumNames ? '' : 'EXPANDED');
+
+  static const $core.List<FeatureSet_RepeatedFieldEncoding> values =
+      <FeatureSet_RepeatedFieldEncoding>[
+    REPEATED_FIELD_ENCODING_UNKNOWN,
+    PACKED,
+    EXPANDED,
+  ];
+
+  static final $core.List<FeatureSet_RepeatedFieldEncoding?> _byValue =
+      $pb.ProtobufEnum.$_initByValueList(values, 2);
+  static FeatureSet_RepeatedFieldEncoding? valueOf($core.int value) =>
+      value < 0 || value >= _byValue.length ? null : _byValue[value];
+
+  const FeatureSet_RepeatedFieldEncoding._(super.v, super.n);
+}
+
+class FeatureSet_Utf8Validation extends $pb.ProtobufEnum {
+  static const FeatureSet_Utf8Validation UTF8_VALIDATION_UNKNOWN =
+      FeatureSet_Utf8Validation._(
+          0, _omitEnumNames ? '' : 'UTF8_VALIDATION_UNKNOWN');
+  static const FeatureSet_Utf8Validation VERIFY =
+      FeatureSet_Utf8Validation._(2, _omitEnumNames ? '' : 'VERIFY');
+  static const FeatureSet_Utf8Validation NONE =
+      FeatureSet_Utf8Validation._(3, _omitEnumNames ? '' : 'NONE');
+
+  static const $core.List<FeatureSet_Utf8Validation> values =
+      <FeatureSet_Utf8Validation>[
+    UTF8_VALIDATION_UNKNOWN,
+    VERIFY,
+    NONE,
+  ];
+
+  static final $core.List<FeatureSet_Utf8Validation?> _byValue =
+      $pb.ProtobufEnum.$_initByValueList(values, 3);
+  static FeatureSet_Utf8Validation? valueOf($core.int value) =>
+      value < 0 || value >= _byValue.length ? null : _byValue[value];
+
+  const FeatureSet_Utf8Validation._(super.v, super.n);
+}
+
+class FeatureSet_MessageEncoding extends $pb.ProtobufEnum {
+  static const FeatureSet_MessageEncoding MESSAGE_ENCODING_UNKNOWN =
+      FeatureSet_MessageEncoding._(
+          0, _omitEnumNames ? '' : 'MESSAGE_ENCODING_UNKNOWN');
+  static const FeatureSet_MessageEncoding LENGTH_PREFIXED =
+      FeatureSet_MessageEncoding._(1, _omitEnumNames ? '' : 'LENGTH_PREFIXED');
+  static const FeatureSet_MessageEncoding DELIMITED =
+      FeatureSet_MessageEncoding._(2, _omitEnumNames ? '' : 'DELIMITED');
+
+  static const $core.List<FeatureSet_MessageEncoding> values =
+      <FeatureSet_MessageEncoding>[
+    MESSAGE_ENCODING_UNKNOWN,
+    LENGTH_PREFIXED,
+    DELIMITED,
+  ];
+
+  static final $core.List<FeatureSet_MessageEncoding?> _byValue =
+      $pb.ProtobufEnum.$_initByValueList(values, 2);
+  static FeatureSet_MessageEncoding? valueOf($core.int value) =>
+      value < 0 || value >= _byValue.length ? null : _byValue[value];
+
+  const FeatureSet_MessageEncoding._(super.v, super.n);
+}
+
+class FeatureSet_JsonFormat extends $pb.ProtobufEnum {
+  static const FeatureSet_JsonFormat JSON_FORMAT_UNKNOWN =
+      FeatureSet_JsonFormat._(0, _omitEnumNames ? '' : 'JSON_FORMAT_UNKNOWN');
+  static const FeatureSet_JsonFormat ALLOW =
+      FeatureSet_JsonFormat._(1, _omitEnumNames ? '' : 'ALLOW');
+  static const FeatureSet_JsonFormat LEGACY_BEST_EFFORT =
+      FeatureSet_JsonFormat._(2, _omitEnumNames ? '' : 'LEGACY_BEST_EFFORT');
+
+  static const $core.List<FeatureSet_JsonFormat> values =
+      <FeatureSet_JsonFormat>[
+    JSON_FORMAT_UNKNOWN,
+    ALLOW,
+    LEGACY_BEST_EFFORT,
+  ];
+
+  static final $core.List<FeatureSet_JsonFormat?> _byValue =
+      $pb.ProtobufEnum.$_initByValueList(values, 2);
+  static FeatureSet_JsonFormat? valueOf($core.int value) =>
+      value < 0 || value >= _byValue.length ? null : _byValue[value];
+
+  const FeatureSet_JsonFormat._(super.v, super.n);
+}
+
+class FeatureSet_EnforceNamingStyle extends $pb.ProtobufEnum {
+  static const FeatureSet_EnforceNamingStyle ENFORCE_NAMING_STYLE_UNKNOWN =
+      FeatureSet_EnforceNamingStyle._(
+          0, _omitEnumNames ? '' : 'ENFORCE_NAMING_STYLE_UNKNOWN');
+  static const FeatureSet_EnforceNamingStyle STYLE2024 =
+      FeatureSet_EnforceNamingStyle._(1, _omitEnumNames ? '' : 'STYLE2024');
+  static const FeatureSet_EnforceNamingStyle STYLE_LEGACY =
+      FeatureSet_EnforceNamingStyle._(2, _omitEnumNames ? '' : 'STYLE_LEGACY');
+
+  static const $core.List<FeatureSet_EnforceNamingStyle> values =
+      <FeatureSet_EnforceNamingStyle>[
+    ENFORCE_NAMING_STYLE_UNKNOWN,
+    STYLE2024,
+    STYLE_LEGACY,
+  ];
+
+  static final $core.List<FeatureSet_EnforceNamingStyle?> _byValue =
+      $pb.ProtobufEnum.$_initByValueList(values, 2);
+  static FeatureSet_EnforceNamingStyle? valueOf($core.int value) =>
+      value < 0 || value >= _byValue.length ? null : _byValue[value];
+
+  const FeatureSet_EnforceNamingStyle._(super.v, super.n);
+}
+
+class FeatureSet_VisibilityFeature_DefaultSymbolVisibility
+    extends $pb.ProtobufEnum {
+  static const FeatureSet_VisibilityFeature_DefaultSymbolVisibility
+      DEFAULT_SYMBOL_VISIBILITY_UNKNOWN =
+      FeatureSet_VisibilityFeature_DefaultSymbolVisibility._(
+          0, _omitEnumNames ? '' : 'DEFAULT_SYMBOL_VISIBILITY_UNKNOWN');
+
+  /// Default pre-EDITION_2024, all UNSET visibility are export.
+  static const FeatureSet_VisibilityFeature_DefaultSymbolVisibility EXPORT_ALL =
+      FeatureSet_VisibilityFeature_DefaultSymbolVisibility._(
+          1, _omitEnumNames ? '' : 'EXPORT_ALL');
+
+  /// All top-level symbols default to export, nested default to local.
+  static const FeatureSet_VisibilityFeature_DefaultSymbolVisibility
+      EXPORT_TOP_LEVEL = FeatureSet_VisibilityFeature_DefaultSymbolVisibility._(
+          2, _omitEnumNames ? '' : 'EXPORT_TOP_LEVEL');
+
+  /// All symbols default to local.
+  static const FeatureSet_VisibilityFeature_DefaultSymbolVisibility LOCAL_ALL =
+      FeatureSet_VisibilityFeature_DefaultSymbolVisibility._(
+          3, _omitEnumNames ? '' : 'LOCAL_ALL');
+
+  /// All symbols local by default. Nested types cannot be exported.
+  /// With special case caveat for message { enum {} reserved 1 to max; }
+  /// This is the recommended setting for new protos.
+  static const FeatureSet_VisibilityFeature_DefaultSymbolVisibility STRICT =
+      FeatureSet_VisibilityFeature_DefaultSymbolVisibility._(
+          4, _omitEnumNames ? '' : 'STRICT');
+
+  static const $core.List<FeatureSet_VisibilityFeature_DefaultSymbolVisibility>
+      values = <FeatureSet_VisibilityFeature_DefaultSymbolVisibility>[
+    DEFAULT_SYMBOL_VISIBILITY_UNKNOWN,
+    EXPORT_ALL,
+    EXPORT_TOP_LEVEL,
+    LOCAL_ALL,
+    STRICT,
+  ];
+
+  static final $core.List<FeatureSet_VisibilityFeature_DefaultSymbolVisibility?>
+      _byValue = $pb.ProtobufEnum.$_initByValueList(values, 4);
+  static FeatureSet_VisibilityFeature_DefaultSymbolVisibility? valueOf(
+          $core.int value) =>
+      value < 0 || value >= _byValue.length ? null : _byValue[value];
+
+  const FeatureSet_VisibilityFeature_DefaultSymbolVisibility._(
+      super.v, super.n);
+}
+
+/// Represents the identified object's effect on the element in the original
+/// .proto file.
+class GeneratedCodeInfo_Annotation_Semantic extends $pb.ProtobufEnum {
+  /// There is no effect or the effect is indescribable.
+  static const GeneratedCodeInfo_Annotation_Semantic NONE =
+      GeneratedCodeInfo_Annotation_Semantic._(0, _omitEnumNames ? '' : 'NONE');
+
+  /// The element is set or otherwise mutated.
+  static const GeneratedCodeInfo_Annotation_Semantic SET =
+      GeneratedCodeInfo_Annotation_Semantic._(1, _omitEnumNames ? '' : 'SET');
+
+  /// An alias to the element is returned.
+  static const GeneratedCodeInfo_Annotation_Semantic ALIAS =
+      GeneratedCodeInfo_Annotation_Semantic._(2, _omitEnumNames ? '' : 'ALIAS');
+
+  static const $core.List<GeneratedCodeInfo_Annotation_Semantic> values =
+      <GeneratedCodeInfo_Annotation_Semantic>[
+    NONE,
+    SET,
+    ALIAS,
+  ];
+
+  static final $core.List<GeneratedCodeInfo_Annotation_Semantic?> _byValue =
+      $pb.ProtobufEnum.$_initByValueList(values, 2);
+  static GeneratedCodeInfo_Annotation_Semantic? valueOf($core.int value) =>
+      value < 0 || value >= _byValue.length ? null : _byValue[value];
+
+  const GeneratedCodeInfo_Annotation_Semantic._(super.v, super.n);
+}
+
 const _omitEnumNames = $core.bool.fromEnvironment('protobuf.omit_enum_names');
diff --git a/protoc_plugin/protos/README.md b/protoc_plugin/protos/README.md
index 1b430fc..8fe4b02 100644
--- a/protoc_plugin/protos/README.md
+++ b/protoc_plugin/protos/README.md
@@ -17,8 +17,9 @@
 
 ## Updating the protos
 
-The protos are currently updated by hand. We should create a shell script to
-update from the source repos at specific SHAs. In the meantime:
+To update the vendored protos to the most recent versions, run:
+`dart tool/update_protos.dart`. Then, run `make update-pregenerated` to rebuild
+the Dart libraries in `lib/src/gen/`.
 
 The contents of `google/protobuf/` can be found at 
 https://github.com/protocolbuffers/protobuf/tree/main/src/google/protobuf.
diff --git a/protoc_plugin/protos/google/api/routing.proto b/protoc_plugin/protos/google/api/routing.proto
new file mode 100644
index 0000000..4fcb2ac
--- /dev/null
+++ b/protoc_plugin/protos/google/api/routing.proto
@@ -0,0 +1,461 @@
+// 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.api;
+
+import "google/protobuf/descriptor.proto";
+
+option go_package = "google.golang.org/genproto/googleapis/api/annotations;annotations";
+option java_multiple_files = true;
+option java_outer_classname = "RoutingProto";
+option java_package = "com.google.api";
+option objc_class_prefix = "GAPI";
+
+extend google.protobuf.MethodOptions {
+  // See RoutingRule.
+  google.api.RoutingRule routing = 72295729;
+}
+
+// Specifies the routing information that should be sent along with the request
+// in the form of routing header.
+// **NOTE:** All service configuration rules follow the "last one wins" order.
+//
+// The examples below will apply to an RPC which has the following request type:
+//
+// Message Definition:
+//
+//     message Request {
+//       // The name of the Table
+//       // Values can be of the following formats:
+//       // - `projects/<project>/tables/<table>`
+//       // - `projects/<project>/instances/<instance>/tables/<table>`
+//       // - `region/<region>/zones/<zone>/tables/<table>`
+//       string table_name = 1;
+//
+//       // This value specifies routing for replication.
+//       // It can be in the following formats:
+//       // - `profiles/<profile_id>`
+//       // - a legacy `profile_id` that can be any string
+//       string app_profile_id = 2;
+//     }
+//
+// Example message:
+//
+//     {
+//       table_name: projects/proj_foo/instances/instance_bar/table/table_baz,
+//       app_profile_id: profiles/prof_qux
+//     }
+//
+// The routing header consists of one or multiple key-value pairs. Every key
+// and value must be percent-encoded, and joined together in the format of
+// `key1=value1&key2=value2`.
+// The examples below skip the percent-encoding for readability.
+//
+// Example 1
+//
+// Extracting a field from the request to put into the routing header
+// unchanged, with the key equal to the field name.
+//
+// annotation:
+//
+//     option (google.api.routing) = {
+//       // Take the `app_profile_id`.
+//       routing_parameters {
+//         field: "app_profile_id"
+//       }
+//     };
+//
+// result:
+//
+//     x-goog-request-params: app_profile_id=profiles/prof_qux
+//
+// Example 2
+//
+// Extracting a field from the request to put into the routing header
+// unchanged, with the key different from the field name.
+//
+// annotation:
+//
+//     option (google.api.routing) = {
+//       // Take the `app_profile_id`, but name it `routing_id` in the header.
+//       routing_parameters {
+//         field: "app_profile_id"
+//         path_template: "{routing_id=**}"
+//       }
+//     };
+//
+// result:
+//
+//     x-goog-request-params: routing_id=profiles/prof_qux
+//
+// Example 3
+//
+// Extracting a field from the request to put into the routing
+// header, while matching a path template syntax on the field's value.
+//
+// NB: it is more useful to send nothing than to send garbage for the purpose
+// of dynamic routing, since garbage pollutes cache. Thus the matching.
+//
+// Sub-example 3a
+//
+// The field matches the template.
+//
+// annotation:
+//
+//     option (google.api.routing) = {
+//       // Take the `table_name`, if it's well-formed (with project-based
+//       // syntax).
+//       routing_parameters {
+//         field: "table_name"
+//         path_template: "{table_name=projects/*/instances/*/**}"
+//       }
+//     };
+//
+// result:
+//
+//     x-goog-request-params:
+//     table_name=projects/proj_foo/instances/instance_bar/table/table_baz
+//
+// Sub-example 3b
+//
+// The field does not match the template.
+//
+// annotation:
+//
+//     option (google.api.routing) = {
+//       // Take the `table_name`, if it's well-formed (with region-based
+//       // syntax).
+//       routing_parameters {
+//         field: "table_name"
+//         path_template: "{table_name=regions/*/zones/*/**}"
+//       }
+//     };
+//
+// result:
+//
+//     <no routing header will be sent>
+//
+// Sub-example 3c
+//
+// Multiple alternative conflictingly named path templates are
+// specified. The one that matches is used to construct the header.
+//
+// annotation:
+//
+//     option (google.api.routing) = {
+//       // Take the `table_name`, if it's well-formed, whether
+//       // using the region- or projects-based syntax.
+//
+//       routing_parameters {
+//         field: "table_name"
+//         path_template: "{table_name=regions/*/zones/*/**}"
+//       }
+//       routing_parameters {
+//         field: "table_name"
+//         path_template: "{table_name=projects/*/instances/*/**}"
+//       }
+//     };
+//
+// result:
+//
+//     x-goog-request-params:
+//     table_name=projects/proj_foo/instances/instance_bar/table/table_baz
+//
+// Example 4
+//
+// Extracting a single routing header key-value pair by matching a
+// template syntax on (a part of) a single request field.
+//
+// annotation:
+//
+//     option (google.api.routing) = {
+//       // Take just the project id from the `table_name` field.
+//       routing_parameters {
+//         field: "table_name"
+//         path_template: "{routing_id=projects/*}/**"
+//       }
+//     };
+//
+// result:
+//
+//     x-goog-request-params: routing_id=projects/proj_foo
+//
+// Example 5
+//
+// Extracting a single routing header key-value pair by matching
+// several conflictingly named path templates on (parts of) a single request
+// field. The last template to match "wins" the conflict.
+//
+// annotation:
+//
+//     option (google.api.routing) = {
+//       // If the `table_name` does not have instances information,
+//       // take just the project id for routing.
+//       // Otherwise take project + instance.
+//
+//       routing_parameters {
+//         field: "table_name"
+//         path_template: "{routing_id=projects/*}/**"
+//       }
+//       routing_parameters {
+//         field: "table_name"
+//         path_template: "{routing_id=projects/*/instances/*}/**"
+//       }
+//     };
+//
+// result:
+//
+//     x-goog-request-params:
+//     routing_id=projects/proj_foo/instances/instance_bar
+//
+// Example 6
+//
+// Extracting multiple routing header key-value pairs by matching
+// several non-conflicting path templates on (parts of) a single request field.
+//
+// Sub-example 6a
+//
+// Make the templates strict, so that if the `table_name` does not
+// have an instance information, nothing is sent.
+//
+// annotation:
+//
+//     option (google.api.routing) = {
+//       // The routing code needs two keys instead of one composite
+//       // but works only for the tables with the "project-instance" name
+//       // syntax.
+//
+//       routing_parameters {
+//         field: "table_name"
+//         path_template: "{project_id=projects/*}/instances/*/**"
+//       }
+//       routing_parameters {
+//         field: "table_name"
+//         path_template: "projects/*/{instance_id=instances/*}/**"
+//       }
+//     };
+//
+// result:
+//
+//     x-goog-request-params:
+//     project_id=projects/proj_foo&instance_id=instances/instance_bar
+//
+// Sub-example 6b
+//
+// Make the templates loose, so that if the `table_name` does not
+// have an instance information, just the project id part is sent.
+//
+// annotation:
+//
+//     option (google.api.routing) = {
+//       // The routing code wants two keys instead of one composite
+//       // but will work with just the `project_id` for tables without
+//       // an instance in the `table_name`.
+//
+//       routing_parameters {
+//         field: "table_name"
+//         path_template: "{project_id=projects/*}/**"
+//       }
+//       routing_parameters {
+//         field: "table_name"
+//         path_template: "projects/*/{instance_id=instances/*}/**"
+//       }
+//     };
+//
+// result (is the same as 6a for our example message because it has the instance
+// information):
+//
+//     x-goog-request-params:
+//     project_id=projects/proj_foo&instance_id=instances/instance_bar
+//
+// Example 7
+//
+// Extracting multiple routing header key-value pairs by matching
+// several path templates on multiple request fields.
+//
+// NB: note that here there is no way to specify sending nothing if one of the
+// fields does not match its template. E.g. if the `table_name` is in the wrong
+// format, the `project_id` will not be sent, but the `routing_id` will be.
+// The backend routing code has to be aware of that and be prepared to not
+// receive a full complement of keys if it expects multiple.
+//
+// annotation:
+//
+//     option (google.api.routing) = {
+//       // The routing needs both `project_id` and `routing_id`
+//       // (from the `app_profile_id` field) for routing.
+//
+//       routing_parameters {
+//         field: "table_name"
+//         path_template: "{project_id=projects/*}/**"
+//       }
+//       routing_parameters {
+//         field: "app_profile_id"
+//         path_template: "{routing_id=**}"
+//       }
+//     };
+//
+// result:
+//
+//     x-goog-request-params:
+//     project_id=projects/proj_foo&routing_id=profiles/prof_qux
+//
+// Example 8
+//
+// Extracting a single routing header key-value pair by matching
+// several conflictingly named path templates on several request fields. The
+// last template to match "wins" the conflict.
+//
+// annotation:
+//
+//     option (google.api.routing) = {
+//       // The `routing_id` can be a project id or a region id depending on
+//       // the table name format, but only if the `app_profile_id` is not set.
+//       // If `app_profile_id` is set it should be used instead.
+//
+//       routing_parameters {
+//         field: "table_name"
+//         path_template: "{routing_id=projects/*}/**"
+//       }
+//       routing_parameters {
+//          field: "table_name"
+//          path_template: "{routing_id=regions/*}/**"
+//       }
+//       routing_parameters {
+//         field: "app_profile_id"
+//         path_template: "{routing_id=**}"
+//       }
+//     };
+//
+// result:
+//
+//     x-goog-request-params: routing_id=profiles/prof_qux
+//
+// Example 9
+//
+// Bringing it all together.
+//
+// annotation:
+//
+//     option (google.api.routing) = {
+//       // For routing both `table_location` and a `routing_id` are needed.
+//       //
+//       // table_location can be either an instance id or a region+zone id.
+//       //
+//       // For `routing_id`, take the value of `app_profile_id`
+//       // - If it's in the format `profiles/<profile_id>`, send
+//       // just the `<profile_id>` part.
+//       // - If it's any other literal, send it as is.
+//       // If the `app_profile_id` is empty, and the `table_name` starts with
+//       // the project_id, send that instead.
+//
+//       routing_parameters {
+//         field: "table_name"
+//         path_template: "projects/*/{table_location=instances/*}/tables/*"
+//       }
+//       routing_parameters {
+//         field: "table_name"
+//         path_template: "{table_location=regions/*/zones/*}/tables/*"
+//       }
+//       routing_parameters {
+//         field: "table_name"
+//         path_template: "{routing_id=projects/*}/**"
+//       }
+//       routing_parameters {
+//         field: "app_profile_id"
+//         path_template: "{routing_id=**}"
+//       }
+//       routing_parameters {
+//         field: "app_profile_id"
+//         path_template: "profiles/{routing_id=*}"
+//       }
+//     };
+//
+// result:
+//
+//     x-goog-request-params:
+//     table_location=instances/instance_bar&routing_id=prof_qux
+message RoutingRule {
+  // A collection of Routing Parameter specifications.
+  // **NOTE:** If multiple Routing Parameters describe the same key
+  // (via the `path_template` field or via the `field` field when
+  // `path_template` is not provided), "last one wins" rule
+  // determines which Parameter gets used.
+  // See the examples for more details.
+  repeated RoutingParameter routing_parameters = 2;
+}
+
+// A projection from an input message to the GRPC or REST header.
+message RoutingParameter {
+  // A request field to extract the header key-value pair from.
+  string field = 1;
+
+  // A pattern matching the key-value field. Optional.
+  // If not specified, the whole field specified in the `field` field will be
+  // taken as value, and its name used as key. If specified, it MUST contain
+  // exactly one named segment (along with any number of unnamed segments) The
+  // pattern will be matched over the field specified in the `field` field, then
+  // if the match is successful:
+  // - the name of the single named segment will be used as a header name,
+  // - the match value of the segment will be used as a header value;
+  // if the match is NOT successful, nothing will be sent.
+  //
+  // Example:
+  //
+  //               -- This is a field in the request message
+  //              |   that the header value will be extracted from.
+  //              |
+  //              |                     -- This is the key name in the
+  //              |                    |   routing header.
+  //              V                    |
+  //     field: "table_name"           v
+  //     path_template: "projects/*/{table_location=instances/*}/tables/*"
+  //                                                ^            ^
+  //                                                |            |
+  //       In the {} brackets is the pattern that --             |
+  //       specifies what to extract from the                    |
+  //       field as a value to be sent.                          |
+  //                                                             |
+  //      The string in the field must match the whole pattern --
+  //      before brackets, inside brackets, after brackets.
+  //
+  // When looking at this specific example, we can see that:
+  // - A key-value pair with the key `table_location`
+  //   and the value matching `instances/*` should be added
+  //   to the x-goog-request-params routing header.
+  // - The value is extracted from the request message's `table_name` field
+  //   if it matches the full pattern specified:
+  //   `projects/*/instances/*/tables/*`.
+  //
+  // **NB:** If the `path_template` field is not provided, the key name is
+  // equal to the field name, and the whole field should be sent as a value.
+  // This makes the pattern for the field and the value functionally equivalent
+  // to `**`, and the configuration
+  //
+  //     {
+  //       field: "table_name"
+  //     }
+  //
+  // is a functionally equivalent shorthand to:
+  //
+  //     {
+  //       field: "table_name"
+  //       path_template: "{table_name=**}"
+  //     }
+  //
+  // See Example 1 for more details.
+  string path_template = 2;
+}
diff --git a/protoc_plugin/protos/google/protobuf/compiler/plugin.proto b/protoc_plugin/protos/google/protobuf/compiler/plugin.proto
index 9242aac..033fab2 100644
--- a/protoc_plugin/protos/google/protobuf/compiler/plugin.proto
+++ b/protoc_plugin/protos/google/protobuf/compiler/plugin.proto
@@ -1,38 +1,12 @@
 // Protocol Buffers - Google's data interchange format
 // Copyright 2008 Google Inc.  All rights reserved.
-// https://developers.google.com/protocol-buffers/
 //
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-//     * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-//     * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following disclaimer
-// in the documentation and/or other materials provided with the
-// distribution.
-//     * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived from
-// this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file or at
+// https://developers.google.com/open-source/licenses/bsd
 
 // Author: kenton@google.com (Kenton Varda)
 //
-// WARNING:  The plugin interface is currently EXPERIMENTAL and is subject to
-//   change.
-//
 // protoc (aka the Protocol Compiler) can be extended via plugins.  A plugin is
 // just a program that reads a CodeGeneratorRequest from stdin and writes a
 // CodeGeneratorResponse to stdout.
@@ -50,6 +24,7 @@
 option java_package = "com.google.protobuf.compiler";
 option java_outer_classname = "PluginProtos";
 
+option csharp_namespace = "Google.Protobuf.Compiler";
 option go_package = "google.golang.org/protobuf/types/pluginpb";
 
 import "google/protobuf/descriptor.proto";
@@ -78,6 +53,11 @@
   // they import.  The files will appear in topological order, so each file
   // appears before any file that imports it.
   //
+  // Note: the files listed in files_to_generate will include runtime-retention
+  // options only, but all other files will include source-retention options.
+  // The source_file_descriptors field below is available in case you need
+  // source-retention options for files_to_generate.
+  //
   // protoc guarantees that all proto_files will be written after
   // the fields above, even though this is not technically guaranteed by the
   // protobuf wire format.  This theoretically could allow a plugin to stream
@@ -90,9 +70,13 @@
   // fully qualified.
   repeated FileDescriptorProto proto_file = 15;
 
+  // File descriptors with all options, including source-retention options.
+  // These descriptors are only provided for the files listed in
+  // files_to_generate.
+  repeated FileDescriptorProto source_file_descriptors = 17;
+
   // The version number of protocol compiler.
   optional Version compiler_version = 3;
-
 }
 
 // The plugin writes an encoded CodeGeneratorResponse to stdout.
@@ -115,8 +99,21 @@
   enum Feature {
     FEATURE_NONE = 0;
     FEATURE_PROTO3_OPTIONAL = 1;
+    FEATURE_SUPPORTS_EDITIONS = 2;
   }
 
+  // The minimum edition this plugin supports.  This will be treated as an
+  // Edition enum, but we want to allow unknown values.  It should be specified
+  // according the edition enum value, *not* the edition number.  Only takes
+  // effect for plugins that have FEATURE_SUPPORTS_EDITIONS set.
+  optional int32 minimum_edition = 3;
+
+  // The maximum edition this plugin supports.  This will be treated as an
+  // Edition enum, but we want to allow unknown values.  It should be specified
+  // according the edition enum value, *not* the edition number.  Only takes
+  // effect for plugins that have FEATURE_SUPPORTS_EDITIONS set.
+  optional int32 maximum_edition = 4;
+
   // Represents a single generated file.
   message File {
     // The file name, relative to the output directory.  The name must not
diff --git a/protoc_plugin/protos/google/protobuf/descriptor.proto b/protoc_plugin/protos/google/protobuf/descriptor.proto
index 9f0ce6c..cb9bea1 100644
--- a/protoc_plugin/protos/google/protobuf/descriptor.proto
+++ b/protoc_plugin/protos/google/protobuf/descriptor.proto
@@ -36,7 +36,6 @@
 // A valid .proto file can be translated directly to a FileDescriptorProto
 // without any other information (e.g. without reading its imports).
 
-
 syntax = "proto2";
 
 package google.protobuf;
@@ -56,6 +55,49 @@
 // files it parses.
 message FileDescriptorSet {
   repeated FileDescriptorProto file = 1;
+
+  // Extensions for tooling.
+  extensions 536000000 [declaration = {
+    number: 536000000
+    type: ".buf.descriptor.v1.FileDescriptorSetExtension"
+    full_name: ".buf.descriptor.v1.buf_file_descriptor_set_extension"
+  }];
+}
+
+// The full set of known editions.
+enum Edition {
+  // A placeholder for an unknown edition value.
+  EDITION_UNKNOWN = 0;
+
+  // A placeholder edition for specifying default behaviors *before* a feature
+  // was first introduced.  This is effectively an "infinite past".
+  EDITION_LEGACY = 900;
+
+  // Legacy syntax "editions".  These pre-date editions, but behave much like
+  // distinct editions.  These can't be used to specify the edition of proto
+  // files, but feature definitions must supply proto2/proto3 defaults for
+  // backwards compatibility.
+  EDITION_PROTO2 = 998;
+  EDITION_PROTO3 = 999;
+
+  // Editions that have been released.  The specific values are arbitrary and
+  // should not be depended on, but they will always be time-ordered for easy
+  // comparison.
+  EDITION_2023 = 1000;
+  EDITION_2024 = 1001;
+
+  // Placeholder editions for testing feature resolution.  These should not be
+  // used or relied on outside of tests.
+  EDITION_1_TEST_ONLY = 1;
+  EDITION_2_TEST_ONLY = 2;
+  EDITION_99997_TEST_ONLY = 99997;
+  EDITION_99998_TEST_ONLY = 99998;
+  EDITION_99999_TEST_ONLY = 99999;
+
+  // Placeholder for specifying unbounded edition support.  This should only
+  // ever be used by plugins that can expect to never require any changes to
+  // support a new edition.
+  EDITION_MAX = 0x7FFFFFFF;
 }
 
 // Describes a complete .proto file.
@@ -71,6 +113,10 @@
   // For Google-internal migration only. Do not use.
   repeated int32 weak_dependency = 11;
 
+  // Names of files imported by this file purely for the purpose of providing
+  // option extensions. These are excluded from the dependency list above.
+  repeated string option_dependency = 15;
+
   // All top-level definitions in this file.
   repeated DescriptorProto message_type = 4;
   repeated EnumDescriptorProto enum_type = 5;
@@ -86,8 +132,19 @@
   optional SourceCodeInfo source_code_info = 9;
 
   // The syntax of the proto file.
-  // The supported values are "proto2" and "proto3".
+  // The supported values are "proto2", "proto3", and "editions".
+  //
+  // If `edition` is present, this value must be "editions".
+  // WARNING: This field should only be used by protobuf plugins or special
+  // cases like the proto compiler. Other uses are discouraged and
+  // developers should rely on the protoreflect APIs for their client language.
   optional string syntax = 12;
+
+  // The edition of the proto file.
+  // WARNING: This field should only be used by protobuf plugins or special
+  // cases like the proto compiler. Other uses are discouraged and
+  // developers should rely on the protoreflect APIs for their client language.
+  optional Edition edition = 14;
 }
 
 // Describes a message type.
@@ -123,12 +180,60 @@
   // Reserved field names, which may not be used by fields in the same message.
   // A given name may only be reserved once.
   repeated string reserved_name = 10;
+
+  // Support for `export` and `local` keywords on enums.
+  optional SymbolVisibility visibility = 11;
 }
 
 message ExtensionRangeOptions {
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
+  message Declaration {
+    // The extension number declared within the extension range.
+    optional int32 number = 1;
+
+    // The fully-qualified name of the extension field. There must be a leading
+    // dot in front of the full name.
+    optional string full_name = 2;
+
+    // The fully-qualified type name of the extension field. Unlike
+    // Metadata.type, Declaration.type must have a leading dot for messages
+    // and enums.
+    optional string type = 3;
+
+    // If true, indicates that the number is reserved in the extension range,
+    // and any extension field with the number will fail to compile. Set this
+    // when a declared extension field is deleted.
+    optional bool reserved = 5;
+
+    // If true, indicates that the extension must be defined as repeated.
+    // Otherwise the extension must be defined as optional.
+    optional bool repeated = 6;
+
+    reserved 4;  // removed is_repeated
+  }
+
+  // For external users: DO NOT USE. We are in the process of open sourcing
+  // extension declaration and executing internal cleanups before it can be
+  // used externally.
+  repeated Declaration declaration = 2 [retention = RETENTION_SOURCE];
+
+  // Any features defined in the specific edition.
+  optional FeatureSet features = 50;
+
+  // The verification state of the extension range.
+  enum VerificationState {
+    // All the extensions of the range must be declared.
+    DECLARATION = 0;
+    UNVERIFIED = 1;
+  }
+
+  // The verification state of the range.
+  // TODO: flip the default to DECLARATION once all empty ranges
+  // are marked as UNVERIFIED.
+  optional VerificationState verification = 3
+      [default = UNVERIFIED, retention = RETENTION_SOURCE];
 
   // Clients can define custom options in extensions of this message. See above.
   extensions 1000 to max;
@@ -153,9 +258,10 @@
     TYPE_BOOL = 8;
     TYPE_STRING = 9;
     // Tag-delimited aggregate.
-    // Group type is deprecated and not supported in proto3. However, Proto3
+    // Group type is deprecated and not supported after google.protobuf. However, Proto3
     // implementations should still be able to parse the group wire format and
-    // treat group fields as unknown fields.
+    // treat group fields as unknown fields.  In Editions, the group wire format
+    // can be enabled via the `message_encoding` feature.
     TYPE_GROUP = 10;
     TYPE_MESSAGE = 11;  // Length-delimited aggregate.
 
@@ -172,8 +278,11 @@
   enum Label {
     // 0 is reserved for errors
     LABEL_OPTIONAL = 1;
-    LABEL_REQUIRED = 2;
     LABEL_REPEATED = 3;
+    // The required label is only allowed in google.protobuf.  In proto3 and Editions
+    // it's explicitly prohibited.  In Editions, the `field_presence` feature
+    // can be used to get this behavior.
+    LABEL_REQUIRED = 2;
   }
 
   optional string name = 1;
@@ -199,7 +308,6 @@
   // For booleans, "true" or "false".
   // For strings, contains the default text contents (not escaped in any way).
   // For bytes, contains the C escaped value.  All bytes >= 128 are escaped.
-  // TODO(kenton):  Base-64 encode?
   optional string default_value = 7;
 
   // If set, gives the index of a oneof in the containing type's oneof_decl
@@ -217,12 +325,12 @@
   // If true, this is a proto3 "optional". When a proto3 field is optional, it
   // tracks presence regardless of field type.
   //
-  // When proto3_optional is true, this field must be belong to a oneof to
-  // signal to old proto3 clients that presence is tracked for this field. This
-  // oneof is known as a "synthetic" oneof, and this field must be its sole
-  // member (each proto3 optional field gets its own synthetic oneof). Synthetic
-  // oneofs exist in the descriptor only, and do not generate any API. Synthetic
-  // oneofs must be ordered after all "real" oneofs.
+  // When proto3_optional is true, this field must belong to a oneof to signal
+  // to old proto3 clients that presence is tracked for this field. This oneof
+  // is known as a "synthetic" oneof, and this field must be its sole member
+  // (each proto3 optional field gets its own synthetic oneof). Synthetic oneofs
+  // exist in the descriptor only, and do not generate any API. Synthetic oneofs
+  // must be ordered after all "real" oneofs.
   //
   // For message fields, proto3_optional doesn't create any semantic change,
   // since non-repeated message fields always track presence. However it still
@@ -271,6 +379,9 @@
   // Reserved enum value names, which may not be reused. A given name may only
   // be reserved once.
   repeated string reserved_name = 5;
+
+  // Support for `export` and `local` keywords on enums.
+  optional SymbolVisibility visibility = 6;
 }
 
 // Describes a value within an enum.
@@ -306,7 +417,6 @@
   optional bool server_streaming = 6 [default = false];
 }
 
-
 // ===================================================================
 // Options
 
@@ -347,18 +457,17 @@
   // domain names.
   optional string java_package = 1;
 
-
-  // If set, all the classes from the .proto file are wrapped in a single
-  // outer class with the given name.  This applies to both Proto1
-  // (equivalent to the old "--one_java_file" option) and Proto2 (where
-  // a .proto always translates to a single class, but you may want to
-  // explicitly choose the class name).
+  // Controls the name of the wrapper Java class generated for the .proto file.
+  // That class will always contain the .proto file's getDescriptor() method as
+  // well as any top-level extensions defined in the .proto file.
+  // If java_multiple_files is disabled, then all the other classes from the
+  // .proto file will be nested inside the single wrapper outer class.
   optional string java_outer_classname = 8;
 
-  // If set true, then the Java code generator will generate a separate .java
+  // If enabled, then the Java code generator will generate a separate .java
   // file for each top-level message, enum, and service defined in the .proto
-  // file.  Thus, these types will *not* be nested inside the outer class
-  // named by java_outer_classname.  However, the outer class will still be
+  // file.  Thus, these types will *not* be nested inside the wrapper class
+  // named by java_outer_classname.  However, the wrapper class will still be
   // generated to contain the file's getDescriptor() method as well as any
   // top-level extensions defined in the file.
   optional bool java_multiple_files = 10 [default = false];
@@ -366,15 +475,18 @@
   // This option does nothing.
   optional bool java_generate_equals_and_hash = 20 [deprecated=true];
 
-  // If set true, then the Java2 code generator will generate code that
-  // throws an exception whenever an attempt is made to assign a non-UTF-8
-  // byte sequence to a string field.
-  // Message reflection will do the same.
-  // However, an extension field still accepts non-UTF-8 byte sequences.
-  // This option has no effect on when used with the lite runtime.
+  // A proto2 file can set this to true to opt in to UTF-8 checking for Java,
+  // which will throw an exception if invalid UTF-8 is parsed from the wire or
+  // assigned to a string field.
+  //
+  // TODO: clarify exactly what kinds of field types this option
+  // applies to, and update these docs accordingly.
+  //
+  // Proto3 files already perform these checks. Setting the option explicitly to
+  // false has no effect: it cannot be used to opt proto3 files out of UTF-8
+  // checks.
   optional bool java_string_check_utf8 = 27 [default = false];
 
-
   // Generated classes can be optimized for speed or code size.
   enum OptimizeMode {
     SPEED = 1;         // Generate complete code for parsing, serialization,
@@ -391,9 +503,6 @@
   //   - Otherwise, the basename of the .proto file, without extension.
   optional string go_package = 11;
 
-
-
-
   // Should generic services be generated in each language?  "Generic" services
   // are not specific to any particular RPC system.  They are generated by the
   // main code generators in each language (without additional plugins).
@@ -407,7 +516,8 @@
   optional bool cc_generic_services = 16 [default = false];
   optional bool java_generic_services = 17 [default = false];
   optional bool py_generic_services = 18 [default = false];
-  optional bool php_generic_services = 42 [default = false];
+  reserved 42;  // removed php_generic_services
+  reserved "php_generic_services";
 
   // Is this file deprecated?
   // Depending on the target platform, this can emit Deprecated annotations
@@ -419,7 +529,6 @@
   // only to generated classes for C++.
   optional bool cc_enable_arenas = 31 [default = true];
 
-
   // Sets the objective c class prefix which is prepended to all objective c
   // generated classes from this .proto. There is no default.
   optional string objc_class_prefix = 36;
@@ -452,6 +561,11 @@
   // determining the ruby package.
   optional string ruby_package = 45;
 
+  // Any features defined in the specific edition.
+  // WARNING: This field should only be used by protobuf plugins or special
+  // cases like the proto compiler. Other uses are discouraged and
+  // developers should rely on the protoreflect APIs for their client language.
+  optional FeatureSet features = 50;
 
   // The parser stores options it doesn't recognize here.
   // See the documentation for the "Options" section above.
@@ -496,6 +610,8 @@
   // this is a formalization for deprecating messages.
   optional bool deprecated = 3 [default = false];
 
+  reserved 4, 5, 6;
+
   // Whether the message is an automatically generated map entry type for the
   // maps field.
   //
@@ -522,6 +638,23 @@
   reserved 8;  // javalite_serializable
   reserved 9;  // javanano_as_lite
 
+  // Enable the legacy handling of JSON field name conflicts.  This lowercases
+  // and strips underscored from the fields before comparison in proto3 only.
+  // The new behavior takes `json_name` into account and applies to proto2 as
+  // well.
+  //
+  // This should only be used as a temporary measure against broken builds due
+  // to the change in behavior for JSON field name conflicts.
+  //
+  // TODO This is legacy behavior we plan to remove once downstream
+  // teams have had time to migrate.
+  optional bool deprecated_legacy_json_field_conflicts = 11 [deprecated = true];
+
+  // Any features defined in the specific edition.
+  // WARNING: This field should only be used by protobuf plugins or special
+  // cases like the proto compiler. Other uses are discouraged and
+  // developers should rely on the protoreflect APIs for their client language.
+  optional FeatureSet features = 12;
 
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
@@ -531,15 +664,24 @@
 }
 
 message FieldOptions {
+  // NOTE: ctype is deprecated. Use `features.(pb.cpp).string_type` instead.
   // The ctype option instructs the C++ code generator to use a different
   // representation of the field than it normally would.  See the specific
-  // options below.  This option is not yet implemented in the open source
-  // release -- sorry, we'll try to include it in a future version!
-  optional CType ctype = 1 [default = STRING];
+  // options below.  This option is only implemented to support use of
+  // [ctype=CORD] and [ctype=STRING] (the default) on non-repeated fields of
+  // type "bytes" in the open source release.
+  // TODO: make ctype actually deprecated.
+  optional CType ctype = 1 [/*deprecated = true,*/ default = STRING];
   enum CType {
     // Default mode.
     STRING = 0;
 
+    // The option [ctype=CORD] may be applied to a non-repeated field of type
+    // "bytes". It indicates that in C++, the data should be stored in a Cord
+    // instead of a string.  For very large strings, this may reduce memory
+    // fragmentation. It may also allow better performance when parsing from a
+    // Cord, or when parsing with aliasing enabled, as the parsed Cord may then
+    // alias the original buffer.
     CORD = 1;
 
     STRING_PIECE = 2;
@@ -548,7 +690,9 @@
   // a more efficient representation on the wire. Rather than repeatedly
   // writing the tag and type for each element, the entire array is encoded as
   // a single length-delimited blob. In proto3, only explicit setting it to
-  // false will avoid using packed encoding.
+  // false will avoid using packed encoding.  This option is prohibited in
+  // Editions, but the `repeated_field_encoding` feature can be used to control
+  // the behavior.
   optional bool packed = 2;
 
   // The jstype option determines the JavaScript type used for values of the
@@ -591,19 +735,18 @@
   // call from multiple threads concurrently, while non-const methods continue
   // to require exclusive access.
   //
-  //
-  // Note that implementations may choose not to check required fields within
-  // a lazy sub-message.  That is, calling IsInitialized() on the outer message
-  // may return true even if the inner message has missing required fields.
-  // This is necessary because otherwise the inner message would have to be
-  // parsed in order to perform the check, defeating the purpose of lazy
-  // parsing.  An implementation which chooses not to check required fields
-  // must be consistent about it.  That is, for any particular sub-message, the
-  // implementation must either *always* check its required fields, or *never*
-  // check its required fields, regardless of whether or not the message has
-  // been parsed.
+  // Note that lazy message fields are still eagerly verified to check
+  // ill-formed wireformat or missing required fields. Calling IsInitialized()
+  // on the outer message would fail if the inner message has missing required
+  // fields. Failed verification would result in parsing failure (except when
+  // uninitialized messages are acceptable).
   optional bool lazy = 5 [default = false];
 
+  // unverified_lazy does no correctness checks on the byte stream. This should
+  // only be used where lazy with verification is prohibitive for performance
+  // reasons.
+  optional bool unverified_lazy = 15 [default = false];
+
   // Is this field deprecated?
   // Depending on the target platform, this can emit Deprecated annotations
   // for accessors, or it will be completely ignored; in the very least, this
@@ -613,6 +756,70 @@
   // For Google-internal migration only. Do not use.
   optional bool weak = 10 [default = false];
 
+  // Indicate that the field value should not be printed out when using debug
+  // formats, e.g. when the field contains sensitive credentials.
+  optional bool debug_redact = 16 [default = false];
+
+  // If set to RETENTION_SOURCE, the option will be omitted from the binary.
+  enum OptionRetention {
+    RETENTION_UNKNOWN = 0;
+    RETENTION_RUNTIME = 1;
+    RETENTION_SOURCE = 2;
+  }
+
+  optional OptionRetention retention = 17;
+
+  // This indicates the types of entities that the field may apply to when used
+  // as an option. If it is unset, then the field may be freely used as an
+  // option on any kind of entity.
+  enum OptionTargetType {
+    TARGET_TYPE_UNKNOWN = 0;
+    TARGET_TYPE_FILE = 1;
+    TARGET_TYPE_EXTENSION_RANGE = 2;
+    TARGET_TYPE_MESSAGE = 3;
+    TARGET_TYPE_FIELD = 4;
+    TARGET_TYPE_ONEOF = 5;
+    TARGET_TYPE_ENUM = 6;
+    TARGET_TYPE_ENUM_ENTRY = 7;
+    TARGET_TYPE_SERVICE = 8;
+    TARGET_TYPE_METHOD = 9;
+  }
+
+  repeated OptionTargetType targets = 19;
+
+  message EditionDefault {
+    optional Edition edition = 3;
+    optional string value = 2;  // Textproto value.
+  }
+  repeated EditionDefault edition_defaults = 20;
+
+  // Any features defined in the specific edition.
+  // WARNING: This field should only be used by protobuf plugins or special
+  // cases like the proto compiler. Other uses are discouraged and
+  // developers should rely on the protoreflect APIs for their client language.
+  optional FeatureSet features = 21;
+
+  // Information about the support window of a feature.
+  message FeatureSupport {
+    // The edition that this feature was first available in.  In editions
+    // earlier than this one, the default assigned to EDITION_LEGACY will be
+    // used, and proto files will not be able to override it.
+    optional Edition edition_introduced = 1;
+
+    // The edition this feature becomes deprecated in.  Using this after this
+    // edition may trigger warnings.
+    optional Edition edition_deprecated = 2;
+
+    // The deprecation warning text if this feature is used after the edition it
+    // was marked deprecated in.
+    optional string deprecation_warning = 3;
+
+    // The edition this feature is no longer available in.  In editions after
+    // this one, the last default assigned will be used, and proto files will
+    // not be able to override it.
+    optional Edition edition_removed = 4;
+  }
+  optional FeatureSupport feature_support = 22;
 
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
@@ -620,10 +827,17 @@
   // Clients can define custom options in extensions of this message. See above.
   extensions 1000 to max;
 
-  reserved 4;  // removed jtype
+  reserved 4;   // removed jtype
+  reserved 18;  // reserve target, target_obsolete_do_not_use
 }
 
 message OneofOptions {
+  // Any features defined in the specific edition.
+  // WARNING: This field should only be used by protobuf plugins or special
+  // cases like the proto compiler. Other uses are discouraged and
+  // developers should rely on the protoreflect APIs for their client language.
+  optional FeatureSet features = 1;
+
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
@@ -645,6 +859,20 @@
 
   reserved 5;  // javanano_as_lite
 
+  // Enable the legacy handling of JSON field name conflicts.  This lowercases
+  // and strips underscored from the fields before comparison in proto3 only.
+  // The new behavior takes `json_name` into account and applies to proto2 as
+  // well.
+  // TODO Remove this legacy behavior once downstream teams have
+  // had time to migrate.
+  optional bool deprecated_legacy_json_field_conflicts = 6 [deprecated = true];
+
+  // Any features defined in the specific edition.
+  // WARNING: This field should only be used by protobuf plugins or special
+  // cases like the proto compiler. Other uses are discouraged and
+  // developers should rely on the protoreflect APIs for their client language.
+  optional FeatureSet features = 7;
+
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
@@ -659,6 +887,20 @@
   // this is a formalization for deprecating enum values.
   optional bool deprecated = 1 [default = false];
 
+  // Any features defined in the specific edition.
+  // WARNING: This field should only be used by protobuf plugins or special
+  // cases like the proto compiler. Other uses are discouraged and
+  // developers should rely on the protoreflect APIs for their client language.
+  optional FeatureSet features = 2;
+
+  // Indicate that fields annotated with this enum value should not be printed
+  // out when using debug formats, e.g. when the field contains sensitive
+  // credentials.
+  optional bool debug_redact = 3 [default = false];
+
+  // Information about the support window of a feature value.
+  optional FieldOptions.FeatureSupport feature_support = 4;
+
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
@@ -668,6 +910,12 @@
 
 message ServiceOptions {
 
+  // Any features defined in the specific edition.
+  // WARNING: This field should only be used by protobuf plugins or special
+  // cases like the proto compiler. Other uses are discouraged and
+  // developers should rely on the protoreflect APIs for their client language.
+  optional FeatureSet features = 34;
+
   // Note:  Field numbers 1 through 32 are reserved for Google's internal RPC
   //   framework.  We apologize for hoarding these numbers to ourselves, but
   //   we were already using them long before we decided to release Protocol
@@ -710,6 +958,12 @@
   optional IdempotencyLevel idempotency_level = 34
       [default = IDEMPOTENCY_UNKNOWN];
 
+  // Any features defined in the specific edition.
+  // WARNING: This field should only be used by protobuf plugins or special
+  // cases like the proto compiler. Other uses are discouraged and
+  // developers should rely on the protoreflect APIs for their client language.
+  optional FeatureSet features = 35;
+
   // The parser stores options it doesn't recognize here. See above.
   repeated UninterpretedOption uninterpreted_option = 999;
 
@@ -717,7 +971,6 @@
   extensions 1000 to max;
 }
 
-
 // A message representing a option the parser does not recognize. This only
 // appears in options protos created by the compiler::Parser class.
 // DescriptorPool resolves these when building Descriptor objects. Therefore,
@@ -728,8 +981,8 @@
   // The name of the uninterpreted option.  Each string represents a segment in
   // a dot-separated name.  is_extension is true iff a segment represents an
   // extension (denoted with parentheses in options specs in .proto files).
-  // E.g.,{ ["foo", false], ["bar.baz", true], ["qux", false] } represents
-  // "foo.(bar.baz).qux".
+  // E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents
+  // "foo.(bar.baz).moo".
   message NamePart {
     required string name_part = 1;
     required bool is_extension = 2;
@@ -747,6 +1000,236 @@
 }
 
 // ===================================================================
+// Features
+
+// TODO Enums in C++ gencode (and potentially other languages) are
+// not well scoped.  This means that each of the feature enums below can clash
+// with each other.  The short names we've chosen maximize call-site
+// readability, but leave us very open to this scenario.  A future feature will
+// be designed and implemented to handle this, hopefully before we ever hit a
+// conflict here.
+message FeatureSet {
+  enum FieldPresence {
+    FIELD_PRESENCE_UNKNOWN = 0;
+    EXPLICIT = 1;
+    IMPLICIT = 2;
+    LEGACY_REQUIRED = 3;
+  }
+  optional FieldPresence field_presence = 1 [
+    retention = RETENTION_RUNTIME,
+    targets = TARGET_TYPE_FIELD,
+    targets = TARGET_TYPE_FILE,
+    feature_support = {
+      edition_introduced: EDITION_2023,
+    },
+    edition_defaults = { edition: EDITION_LEGACY, value: "EXPLICIT" },
+    edition_defaults = { edition: EDITION_PROTO3, value: "IMPLICIT" },
+    edition_defaults = { edition: EDITION_2023, value: "EXPLICIT" }
+  ];
+
+  enum EnumType {
+    ENUM_TYPE_UNKNOWN = 0;
+    OPEN = 1;
+    CLOSED = 2;
+  }
+  optional EnumType enum_type = 2 [
+    retention = RETENTION_RUNTIME,
+    targets = TARGET_TYPE_ENUM,
+    targets = TARGET_TYPE_FILE,
+    feature_support = {
+      edition_introduced: EDITION_2023,
+    },
+    edition_defaults = { edition: EDITION_LEGACY, value: "CLOSED" },
+    edition_defaults = { edition: EDITION_PROTO3, value: "OPEN" }
+  ];
+
+  enum RepeatedFieldEncoding {
+    REPEATED_FIELD_ENCODING_UNKNOWN = 0;
+    PACKED = 1;
+    EXPANDED = 2;
+  }
+  optional RepeatedFieldEncoding repeated_field_encoding = 3 [
+    retention = RETENTION_RUNTIME,
+    targets = TARGET_TYPE_FIELD,
+    targets = TARGET_TYPE_FILE,
+    feature_support = {
+      edition_introduced: EDITION_2023,
+    },
+    edition_defaults = { edition: EDITION_LEGACY, value: "EXPANDED" },
+    edition_defaults = { edition: EDITION_PROTO3, value: "PACKED" }
+  ];
+
+  enum Utf8Validation {
+    UTF8_VALIDATION_UNKNOWN = 0;
+    VERIFY = 2;
+    NONE = 3;
+    reserved 1;
+  }
+  optional Utf8Validation utf8_validation = 4 [
+    retention = RETENTION_RUNTIME,
+    targets = TARGET_TYPE_FIELD,
+    targets = TARGET_TYPE_FILE,
+    feature_support = {
+      edition_introduced: EDITION_2023,
+    },
+    edition_defaults = { edition: EDITION_LEGACY, value: "NONE" },
+    edition_defaults = { edition: EDITION_PROTO3, value: "VERIFY" }
+  ];
+
+  enum MessageEncoding {
+    MESSAGE_ENCODING_UNKNOWN = 0;
+    LENGTH_PREFIXED = 1;
+    DELIMITED = 2;
+  }
+  optional MessageEncoding message_encoding = 5 [
+    retention = RETENTION_RUNTIME,
+    targets = TARGET_TYPE_FIELD,
+    targets = TARGET_TYPE_FILE,
+    feature_support = {
+      edition_introduced: EDITION_2023,
+    },
+    edition_defaults = { edition: EDITION_LEGACY, value: "LENGTH_PREFIXED" }
+  ];
+
+  enum JsonFormat {
+    JSON_FORMAT_UNKNOWN = 0;
+    ALLOW = 1;
+    LEGACY_BEST_EFFORT = 2;
+  }
+  optional JsonFormat json_format = 6 [
+    retention = RETENTION_RUNTIME,
+    targets = TARGET_TYPE_MESSAGE,
+    targets = TARGET_TYPE_ENUM,
+    targets = TARGET_TYPE_FILE,
+    feature_support = {
+      edition_introduced: EDITION_2023,
+    },
+    edition_defaults = { edition: EDITION_LEGACY, value: "LEGACY_BEST_EFFORT" },
+    edition_defaults = { edition: EDITION_PROTO3, value: "ALLOW" }
+  ];
+
+  enum EnforceNamingStyle {
+    ENFORCE_NAMING_STYLE_UNKNOWN = 0;
+    STYLE2024 = 1;
+    STYLE_LEGACY = 2;
+  }
+  optional EnforceNamingStyle enforce_naming_style = 7 [
+    retention = RETENTION_SOURCE,
+    targets = TARGET_TYPE_FILE,
+    targets = TARGET_TYPE_EXTENSION_RANGE,
+    targets = TARGET_TYPE_MESSAGE,
+    targets = TARGET_TYPE_FIELD,
+    targets = TARGET_TYPE_ONEOF,
+    targets = TARGET_TYPE_ENUM,
+    targets = TARGET_TYPE_ENUM_ENTRY,
+    targets = TARGET_TYPE_SERVICE,
+    targets = TARGET_TYPE_METHOD,
+    feature_support = {
+      edition_introduced: EDITION_2024,
+    },
+    edition_defaults = { edition: EDITION_LEGACY, value: "STYLE_LEGACY" },
+    edition_defaults = { edition: EDITION_2024, value: "STYLE2024" }
+  ];
+
+  message VisibilityFeature {
+    enum DefaultSymbolVisibility {
+      DEFAULT_SYMBOL_VISIBILITY_UNKNOWN = 0;
+
+      // Default pre-EDITION_2024, all UNSET visibility are export.
+      EXPORT_ALL = 1;
+
+      // All top-level symbols default to export, nested default to local.
+      EXPORT_TOP_LEVEL = 2;
+
+      // All symbols default to local.
+      LOCAL_ALL = 3;
+
+      // All symbols local by default. Nested types cannot be exported.
+      // With special case caveat for message { enum {} reserved 1 to max; }
+      // This is the recommended setting for new protos.
+      STRICT = 4;
+    }
+    reserved 1 to max;
+  }
+  optional VisibilityFeature.DefaultSymbolVisibility default_symbol_visibility =
+      8 [
+        retention = RETENTION_SOURCE,
+        targets = TARGET_TYPE_FILE,
+        feature_support = {
+          edition_introduced: EDITION_2024,
+        },
+        edition_defaults = { edition: EDITION_LEGACY, value: "EXPORT_ALL" },
+        edition_defaults = { edition: EDITION_2024, value: "EXPORT_TOP_LEVEL" }
+      ];
+
+  reserved 999;
+
+  extensions 1000 to 9994 [
+    declaration = {
+      number: 1000,
+      full_name: ".pb.cpp",
+      type: ".pb.CppFeatures"
+    },
+    declaration = {
+      number: 1001,
+      full_name: ".pb.java",
+      type: ".pb.JavaFeatures"
+    },
+    declaration = { number: 1002, full_name: ".pb.go", type: ".pb.GoFeatures" },
+    declaration = {
+      number: 1003,
+      full_name: ".pb.python",
+      type: ".pb.PythonFeatures"
+    },
+    declaration = {
+      number: 9989,
+      full_name: ".pb.java_mutable",
+      type: ".pb.JavaMutableFeatures"
+    },
+    declaration = {
+      number: 9990,
+      full_name: ".pb.proto1",
+      type: ".pb.Proto1Features"
+    }
+  ];
+
+  extensions 9995 to 9999;  // For internal testing
+  extensions 10000;         // for https://github.com/bufbuild/protobuf-es
+}
+
+// A compiled specification for the defaults of a set of features.  These
+// messages are generated from FeatureSet extensions and can be used to seed
+// feature resolution. The resolution with this object becomes a simple search
+// for the closest matching edition, followed by proto merges.
+message FeatureSetDefaults {
+  // A map from every known edition with a unique set of defaults to its
+  // defaults. Not all editions may be contained here.  For a given edition,
+  // the defaults at the closest matching edition ordered at or before it should
+  // be used.  This field must be in strict ascending order by edition.
+  message FeatureSetEditionDefault {
+    optional Edition edition = 3;
+
+    // Defaults of features that can be overridden in this edition.
+    optional FeatureSet overridable_features = 4;
+
+    // Defaults of features that can't be overridden in this edition.
+    optional FeatureSet fixed_features = 5;
+
+    reserved 1, 2;
+    reserved "features";
+  }
+  repeated FeatureSetEditionDefault defaults = 1;
+
+  // The minimum supported edition (inclusive) when this was constructed.
+  // Editions before this will not have defaults.
+  optional Edition minimum_edition = 4;
+
+  // The maximum known edition (inclusive) when this was constructed. Editions
+  // after this will not have reliable defaults.
+  optional Edition maximum_edition = 5;
+}
+
+// ===================================================================
 // Optional source code info
 
 // Encapsulates information about the original source file from which a
@@ -801,8 +1284,8 @@
     // location.
     //
     // Each element is a field number or an index.  They form a path from
-    // the root FileDescriptorProto to the place where the definition.  For
-    // example, this path:
+    // the root FileDescriptorProto to the place where the definition appears.
+    // For example, this path:
     //   [ 4, 3, 2, 7, 1 ]
     // refers to:
     //   file.message_type(3)  // 4, 3
@@ -856,13 +1339,13 @@
     //   // Comment attached to baz.
     //   // Another line attached to baz.
     //
-    //   // Comment attached to qux.
+    //   // Comment attached to moo.
     //   //
-    //   // Another line attached to qux.
-    //   optional double qux = 4;
+    //   // Another line attached to moo.
+    //   optional double moo = 4;
     //
     //   // Detached comment for corge. This is not leading or trailing comments
-    //   // to qux or corge because there are blank lines separating it from
+    //   // to moo or corge because there are blank lines separating it from
     //   // both.
     //
     //   // Detached comment for corge paragraph 2.
@@ -880,6 +1363,13 @@
     optional string trailing_comments = 4;
     repeated string leading_detached_comments = 6;
   }
+
+  // Extensions for tooling.
+  extensions 536000000 [declaration = {
+    number: 536000000
+    type: ".buf.descriptor.v1.SourceCodeInfoExtension"
+    full_name: ".buf.descriptor.v1.buf_source_code_info_extension"
+  }];
 }
 
 // Describes the relationship between generated code and its original source
@@ -902,8 +1392,31 @@
     optional int32 begin = 3;
 
     // Identifies the ending offset in bytes in the generated code that
-    // relates to the identified offset. The end offset should be one past
+    // relates to the identified object. The end offset should be one past
     // the last relevant byte (so the length of the text = end - begin).
     optional int32 end = 4;
+
+    // Represents the identified object's effect on the element in the original
+    // .proto file.
+    enum Semantic {
+      // There is no effect or the effect is indescribable.
+      NONE = 0;
+      // The element is set or otherwise mutated.
+      SET = 1;
+      // An alias to the element is returned.
+      ALIAS = 2;
+    }
+    optional Semantic semantic = 5;
   }
 }
+
+// Describes the 'visibility' of a symbol with respect to the proto import
+// system. Symbols can only be imported when the visibility rules do not prevent
+// it (ex: local symbols cannot be imported).  Visibility modifiers can only set
+// on `message` and `enum` as they are the only types available to be referenced
+// from other files.
+enum SymbolVisibility {
+  VISIBILITY_UNSET = 0;
+  VISIBILITY_LOCAL = 1;
+  VISIBILITY_EXPORT = 2;
+}
diff --git a/protoc_plugin/tool/update_protos.dart b/protoc_plugin/tool/update_protos.dart
new file mode 100644
index 0000000..cd3f221
--- /dev/null
+++ b/protoc_plugin/tool/update_protos.dart
@@ -0,0 +1,95 @@
+// Copyright (c) 2025, the Dart project authors.  Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// Run this script to update to the latest google/protobuf and googleapis
+/// protobufs.
+library;
+
+import 'dart:io';
+
+void main(List<String> args) async {
+  final cacheDir = Directory('.dart_tool/protoc_plugin');
+  final protobufDir = Directory('${cacheDir.path}/protobuf');
+  final googleapisDir = Directory('${cacheDir.path}/googleapis');
+
+  final destDir = Directory('protos');
+
+  // Update from protocolbuffers/protobuf.
+  if (protobufDir.existsSync()) {
+    await git(['pull'], cwd: protobufDir);
+  } else {
+    await git([
+      'clone',
+      'https://github.com/protocolbuffers/protobuf.git',
+      '--depth',
+      '1',
+    ], cwd: cacheDir);
+  }
+
+  copy(protobufDir, destDir, 'src', [
+    'google/protobuf/compiler/plugin.proto',
+    'google/protobuf/descriptor.proto',
+    'google/protobuf/duration.proto',
+  ]);
+
+  // Update from googleapis/googleapis.
+  if (googleapisDir.existsSync()) {
+    await git(['pull'], cwd: googleapisDir);
+  } else {
+    await git([
+      'clone',
+      'https://github.com/googleapis/googleapis.git',
+      '--depth',
+      '1',
+    ], cwd: cacheDir);
+  }
+
+  copy(googleapisDir, destDir, '', [
+    'google/api/client.proto',
+    'google/api/http.proto',
+    'google/api/launch_stage.proto',
+    'google/api/routing.proto',
+  ]);
+}
+
+Future<void> git(List<String> args, {required Directory cwd}) async {
+  print('[${cwd.path}] git ${args.join(' ')}');
+
+  if (!cwd.existsSync()) {
+    cwd.createSync(recursive: true);
+  }
+
+  final result = await Process.run('git', args, workingDirectory: cwd.path);
+  stdout.write(result.stdout);
+  stderr.write(result.stderr);
+  if (result.exitCode != 0) {
+    exitCode = result.exitCode;
+    throw 'git exited with ${result.exitCode}';
+  }
+}
+
+void copy(Directory from, Directory to, String fromPrefix, List<String> files) {
+  print('copying ${from.path} => ${to.path}');
+
+  if (fromPrefix.isNotEmpty) {
+    fromPrefix = '$fromPrefix/';
+  }
+
+  for (final file in files) {
+    final source = File('${from.path}/$fromPrefix$file');
+    final target = File('${to.path}/$file');
+
+    if (!target.parent.existsSync()) {
+      target.parent.createSync(recursive: true);
+    }
+
+    final sourceContents = source.readAsStringSync();
+    if (!target.existsSync() || target.readAsStringSync() != sourceContents) {
+      print('  => $file');
+      target.writeAsStringSync(sourceContents);
+    }
+  }
+
+  print('');
+}