@dogmatiq/protobuf 0.4.1 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -10,7 +10,9 @@ export declare const file_github_com_dogmatiq_protobuf_envelopepb_envelope: GenF
10
10
  /**
11
11
  * Envelope is a container for a Dogma message and its meta-data.
12
12
  *
13
- * It is wire-compatible with [MultiEnvelope].
13
+ * An Envelope can be decoded as a single-body [MultiEnvelope]. Decoding a
14
+ * MultiEnvelope as an Envelope is only safe when it contains exactly one body;
15
+ * multiple bodies merge when decoded into the singular body field.
14
16
  *
15
17
  * @generated from message dogma.protobuf.v1.Envelope
16
18
  */
@@ -33,7 +35,6 @@ export declare const EnvelopeSchema: GenMessage<Envelope>;
33
35
  * MultiEnvelope is an efficient encoding of an ordered sequence of [Envelope]
34
36
  * values that share common header context.
35
37
  *
36
- *
37
38
  * @generated from message dogma.protobuf.v1.MultiEnvelope
38
39
  */
39
40
  export type MultiEnvelope = Message$1<"dogma.protobuf.v1.MultiEnvelope"> & {
@@ -140,6 +141,12 @@ export type Message = Message$1<"dogma.protobuf.v1.Message"> & {
140
141
  */
141
142
  export declare const MessageSchema: GenMessage<Message>;
142
143
  /**
144
+ * Header contains origin and causal context that can be common to messages
145
+ * produced by the same cause.
146
+ *
147
+ * Extensions and baggage from the header and body are combined by message
148
+ * type. Body values take precedence over header values of the same type.
149
+ *
143
150
  * @generated from message dogma.protobuf.v1.Header
144
151
  */
145
152
  export type Header = Message$1<"dogma.protobuf.v1.Header"> & {
@@ -16,6 +16,8 @@ export type Identity = Message<"dogma.protobuf.v1.Identity"> & {
16
16
  /**
17
17
  * Name is the entity's human-readable name.
18
18
  *
19
+ * The name MUST be between 1 and 255 bytes when encoded as UTF-8.
20
+ *
19
21
  * The name should be unique enough to allow a human to identify the entity
20
22
  * without ambiguity. There is no hard requirement for uniqueness.
21
23
  *
@@ -24,3 +24,27 @@ export type UnrecognizedEventStream = Message<"dogma.messaging.v1.UnrecognizedEv
24
24
  * Use `create(UnrecognizedEventStreamSchema)` to create a new message.
25
25
  */
26
26
  export declare const UnrecognizedEventStreamSchema: GenMessage<UnrecognizedEventStream>;
27
+ /**
28
+ * EventStreamConsumerTooSlow is an error-details value for RESOURCE_EXHAUSTED
29
+ * errors returned by WatchEvents when a client cannot keep up and the server
30
+ * can no longer deliver a stream contiguously.
31
+ *
32
+ * A client that is behind the tail does not cause this error while contiguous
33
+ * delivery remains possible.
34
+ *
35
+ * @generated from message dogma.messaging.v1.EventStreamConsumerTooSlow
36
+ */
37
+ export type EventStreamConsumerTooSlow = Message<"dogma.messaging.v1.EventStreamConsumerTooSlow"> & {
38
+ /**
39
+ * EventStreamId is the ID of the stream that could no longer be delivered
40
+ * contiguously.
41
+ *
42
+ * @generated from field: dogma.protobuf.v1.UUID event_stream_id = 1;
43
+ */
44
+ eventStreamId?: UUID | undefined;
45
+ };
46
+ /**
47
+ * Describes the message dogma.messaging.v1.EventStreamConsumerTooSlow.
48
+ * Use `create(EventStreamConsumerTooSlowSchema)` to create a new message.
49
+ */
50
+ export declare const EventStreamConsumerTooSlowSchema: GenMessage<EventStreamConsumerTooSlow>;
@@ -6,9 +6,14 @@ import { file_github_com_dogmatiq_protobuf_uuidpb_uuid } from "../uuidpb/uuid_pb
6
6
  /**
7
7
  * Describes the file github.com/dogmatiq/protobuf/messaginggrpc/errors.proto.
8
8
  */
9
- export const file_github_com_dogmatiq_protobuf_messaginggrpc_errors = /*@__PURE__*/ fileDesc("CjdnaXRodWIuY29tL2RvZ21hdGlxL3Byb3RvYnVmL21lc3NhZ2luZ2dycGMvZXJyb3JzLnByb3RvEhJkb2dtYS5tZXNzYWdpbmcudjEiSwoXVW5yZWNvZ25pemVkRXZlbnRTdHJlYW0SMAoPZXZlbnRfc3RyZWFtX2lkGAEgASgLMhcuZG9nbWEucHJvdG9idWYudjEuVVVJREIsWipnaXRodWIuY29tL2RvZ21hdGlxL3Byb3RvYnVmL21lc3NhZ2luZ2dycGNiCGVkaXRpb25zcOkH", [file_github_com_dogmatiq_protobuf_uuidpb_uuid]);
9
+ export const file_github_com_dogmatiq_protobuf_messaginggrpc_errors = /*@__PURE__*/ fileDesc("CjdnaXRodWIuY29tL2RvZ21hdGlxL3Byb3RvYnVmL21lc3NhZ2luZ2dycGMvZXJyb3JzLnByb3RvEhJkb2dtYS5tZXNzYWdpbmcudjEiSwoXVW5yZWNvZ25pemVkRXZlbnRTdHJlYW0SMAoPZXZlbnRfc3RyZWFtX2lkGAEgASgLMhcuZG9nbWEucHJvdG9idWYudjEuVVVJRCJOChpFdmVudFN0cmVhbUNvbnN1bWVyVG9vU2xvdxIwCg9ldmVudF9zdHJlYW1faWQYASABKAsyFy5kb2dtYS5wcm90b2J1Zi52MS5VVUlEQixaKmdpdGh1Yi5jb20vZG9nbWF0aXEvcHJvdG9idWYvbWVzc2FnaW5nZ3JwY2IIZWRpdGlvbnNw6Qc", [file_github_com_dogmatiq_protobuf_uuidpb_uuid]);
10
10
  /**
11
11
  * Describes the message dogma.messaging.v1.UnrecognizedEventStream.
12
12
  * Use `create(UnrecognizedEventStreamSchema)` to create a new message.
13
13
  */
14
14
  export const UnrecognizedEventStreamSchema = /*@__PURE__*/ messageDesc(file_github_com_dogmatiq_protobuf_messaginggrpc_errors, 0);
15
+ /**
16
+ * Describes the message dogma.messaging.v1.EventStreamConsumerTooSlow.
17
+ * Use `create(EventStreamConsumerTooSlowSchema)` to create a new message.
18
+ */
19
+ export const EventStreamConsumerTooSlowSchema = /*@__PURE__*/ messageDesc(file_github_com_dogmatiq_protobuf_messaginggrpc_errors, 1);
@@ -1,6 +1,7 @@
1
1
  import type { GenFile, GenMessage, GenService } from "@bufbuild/protobuf/codegenv2";
2
2
  import type { MultiEnvelope } from "../envelopepb/envelope_pb.js";
3
3
  import type { UUID } from "../uuidpb/uuid_pb.js";
4
+ import type { MessageFilter } from "./filter_pb.js";
4
5
  import type { Message } from "@bufbuild/protobuf";
5
6
  /**
6
7
  * Describes the file github.com/dogmatiq/protobuf/messaginggrpc/eventstreamconsumer.proto.
@@ -14,12 +15,11 @@ export declare const file_github_com_dogmatiq_protobuf_messaginggrpc_eventstream
14
15
  */
15
16
  export type WatchEventsRequest = Message<"dogma.messaging.v1.WatchEventsRequest"> & {
16
17
  /**
17
- * MessageTypeIds is the set of message type IDs of the event types to
18
- * include in the segments. An empty set matches every event.
18
+ * Filter describes the events to deliver.
19
19
  *
20
- * @generated from field: repeated dogma.protobuf.v1.UUID message_type_ids = 1;
20
+ * @generated from field: dogma.messaging.v1.MessageFilter filter = 1;
21
21
  */
22
- messageTypeIds: UUID[];
22
+ filter?: MessageFilter | undefined;
23
23
  };
24
24
  /**
25
25
  * Describes the message dogma.messaging.v1.WatchEventsRequest.
@@ -48,12 +48,11 @@ export type ReadEventsRequest = Message<"dogma.messaging.v1.ReadEventsRequest">
48
48
  */
49
49
  beginOffset: bigint;
50
50
  /**
51
- * MessageTypeIds is the set of message type IDs of the event types to
52
- * include in the segments. An empty set matches every event.
51
+ * Filter describes the events to deliver.
53
52
  *
54
- * @generated from field: repeated dogma.protobuf.v1.UUID message_type_ids = 3;
53
+ * @generated from field: dogma.messaging.v1.MessageFilter filter = 3;
55
54
  */
56
- messageTypeIds: UUID[];
55
+ filter?: MessageFilter | undefined;
57
56
  };
58
57
  /**
59
58
  * Describes the message dogma.messaging.v1.ReadEventsRequest.
@@ -120,25 +119,22 @@ export declare const EventStreamSegmentSchema: GenMessage<EventStreamSegment>;
120
119
  */
121
120
  export declare const EventStreamConsumerAPI: GenService<{
122
121
  /**
123
- * WatchEvents delivers events of the requested message types as they are
124
- * appended to any event stream offered by the server, for as long as the call
125
- * is open.
126
- *
127
- * The feed starts at the tail of each stream. The first [EventStreamSegment]
128
- * the client receives for a stream tells it that the stream exists and where
129
- * in the stream the feed begins. After this first segment, each subsequent
130
- * segment for the same stream begins at the end offset of the one before it.
131
- *
132
- * The server MAY send a first segment for every stream it offers, or only for
133
- * those streams that contain events of a requested type. In the latter case
134
- * the server MUST decide from the events in the stream, not from the types
135
- * that the server is able to record.
136
- *
137
- * If the server can no longer deliver a stream contiguously, for example
138
- * because the client has fallen too far behind, it closes the call. A client
139
- * that reconnects MUST expect to have missed events. On the new call, the
140
- * first segment it receives for each stream again tells it where the feed
141
- * begins, which is not necessarily where the previous call left off.
122
+ * WatchEvents delivers events from all streams available from the server.
123
+ * Events are delivered as they are appended, provided they match the
124
+ * request's filter.
125
+ *
126
+ * The feed starts at the tail of each stream. Every available stream that
127
+ * already contains matching events is represented by at least one segment.
128
+ * The first [EventStreamSegment] received for a stream may be empty, but it
129
+ * tells the client that the stream exists and the offset at which delivery
130
+ * begins. Each subsequent segment for that stream begins at the end offset
131
+ * of the previous segment.
132
+ *
133
+ * If the client cannot keep up and the server can no longer deliver a stream
134
+ * contiguously, the call ends with RESOURCE_EXHAUSTED and an attached
135
+ * [EventStreamConsumerTooSlow] value identifying the affected stream.
136
+ *
137
+ * A missing or invalid message filter results in INVALID_ARGUMENT.
142
138
  *
143
139
  * @generated from rpc dogma.messaging.v1.EventStreamConsumerAPI.WatchEvents
144
140
  */
@@ -148,20 +144,20 @@ export declare const EventStreamConsumerAPI: GenService<{
148
144
  output: typeof EventStreamSegmentSchema;
149
145
  };
150
146
  /**
151
- * ReadEvents delivers the events of the requested message types from a
152
- * single stream, in order, starting at a specific offset and ending at the
153
- * end of the stream as it stands when the server reaches it.
147
+ * ReadEvents delivers events that match the request's filter from a single
148
+ * event stream, in order, beginning at the requested offset.
149
+ *
150
+ * The first segment begins at the requested offset. Each subsequent segment
151
+ * begins at the end offset of the previous segment. Delivery ends when the
152
+ * server reaches the end of the stream, at which point it closes the call.
154
153
  *
155
- * It is intended for a consumer whose checkpoint is behind the offset at
156
- * which [EventStreamConsumerAPI.WatchEvents] began delivering the stream.
157
- * It delivers what the caller has missed, then the server closes the call.
154
+ * An unrecognized stream ID results in NOT_FOUND with an attached
155
+ * [UnrecognizedEventStream] value. See [UnrecognizedEventStreamError].
158
156
  *
159
- * If the requested stream ID is not recognized the server MUST return a
160
- * NOT_FOUND error with an attached [UnrecognizedEventStream] value. See
161
- * [UnrecognizedEventStreamError].
157
+ * A requested offset beyond the end of the stream results in OUT_OF_RANGE.
158
+ * An offset equal to the end of the stream is valid and returns no events.
162
159
  *
163
- * If the requested offset is greater than the offset that the next event
164
- * appended to the stream will have, an OUT_OF_RANGE error occurs.
160
+ * A missing or invalid message filter results in INVALID_ARGUMENT.
165
161
  *
166
162
  * @generated from rpc dogma.messaging.v1.EventStreamConsumerAPI.ReadEvents
167
163
  */
@@ -4,10 +4,11 @@
4
4
  import { fileDesc, messageDesc, serviceDesc } from "@bufbuild/protobuf/codegenv2";
5
5
  import { file_github_com_dogmatiq_protobuf_envelopepb_envelope } from "../envelopepb/envelope_pb.js";
6
6
  import { file_github_com_dogmatiq_protobuf_uuidpb_uuid } from "../uuidpb/uuid_pb.js";
7
+ import { file_github_com_dogmatiq_protobuf_messaginggrpc_filter } from "./filter_pb.js";
7
8
  /**
8
9
  * Describes the file github.com/dogmatiq/protobuf/messaginggrpc/eventstreamconsumer.proto.
9
10
  */
10
- export const file_github_com_dogmatiq_protobuf_messaginggrpc_eventstreamconsumer = /*@__PURE__*/ fileDesc("CkRnaXRodWIuY29tL2RvZ21hdGlxL3Byb3RvYnVmL21lc3NhZ2luZ2dycGMvZXZlbnRzdHJlYW1jb25zdW1lci5wcm90bxISZG9nbWEubWVzc2FnaW5nLnYxIkcKEldhdGNoRXZlbnRzUmVxdWVzdBIxChBtZXNzYWdlX3R5cGVfaWRzGAEgAygLMhcuZG9nbWEucHJvdG9idWYudjEuVVVJRCKVAQoRUmVhZEV2ZW50c1JlcXVlc3QSMAoPZXZlbnRfc3RyZWFtX2lkGAEgASgLMhcuZG9nbWEucHJvdG9idWYudjEuVVVJRBIbCgxiZWdpbl9vZmZzZXQYAiABKARCBaoBAggCEjEKEG1lc3NhZ2VfdHlwZV9pZHMYAyADKAsyFy5kb2dtYS5wcm90b2J1Zi52MS5VVUlEIrMBChJFdmVudFN0cmVhbVNlZ21lbnQSMAoPZXZlbnRfc3RyZWFtX2lkGAEgASgLMhcuZG9nbWEucHJvdG9idWYudjEuVVVJRBIbCgxiZWdpbl9vZmZzZXQYAiABKARCBaoBAggCEhkKCmVuZF9vZmZzZXQYAyABKARCBaoBAggCEjMKCWVudmVsb3BlcxgEIAMoCzIgLmRvZ21hLnByb3RvYnVmLnYxLk11bHRpRW52ZWxvcGUy2AEKFkV2ZW50U3RyZWFtQ29uc3VtZXJBUEkSXwoLV2F0Y2hFdmVudHMSJi5kb2dtYS5tZXNzYWdpbmcudjEuV2F0Y2hFdmVudHNSZXF1ZXN0GiYuZG9nbWEubWVzc2FnaW5nLnYxLkV2ZW50U3RyZWFtU2VnbWVudDABEl0KClJlYWRFdmVudHMSJS5kb2dtYS5tZXNzYWdpbmcudjEuUmVhZEV2ZW50c1JlcXVlc3QaJi5kb2dtYS5tZXNzYWdpbmcudjEuRXZlbnRTdHJlYW1TZWdtZW50MAFCLFoqZ2l0aHViLmNvbS9kb2dtYXRpcS9wcm90b2J1Zi9tZXNzYWdpbmdncnBjYghlZGl0aW9uc3DpBw", [file_github_com_dogmatiq_protobuf_envelopepb_envelope, file_github_com_dogmatiq_protobuf_uuidpb_uuid]);
11
+ export const file_github_com_dogmatiq_protobuf_messaginggrpc_eventstreamconsumer = /*@__PURE__*/ fileDesc("CkRnaXRodWIuY29tL2RvZ21hdGlxL3Byb3RvYnVmL21lc3NhZ2luZ2dycGMvZXZlbnRzdHJlYW1jb25zdW1lci5wcm90bxISZG9nbWEubWVzc2FnaW5nLnYxIkcKEldhdGNoRXZlbnRzUmVxdWVzdBIxCgZmaWx0ZXIYASABKAsyIS5kb2dtYS5tZXNzYWdpbmcudjEuTWVzc2FnZUZpbHRlciKVAQoRUmVhZEV2ZW50c1JlcXVlc3QSMAoPZXZlbnRfc3RyZWFtX2lkGAEgASgLMhcuZG9nbWEucHJvdG9idWYudjEuVVVJRBIbCgxiZWdpbl9vZmZzZXQYAiABKARCBaoBAggCEjEKBmZpbHRlchgDIAEoCzIhLmRvZ21hLm1lc3NhZ2luZy52MS5NZXNzYWdlRmlsdGVyIrMBChJFdmVudFN0cmVhbVNlZ21lbnQSMAoPZXZlbnRfc3RyZWFtX2lkGAEgASgLMhcuZG9nbWEucHJvdG9idWYudjEuVVVJRBIbCgxiZWdpbl9vZmZzZXQYAiABKARCBaoBAggCEhkKCmVuZF9vZmZzZXQYAyABKARCBaoBAggCEjMKCWVudmVsb3BlcxgEIAMoCzIgLmRvZ21hLnByb3RvYnVmLnYxLk11bHRpRW52ZWxvcGUy2AEKFkV2ZW50U3RyZWFtQ29uc3VtZXJBUEkSXwoLV2F0Y2hFdmVudHMSJi5kb2dtYS5tZXNzYWdpbmcudjEuV2F0Y2hFdmVudHNSZXF1ZXN0GiYuZG9nbWEubWVzc2FnaW5nLnYxLkV2ZW50U3RyZWFtU2VnbWVudDABEl0KClJlYWRFdmVudHMSJS5kb2dtYS5tZXNzYWdpbmcudjEuUmVhZEV2ZW50c1JlcXVlc3QaJi5kb2dtYS5tZXNzYWdpbmcudjEuRXZlbnRTdHJlYW1TZWdtZW50MAFCLFoqZ2l0aHViLmNvbS9kb2dtYXRpcS9wcm90b2J1Zi9tZXNzYWdpbmdncnBjYghlZGl0aW9uc3DpBw", [file_github_com_dogmatiq_protobuf_envelopepb_envelope, file_github_com_dogmatiq_protobuf_uuidpb_uuid, file_github_com_dogmatiq_protobuf_messaginggrpc_filter]);
11
12
  /**
12
13
  * Describes the message dogma.messaging.v1.WatchEventsRequest.
13
14
  * Use `create(WatchEventsRequestSchema)` to create a new message.
@@ -0,0 +1,6 @@
1
+ import type { MessageFilter } from "./filter_pb.js";
2
+ /**
3
+ * Throws an error if x matches no message types or contains an invalid message
4
+ * type ID.
5
+ */
6
+ export declare function validateMessageFilter(x: MessageFilter | undefined): void;
@@ -0,0 +1,23 @@
1
+ import { validateUUID } from "../uuidpb/uuid.js";
2
+ /**
3
+ * Throws an error if x matches no message types or contains an invalid message
4
+ * type ID.
5
+ */
6
+ export function validateMessageFilter(x) {
7
+ const types = x?.types;
8
+ if (types?.case === "all") {
9
+ return;
10
+ }
11
+ const ids = types?.case === "specific" ? types.value.ids : [];
12
+ if (ids.length === 0) {
13
+ throw new Error("message filter must match all message types or at least one specific type");
14
+ }
15
+ ids.forEach((id, i) => {
16
+ try {
17
+ validateUUID(id);
18
+ }
19
+ catch (cause) {
20
+ throw new Error(`invalid message type ID at index ${i}: ${cause.message}`, { cause });
21
+ }
22
+ });
23
+ }
@@ -0,0 +1,64 @@
1
+ import type { GenFile, GenMessage } from "@bufbuild/protobuf/codegenv2";
2
+ import type { Empty } from "@bufbuild/protobuf/wkt";
3
+ import type { UUID } from "../uuidpb/uuid_pb.js";
4
+ import type { Message } from "@bufbuild/protobuf";
5
+ /**
6
+ * Describes the file github.com/dogmatiq/protobuf/messaginggrpc/filter.proto.
7
+ */
8
+ export declare const file_github_com_dogmatiq_protobuf_messaginggrpc_filter: GenFile;
9
+ /**
10
+ * MessageFilter describes a set of messages to deliver.
11
+ *
12
+ * @generated from message dogma.messaging.v1.MessageFilter
13
+ */
14
+ export type MessageFilter = Message<"dogma.messaging.v1.MessageFilter"> & {
15
+ /**
16
+ * Types determines which message types match. One alternative must be set.
17
+ *
18
+ * @generated from oneof dogma.messaging.v1.MessageFilter.types
19
+ */
20
+ types: {
21
+ /**
22
+ * All matches all message types.
23
+ *
24
+ * @generated from field: google.protobuf.Empty all = 1;
25
+ */
26
+ value: Empty;
27
+ case: "all";
28
+ } | {
29
+ /**
30
+ * Specific matches the listed message types.
31
+ *
32
+ * @generated from field: dogma.messaging.v1.MessageFilter.MessageTypes specific = 2;
33
+ */
34
+ value: MessageFilter_MessageTypes;
35
+ case: "specific";
36
+ } | {
37
+ case: undefined;
38
+ value?: undefined;
39
+ };
40
+ };
41
+ /**
42
+ * Describes the message dogma.messaging.v1.MessageFilter.
43
+ * Use `create(MessageFilterSchema)` to create a new message.
44
+ */
45
+ export declare const MessageFilterSchema: GenMessage<MessageFilter>;
46
+ /**
47
+ * MessageTypes describes a set of specific message types.
48
+ *
49
+ * @generated from message dogma.messaging.v1.MessageFilter.MessageTypes
50
+ */
51
+ export type MessageFilter_MessageTypes = Message<"dogma.messaging.v1.MessageFilter.MessageTypes"> & {
52
+ /**
53
+ * Ids is the set of message type IDs that match the filter.
54
+ * The list must not be empty.
55
+ *
56
+ * @generated from field: repeated dogma.protobuf.v1.UUID ids = 1;
57
+ */
58
+ ids: UUID[];
59
+ };
60
+ /**
61
+ * Describes the message dogma.messaging.v1.MessageFilter.MessageTypes.
62
+ * Use `create(MessageFilter_MessageTypesSchema)` to create a new message.
63
+ */
64
+ export declare const MessageFilter_MessageTypesSchema: GenMessage<MessageFilter_MessageTypes>;
@@ -0,0 +1,20 @@
1
+ // @generated by protoc-gen-es v2.16.0 with parameter "target=ts,import_extension=js"
2
+ // @generated from file github.com/dogmatiq/protobuf/messaginggrpc/filter.proto (package dogma.messaging.v1, edition 2024)
3
+ /* eslint-disable */
4
+ import { fileDesc, messageDesc } from "@bufbuild/protobuf/codegenv2";
5
+ import { file_google_protobuf_empty } from "@bufbuild/protobuf/wkt";
6
+ import { file_github_com_dogmatiq_protobuf_uuidpb_uuid } from "../uuidpb/uuid_pb.js";
7
+ /**
8
+ * Describes the file github.com/dogmatiq/protobuf/messaginggrpc/filter.proto.
9
+ */
10
+ export const file_github_com_dogmatiq_protobuf_messaginggrpc_filter = /*@__PURE__*/ fileDesc("CjdnaXRodWIuY29tL2RvZ21hdGlxL3Byb3RvYnVmL21lc3NhZ2luZ2dycGMvZmlsdGVyLnByb3RvEhJkb2dtYS5tZXNzYWdpbmcudjEiuQEKDU1lc3NhZ2VGaWx0ZXISJQoDYWxsGAEgASgLMhYuZ29vZ2xlLnByb3RvYnVmLkVtcHR5SAASQgoIc3BlY2lmaWMYAiABKAsyLi5kb2dtYS5tZXNzYWdpbmcudjEuTWVzc2FnZUZpbHRlci5NZXNzYWdlVHlwZXNIABo0CgxNZXNzYWdlVHlwZXMSJAoDaWRzGAEgAygLMhcuZG9nbWEucHJvdG9idWYudjEuVVVJREIHCgV0eXBlc0IsWipnaXRodWIuY29tL2RvZ21hdGlxL3Byb3RvYnVmL21lc3NhZ2luZ2dycGNiCGVkaXRpb25zcOkH", [file_google_protobuf_empty, file_github_com_dogmatiq_protobuf_uuidpb_uuid]);
11
+ /**
12
+ * Describes the message dogma.messaging.v1.MessageFilter.
13
+ * Use `create(MessageFilterSchema)` to create a new message.
14
+ */
15
+ export const MessageFilterSchema = /*@__PURE__*/ messageDesc(file_github_com_dogmatiq_protobuf_messaginggrpc_filter, 0);
16
+ /**
17
+ * Describes the message dogma.messaging.v1.MessageFilter.MessageTypes.
18
+ * Use `create(MessageFilter_MessageTypesSchema)` to create a new message.
19
+ */
20
+ export const MessageFilter_MessageTypesSchema = /*@__PURE__*/ messageDesc(file_github_com_dogmatiq_protobuf_messaginggrpc_filter, 0, 0);
@@ -1,2 +1,4 @@
1
1
  export * from "./errors_pb.js";
2
2
  export * from "./eventstreamconsumer_pb.js";
3
+ export * from "./filter.js";
4
+ export * from "./filter_pb.js";
@@ -1,2 +1,4 @@
1
1
  export * from "./errors_pb.js";
2
2
  export * from "./eventstreamconsumer_pb.js";
3
+ export * from "./filter.js";
4
+ export * from "./filter_pb.js";
@@ -42,6 +42,12 @@ export function uuidEquals(a, b) {
42
42
  * (name-based) UUID.
43
43
  */
44
44
  export function validateUUID(x) {
45
+ if (x.upper < 0n ||
46
+ x.upper > MAX_UINT64 ||
47
+ x.lower < 0n ||
48
+ x.lower > MAX_UINT64) {
49
+ throw new Error("UUID components must be unsigned 64-bit integers");
50
+ }
45
51
  const version = (x.upper >> 8n) & 0xf0n;
46
52
  if (version !== 0x40n && version !== 0x50n) {
47
53
  throw new Error("UUID must use version 4 or 5");
@@ -82,6 +88,7 @@ export function parseUUID(str) {
82
88
  lower: BigInt("0x" + hex.slice(16)),
83
89
  });
84
90
  }
91
+ const MAX_UINT64 = 0xffffffffffffffffn;
85
92
  const PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
86
93
  // toBytes returns the 16-byte big-endian representation of a UUID.
87
94
  function toBytes(x) {
@@ -7,6 +7,9 @@ export declare const file_github_com_dogmatiq_protobuf_uuidpb_uuid: GenFile;
7
7
  /**
8
8
  * UUID is a size-optimized representation of an RFC 9562 UUID.
9
9
  *
10
+ * UUID values MUST use version 4 (random) or version 5 (name-based), and the
11
+ * RFC 9562 variant.
12
+ *
10
13
  * @generated from message dogma.protobuf.v1.UUID
11
14
  */
12
15
  export type UUID = Message<"dogma.protobuf.v1.UUID"> & {
@@ -10,7 +10,9 @@ import "github.com/dogmatiq/protobuf/uuidpb/uuid.proto";
10
10
 
11
11
  // Envelope is a container for a Dogma message and its meta-data.
12
12
  //
13
- // It is wire-compatible with [MultiEnvelope].
13
+ // An Envelope can be decoded as a single-body [MultiEnvelope]. Decoding a
14
+ // MultiEnvelope as an Envelope is only safe when it contains exactly one body;
15
+ // multiple bodies merge when decoded into the singular body field.
14
16
  message Envelope {
15
17
  Header header = 1;
16
18
  Body body = 2;
@@ -18,7 +20,6 @@ message Envelope {
18
20
 
19
21
  // MultiEnvelope is an efficient encoding of an ordered sequence of [Envelope]
20
22
  // values that share common header context.
21
- //
22
23
  message MultiEnvelope {
23
24
  Header header = 1;
24
25
  repeated Body bodies = 2;
@@ -73,6 +74,11 @@ message Message {
73
74
  bytes data = 3 [features.field_presence = IMPLICIT];
74
75
  }
75
76
 
77
+ // Header contains origin and causal context that can be common to messages
78
+ // produced by the same cause.
79
+ //
80
+ // Extensions and baggage from the header and body are combined by message
81
+ // type. Body values take precedence over header values of the same type.
76
82
  message Header {
77
83
  // CausationId is the ID of the message that was the direct cause of the
78
84
  // messages.
@@ -11,6 +11,8 @@ import "github.com/dogmatiq/protobuf/uuidpb/uuid.proto";
11
11
  message Identity {
12
12
  // Name is the entity's human-readable name.
13
13
  //
14
+ // The name MUST be between 1 and 255 bytes when encoded as UTF-8.
15
+ //
14
16
  // The name should be unique enough to allow a human to identify the entity
15
17
  // without ambiguity. There is no hard requirement for uniqueness.
16
18
  //
@@ -11,3 +11,15 @@ message UnrecognizedEventStream {
11
11
  // EventStreamId is the ID of the unrecognized stream.
12
12
  dogma.protobuf.v1.UUID event_stream_id = 1;
13
13
  }
14
+
15
+ // EventStreamConsumerTooSlow is an error-details value for RESOURCE_EXHAUSTED
16
+ // errors returned by WatchEvents when a client cannot keep up and the server
17
+ // can no longer deliver a stream contiguously.
18
+ //
19
+ // A client that is behind the tail does not cause this error while contiguous
20
+ // delivery remains possible.
21
+ message EventStreamConsumerTooSlow {
22
+ // EventStreamId is the ID of the stream that could no longer be delivered
23
+ // contiguously.
24
+ dogma.protobuf.v1.UUID event_stream_id = 1;
25
+ }
@@ -5,54 +5,51 @@ option go_package = "github.com/dogmatiq/protobuf/messaginggrpc";
5
5
 
6
6
  import "github.com/dogmatiq/protobuf/envelopepb/envelope.proto";
7
7
  import "github.com/dogmatiq/protobuf/uuidpb/uuid.proto";
8
+ import "github.com/dogmatiq/protobuf/messaginggrpc/filter.proto";
8
9
 
9
10
  // EventStreamConsumerAPI is a service for consuming event messages from
10
11
  // offset-based, ordered event streams.
11
12
  service EventStreamConsumerAPI {
12
- // WatchEvents delivers events of the requested message types as they are
13
- // appended to any event stream offered by the server, for as long as the call
14
- // is open.
13
+ // WatchEvents delivers events from all streams available from the server.
14
+ // Events are delivered as they are appended, provided they match the
15
+ // request's filter.
15
16
  //
16
- // The feed starts at the tail of each stream. The first [EventStreamSegment]
17
- // the client receives for a stream tells it that the stream exists and where
18
- // in the stream the feed begins. After this first segment, each subsequent
19
- // segment for the same stream begins at the end offset of the one before it.
17
+ // The feed starts at the tail of each stream. Every available stream that
18
+ // already contains matching events is represented by at least one segment.
19
+ // The first [EventStreamSegment] received for a stream may be empty, but it
20
+ // tells the client that the stream exists and the offset at which delivery
21
+ // begins. Each subsequent segment for that stream begins at the end offset
22
+ // of the previous segment.
20
23
  //
21
- // The server MAY send a first segment for every stream it offers, or only for
22
- // those streams that contain events of a requested type. In the latter case
23
- // the server MUST decide from the events in the stream, not from the types
24
- // that the server is able to record.
24
+ // If the client cannot keep up and the server can no longer deliver a stream
25
+ // contiguously, the call ends with RESOURCE_EXHAUSTED and an attached
26
+ // [EventStreamConsumerTooSlow] value identifying the affected stream.
25
27
  //
26
- // If the server can no longer deliver a stream contiguously, for example
27
- // because the client has fallen too far behind, it closes the call. A client
28
- // that reconnects MUST expect to have missed events. On the new call, the
29
- // first segment it receives for each stream again tells it where the feed
30
- // begins, which is not necessarily where the previous call left off.
28
+ // A missing or invalid message filter results in INVALID_ARGUMENT.
31
29
  rpc WatchEvents(WatchEventsRequest) returns (stream EventStreamSegment);
32
30
 
33
- // ReadEvents delivers the events of the requested message types from a
34
- // single stream, in order, starting at a specific offset and ending at the
35
- // end of the stream as it stands when the server reaches it.
31
+ // ReadEvents delivers events that match the request's filter from a single
32
+ // event stream, in order, beginning at the requested offset.
36
33
  //
37
- // It is intended for a consumer whose checkpoint is behind the offset at
38
- // which [EventStreamConsumerAPI.WatchEvents] began delivering the stream.
39
- // It delivers what the caller has missed, then the server closes the call.
34
+ // The first segment begins at the requested offset. Each subsequent segment
35
+ // begins at the end offset of the previous segment. Delivery ends when the
36
+ // server reaches the end of the stream, at which point it closes the call.
40
37
  //
41
- // If the requested stream ID is not recognized the server MUST return a
42
- // NOT_FOUND error with an attached [UnrecognizedEventStream] value. See
43
- // [UnrecognizedEventStreamError].
38
+ // An unrecognized stream ID results in NOT_FOUND with an attached
39
+ // [UnrecognizedEventStream] value. See [UnrecognizedEventStreamError].
44
40
  //
45
- // If the requested offset is greater than the offset that the next event
46
- // appended to the stream will have, an OUT_OF_RANGE error occurs.
41
+ // A requested offset beyond the end of the stream results in OUT_OF_RANGE.
42
+ // An offset equal to the end of the stream is valid and returns no events.
43
+ //
44
+ // A missing or invalid message filter results in INVALID_ARGUMENT.
47
45
  rpc ReadEvents(ReadEventsRequest) returns (stream EventStreamSegment);
48
46
  }
49
47
 
50
48
  // WatchEventsRequest is the input to the [EventStreamConsumerAPI.WatchEvents]
51
49
  // method.
52
50
  message WatchEventsRequest {
53
- // MessageTypeIds is the set of message type IDs of the event types to
54
- // include in the segments. An empty set matches every event.
55
- repeated dogma.protobuf.v1.UUID message_type_ids = 1;
51
+ // Filter describes the events to deliver.
52
+ MessageFilter filter = 1;
56
53
  }
57
54
 
58
55
  // ReadEventsRequest is the input to the [EventStreamConsumerAPI.ReadEvents]
@@ -66,9 +63,8 @@ message ReadEventsRequest {
66
63
  // are delivered, then the call is closed.
67
64
  uint64 begin_offset = 2 [features.field_presence = IMPLICIT];
68
65
 
69
- // MessageTypeIds is the set of message type IDs of the event types to
70
- // include in the segments. An empty set matches every event.
71
- repeated dogma.protobuf.v1.UUID message_type_ids = 3;
66
+ // Filter describes the events to deliver.
67
+ MessageFilter filter = 3;
72
68
  }
73
69
 
74
70
  // EventStreamSegment is a contiguous piece of one event stream, the half-open
@@ -0,0 +1,26 @@
1
+ edition = "2024";
2
+ package dogma.messaging.v1;
3
+
4
+ option go_package = "github.com/dogmatiq/protobuf/messaginggrpc";
5
+
6
+ import "google/protobuf/empty.proto";
7
+ import "github.com/dogmatiq/protobuf/uuidpb/uuid.proto";
8
+
9
+ // MessageFilter describes a set of messages to deliver.
10
+ message MessageFilter {
11
+ // MessageTypes describes a set of specific message types.
12
+ message MessageTypes {
13
+ // Ids is the set of message type IDs that match the filter.
14
+ // The list must not be empty.
15
+ repeated dogma.protobuf.v1.UUID ids = 1;
16
+ }
17
+
18
+ // Types determines which message types match. One alternative must be set.
19
+ oneof types {
20
+ // All matches all message types.
21
+ google.protobuf.Empty all = 1;
22
+
23
+ // Specific matches the listed message types.
24
+ MessageTypes specific = 2;
25
+ }
26
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dogmatiq/protobuf",
3
- "version": "0.4.1",
3
+ "version": "0.6.0",
4
4
  "description": "Protocol Buffers and gRPC definitions for Dogma",
5
5
  "keywords": [
6
6
  "dogma",
@@ -62,7 +62,7 @@
62
62
  "@arethetypeswrong/cli": "^0.18.5",
63
63
  "@bufbuild/protobuf": "^2.16.0",
64
64
  "@bufbuild/protoc-gen-es": "^2.16.0",
65
- "@types/node": "^20.19.43",
65
+ "@types/node": "^26.6.6",
66
66
  "@vitest/coverage-v8": "^5.0.5",
67
67
  "prettier": "^3.9.10",
68
68
  "prettier-plugin-organize-imports": "^4.3.0",
package/uuidpb/uuid.proto CHANGED
@@ -4,6 +4,9 @@ package dogma.protobuf.v1;
4
4
  option go_package = "github.com/dogmatiq/protobuf/uuidpb";
5
5
 
6
6
  // UUID is a size-optimized representation of an RFC 9562 UUID.
7
+ //
8
+ // UUID values MUST use version 4 (random) or version 5 (name-based), and the
9
+ // RFC 9562 variant.
7
10
  message UUID {
8
11
  uint64 upper = 1 [features.field_presence = IMPLICIT];
9
12
  uint64 lower = 2 [features.field_presence = IMPLICIT];