@gomessaging/messaging 0.0.1
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.
- package/README.md +185 -0
- package/dist/cloudevents.d.ts +73 -0
- package/dist/cloudevents.d.ts.map +1 -0
- package/dist/cloudevents.js +148 -0
- package/dist/cloudevents.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/metrics.d.ts +40 -0
- package/dist/metrics.d.ts.map +1 -0
- package/dist/metrics.js +11 -0
- package/dist/metrics.js.map +1 -0
- package/dist/naming.d.ts +54 -0
- package/dist/naming.d.ts.map +1 -0
- package/dist/naming.js +78 -0
- package/dist/naming.js.map +1 -0
- package/dist/routing.d.ts +10 -0
- package/dist/routing.d.ts.map +1 -0
- package/dist/routing.js +41 -0
- package/dist/routing.js.map +1 -0
- package/dist/topology.d.ts +2 -0
- package/dist/topology.d.ts.map +1 -0
- package/dist/topology.js +4 -0
- package/dist/topology.js.map +1 -0
- package/dist/types.d.ts +73 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +5 -0
- package/dist/types.js.map +1 -0
- package/dist/validate.d.ts +12 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +138 -0
- package/dist/validate.js.map +1 -0
- package/dist/visualize.d.ts +10 -0
- package/dist/visualize.d.ts.map +1 -0
- package/dist/visualize.js +134 -0
- package/dist/visualize.js.map +1 -0
- package/package.json +34 -0
- package/src/cloudevents.ts +166 -0
- package/src/index.ts +86 -0
- package/src/metrics.ts +58 -0
- package/src/naming.ts +94 -0
- package/src/routing.ts +39 -0
- package/src/topology.ts +13 -0
- package/src/types.ts +101 -0
- package/src/validate.ts +183 -0
- package/src/visualize.ts +167 -0
package/README.md
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# @gomessaging/messaging
|
|
2
|
+
|
|
3
|
+
TypeScript implementation of the [messaging specification](https://codeberg.org/messaging/messaging). This package mirrors the Go messaging library, providing identical naming functions, validation, CloudEvents handling, routing, and visualization for Node.js/TypeScript transport implementations.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npm install @gomessaging/messaging
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import {
|
|
15
|
+
// Naming
|
|
16
|
+
topicExchangeName,
|
|
17
|
+
serviceEventQueueName,
|
|
18
|
+
natsStreamName,
|
|
19
|
+
natsSubject,
|
|
20
|
+
|
|
21
|
+
// CloudEvents
|
|
22
|
+
validateCEHeaders,
|
|
23
|
+
metadataFromHeaders,
|
|
24
|
+
normalizeCEHeaders,
|
|
25
|
+
hasCEHeaders,
|
|
26
|
+
enrichLegacyMetadata,
|
|
27
|
+
|
|
28
|
+
// Validation
|
|
29
|
+
validate,
|
|
30
|
+
validateTopologies,
|
|
31
|
+
|
|
32
|
+
// Visualization
|
|
33
|
+
mermaid,
|
|
34
|
+
|
|
35
|
+
// Routing
|
|
36
|
+
matchRoutingKey,
|
|
37
|
+
routingKeyOverlaps,
|
|
38
|
+
|
|
39
|
+
// Types
|
|
40
|
+
type Topology,
|
|
41
|
+
type Endpoint,
|
|
42
|
+
type ConsumableEvent,
|
|
43
|
+
type Metadata,
|
|
44
|
+
type EventHandler,
|
|
45
|
+
} from "@gomessaging/messaging";
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
### Naming
|
|
49
|
+
|
|
50
|
+
Deterministic resource names for AMQP and NATS:
|
|
51
|
+
|
|
52
|
+
```typescript
|
|
53
|
+
topicExchangeName("events");
|
|
54
|
+
// "events.topic.exchange"
|
|
55
|
+
|
|
56
|
+
serviceEventQueueName("events.topic.exchange", "notifications");
|
|
57
|
+
// "events.topic.exchange.queue.notifications"
|
|
58
|
+
|
|
59
|
+
natsStreamName("audit.topic.exchange");
|
|
60
|
+
// "audit"
|
|
61
|
+
|
|
62
|
+
natsSubject("events", "Order.Created");
|
|
63
|
+
// "events.Order.Created"
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### Validation
|
|
67
|
+
|
|
68
|
+
Validate service topologies statically:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
const errors = validate(topology);
|
|
72
|
+
|
|
73
|
+
// Cross-validate multiple services
|
|
74
|
+
const errors = validateTopologies([orderTopology, notificationTopology]);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### CloudEvents
|
|
78
|
+
|
|
79
|
+
Parse and validate CloudEvents headers:
|
|
80
|
+
|
|
81
|
+
```typescript
|
|
82
|
+
const warnings = validateCEHeaders(headers);
|
|
83
|
+
const metadata = metadataFromHeaders(headers);
|
|
84
|
+
|
|
85
|
+
// Normalize AMQP prefixes (cloudEvents:type → ce-type)
|
|
86
|
+
const normalized = normalizeCEHeaders(headers);
|
|
87
|
+
|
|
88
|
+
// Enrich legacy messages without CE headers
|
|
89
|
+
const enriched = enrichLegacyMetadata(metadata, deliveryInfo, () => crypto.randomUUID());
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
### Visualization
|
|
93
|
+
|
|
94
|
+
Generate Mermaid diagrams:
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
const diagram = mermaid([orderTopology, notificationTopology]);
|
|
98
|
+
// Returns a Mermaid flowchart string
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### Routing
|
|
102
|
+
|
|
103
|
+
Match routing keys with AMQP-style wildcards:
|
|
104
|
+
|
|
105
|
+
```typescript
|
|
106
|
+
matchRoutingKey("Order.*", "Order.Created"); // true
|
|
107
|
+
matchRoutingKey("Order.*", "Order.Item.Added"); // false
|
|
108
|
+
routingKeyOverlaps("Order.*", "Order.Created"); // true
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## API Reference
|
|
112
|
+
|
|
113
|
+
### Naming Functions
|
|
114
|
+
|
|
115
|
+
| Function | Signature | Description |
|
|
116
|
+
|----------|-----------|-------------|
|
|
117
|
+
| `topicExchangeName` | `(name: string) => string` | Topic exchange name |
|
|
118
|
+
| `serviceEventQueueName` | `(exchange: string, service: string) => string` | Event consumer queue |
|
|
119
|
+
| `serviceRequestExchangeName` | `(service: string) => string` | Request exchange |
|
|
120
|
+
| `serviceResponseExchangeName` | `(service: string) => string` | Response exchange |
|
|
121
|
+
| `serviceRequestQueueName` | `(service: string) => string` | Request queue |
|
|
122
|
+
| `serviceResponseQueueName` | `(target: string, service: string) => string` | Response queue |
|
|
123
|
+
| `natsStreamName` | `(name: string) => string` | NATS stream name |
|
|
124
|
+
| `natsSubject` | `(stream: string, routingKey: string) => string` | NATS subject |
|
|
125
|
+
| `translateWildcard` | `(routingKey: string) => string` | AMQP `#` to NATS `>` |
|
|
126
|
+
|
|
127
|
+
### Validation Functions
|
|
128
|
+
|
|
129
|
+
| Function | Signature | Description |
|
|
130
|
+
|----------|-----------|-------------|
|
|
131
|
+
| `validate` | `(topology: Topology) => string \| null` | Single-service validation |
|
|
132
|
+
| `validateTopologies` | `(topologies: Topology[]) => string \| null` | Cross-service validation |
|
|
133
|
+
|
|
134
|
+
### CloudEvents Functions
|
|
135
|
+
|
|
136
|
+
| Function | Signature | Description |
|
|
137
|
+
|----------|-----------|-------------|
|
|
138
|
+
| `validateCEHeaders` | `(headers: Headers) => string[]` | Validate CE headers, returns warnings |
|
|
139
|
+
| `metadataFromHeaders` | `(headers: Headers) => Metadata` | Parse headers into Metadata |
|
|
140
|
+
| `normalizeCEHeaders` | `(headers: Headers) => Headers` | Normalize prefix to `ce-` |
|
|
141
|
+
| `hasCEHeaders` | `(headers: Headers) => boolean` | Check if any CE headers present |
|
|
142
|
+
| `enrichLegacyMetadata` | `(m: Metadata, d: DeliveryInfo, idGen: () => string) => Metadata` | Enrich missing fields |
|
|
143
|
+
|
|
144
|
+
### Core Types
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
type Transport = "amqp" | "nats";
|
|
148
|
+
type EndpointDirection = "publish" | "consume";
|
|
149
|
+
type ExchangeKind = "topic" | "direct" | "headers";
|
|
150
|
+
type Pattern = "event-stream" | "custom-stream" | "service-request" | "service-response" | "queue-publish";
|
|
151
|
+
|
|
152
|
+
interface Endpoint {
|
|
153
|
+
direction: EndpointDirection;
|
|
154
|
+
pattern: Pattern;
|
|
155
|
+
exchangeName: string;
|
|
156
|
+
exchangeKind: ExchangeKind;
|
|
157
|
+
queueName?: string;
|
|
158
|
+
routingKey?: string;
|
|
159
|
+
messageType?: string;
|
|
160
|
+
ephemeral?: boolean;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
interface Topology {
|
|
164
|
+
transport: Transport;
|
|
165
|
+
serviceName: string;
|
|
166
|
+
endpoints: Endpoint[];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
interface ConsumableEvent<T> extends Metadata {
|
|
170
|
+
deliveryInfo: DeliveryInfo;
|
|
171
|
+
payload: T;
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Conformance
|
|
176
|
+
|
|
177
|
+
This package is tested against the shared JSON fixtures in [`testdata/`](../testdata/). The same fixtures are used by the Go messaging library, ensuring both implementations produce identical outputs.
|
|
178
|
+
|
|
179
|
+
```sh
|
|
180
|
+
npm test
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
## License
|
|
184
|
+
|
|
185
|
+
MIT
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { DeliveryInfo, Headers, Metadata } from "./types.js";
|
|
2
|
+
/** CloudEvents attribute header keys for binary content mode (canonical "ce-" prefix). */
|
|
3
|
+
export declare const CESpecVersion = "ce-specversion";
|
|
4
|
+
export declare const CEType = "ce-type";
|
|
5
|
+
export declare const CESource = "ce-source";
|
|
6
|
+
export declare const CEID = "ce-id";
|
|
7
|
+
export declare const CETime = "ce-time";
|
|
8
|
+
export declare const CESpecVersionValue = "1.0";
|
|
9
|
+
/** Optional CE attributes */
|
|
10
|
+
export declare const CEDataContentType = "ce-datacontenttype";
|
|
11
|
+
export declare const CESubject = "ce-subject";
|
|
12
|
+
export declare const CEDataSchema = "ce-dataschema";
|
|
13
|
+
/** Extension attribute for correlation */
|
|
14
|
+
export declare const CECorrelationID = "ce-correlationid";
|
|
15
|
+
/** Bare CE attribute names (without prefix). */
|
|
16
|
+
export declare const CEAttrSpecVersion = "specversion";
|
|
17
|
+
export declare const CEAttrType = "type";
|
|
18
|
+
export declare const CEAttrSource = "source";
|
|
19
|
+
export declare const CEAttrID = "id";
|
|
20
|
+
export declare const CEAttrTime = "time";
|
|
21
|
+
export declare const CEAttrDataContentType = "datacontenttype";
|
|
22
|
+
export declare const CEAttrSubject = "subject";
|
|
23
|
+
export declare const CEAttrCorrelationID = "correlationid";
|
|
24
|
+
/** CERequiredAttributes lists header keys required by CE 1.0. */
|
|
25
|
+
export declare const CERequiredAttributes: string[];
|
|
26
|
+
/**
|
|
27
|
+
* AMQPCEHeaderKey returns the AMQP application-properties key for a bare
|
|
28
|
+
* CloudEvents attribute name, using the "cloudEvents:" prefix per the
|
|
29
|
+
* CloudEvents AMQP Protocol Binding specification.
|
|
30
|
+
* Example: AMQPCEHeaderKey("specversion") -> "cloudEvents:specversion"
|
|
31
|
+
*/
|
|
32
|
+
export declare function AMQPCEHeaderKey(attr: string): string;
|
|
33
|
+
/**
|
|
34
|
+
* NormalizeCEHeaders rewrites incoming transport headers so that all
|
|
35
|
+
* CloudEvents attributes use the canonical "ce-" prefix. This allows
|
|
36
|
+
* consumers to accept messages with any known prefix variant:
|
|
37
|
+
* - "cloudEvents:specversion" -> "ce-specversion"
|
|
38
|
+
* - "cloudEvents_specversion" -> "ce-specversion" (JMS compat)
|
|
39
|
+
* - "ce-specversion" -> unchanged
|
|
40
|
+
*
|
|
41
|
+
* Non-CE headers are preserved unchanged. A new object is returned.
|
|
42
|
+
*/
|
|
43
|
+
export declare function normalizeCEHeaders(h: Headers): Headers;
|
|
44
|
+
/**
|
|
45
|
+
* HasCEHeaders reports whether h contains at least one CE required attribute,
|
|
46
|
+
* checking for "ce-", "cloudEvents:", and "cloudEvents_" prefixes.
|
|
47
|
+
* Use this to distinguish legacy (pre-CloudEvents) messages from malformed CE messages.
|
|
48
|
+
*/
|
|
49
|
+
export declare function hasCEHeaders(h: Headers): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* EnrichLegacyMetadata populates empty Metadata fields with synthetic
|
|
52
|
+
* CloudEvents attributes derived from transport delivery information.
|
|
53
|
+
*
|
|
54
|
+
* Fields set when empty: id (randomUUID), timestamp (now), type (from key),
|
|
55
|
+
* source (from source), dataContentType ("application/json"), specVersion ("1.0").
|
|
56
|
+
*
|
|
57
|
+
* Fields NOT set: correlationId, subject (cannot be inferred).
|
|
58
|
+
* Any non-empty fields in m are preserved (not overwritten).
|
|
59
|
+
* Returns a new Metadata object; the input is not mutated.
|
|
60
|
+
*/
|
|
61
|
+
export declare function enrichLegacyMetadata(m: Metadata, info: DeliveryInfo): Metadata;
|
|
62
|
+
/**
|
|
63
|
+
* MetadataFromHeaders extracts CloudEvents metadata from message headers
|
|
64
|
+
* into a Metadata struct. Invalid (non-RFC3339) timestamps return empty string.
|
|
65
|
+
*/
|
|
66
|
+
export declare function metadataFromHeaders(h: Headers): Metadata;
|
|
67
|
+
/**
|
|
68
|
+
* ValidateCEHeaders checks that all required CloudEvents 1.0 attributes
|
|
69
|
+
* are present and are strings. Returns a list of warnings for any
|
|
70
|
+
* missing or non-string attributes.
|
|
71
|
+
*/
|
|
72
|
+
export declare function validateCEHeaders(h: Headers): string[];
|
|
73
|
+
//# sourceMappingURL=cloudevents.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudevents.d.ts","sourceRoot":"","sources":["../src/cloudevents.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAElE,0FAA0F;AAC1F,eAAO,MAAM,aAAa,mBAAmB,CAAC;AAC9C,eAAO,MAAM,MAAM,YAAY,CAAC;AAChC,eAAO,MAAM,QAAQ,cAAc,CAAC;AACpC,eAAO,MAAM,IAAI,UAAU,CAAC;AAC5B,eAAO,MAAM,MAAM,YAAY,CAAC;AAChC,eAAO,MAAM,kBAAkB,QAAQ,CAAC;AAExC,6BAA6B;AAC7B,eAAO,MAAM,iBAAiB,uBAAuB,CAAC;AACtD,eAAO,MAAM,SAAS,eAAe,CAAC;AACtC,eAAO,MAAM,YAAY,kBAAkB,CAAC;AAE5C,0CAA0C;AAC1C,eAAO,MAAM,eAAe,qBAAqB,CAAC;AAElD,gDAAgD;AAChD,eAAO,MAAM,iBAAiB,gBAAgB,CAAC;AAC/C,eAAO,MAAM,UAAU,SAAS,CAAC;AACjC,eAAO,MAAM,YAAY,WAAW,CAAC;AACrC,eAAO,MAAM,QAAQ,OAAO,CAAC;AAC7B,eAAO,MAAM,UAAU,SAAS,CAAC;AACjC,eAAO,MAAM,qBAAqB,oBAAoB,CAAC;AACvD,eAAO,MAAM,aAAa,YAAY,CAAC;AACvC,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AAEnD,iEAAiE;AACjE,eAAO,MAAM,oBAAoB,UAMhC,CAAC;AAEF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAYtD;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAWhD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,oBAAoB,CAClC,CAAC,EAAE,QAAQ,EACX,IAAI,EAAE,YAAY,GACjB,QAAQ,CAUV;AAcD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EAAE,OAAO,GAAG,QAAQ,CAYxD;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,EAAE,CAYtD"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// MIT License
|
|
2
|
+
// Copyright (c) 2026 sparetimecoders
|
|
3
|
+
/** CloudEvents attribute header keys for binary content mode (canonical "ce-" prefix). */
|
|
4
|
+
export const CESpecVersion = "ce-specversion";
|
|
5
|
+
export const CEType = "ce-type";
|
|
6
|
+
export const CESource = "ce-source";
|
|
7
|
+
export const CEID = "ce-id";
|
|
8
|
+
export const CETime = "ce-time";
|
|
9
|
+
export const CESpecVersionValue = "1.0";
|
|
10
|
+
/** Optional CE attributes */
|
|
11
|
+
export const CEDataContentType = "ce-datacontenttype";
|
|
12
|
+
export const CESubject = "ce-subject";
|
|
13
|
+
export const CEDataSchema = "ce-dataschema";
|
|
14
|
+
/** Extension attribute for correlation */
|
|
15
|
+
export const CECorrelationID = "ce-correlationid";
|
|
16
|
+
/** Bare CE attribute names (without prefix). */
|
|
17
|
+
export const CEAttrSpecVersion = "specversion";
|
|
18
|
+
export const CEAttrType = "type";
|
|
19
|
+
export const CEAttrSource = "source";
|
|
20
|
+
export const CEAttrID = "id";
|
|
21
|
+
export const CEAttrTime = "time";
|
|
22
|
+
export const CEAttrDataContentType = "datacontenttype";
|
|
23
|
+
export const CEAttrSubject = "subject";
|
|
24
|
+
export const CEAttrCorrelationID = "correlationid";
|
|
25
|
+
/** CERequiredAttributes lists header keys required by CE 1.0. */
|
|
26
|
+
export const CERequiredAttributes = [
|
|
27
|
+
CESpecVersion,
|
|
28
|
+
CEType,
|
|
29
|
+
CESource,
|
|
30
|
+
CEID,
|
|
31
|
+
CETime,
|
|
32
|
+
];
|
|
33
|
+
/**
|
|
34
|
+
* AMQPCEHeaderKey returns the AMQP application-properties key for a bare
|
|
35
|
+
* CloudEvents attribute name, using the "cloudEvents:" prefix per the
|
|
36
|
+
* CloudEvents AMQP Protocol Binding specification.
|
|
37
|
+
* Example: AMQPCEHeaderKey("specversion") -> "cloudEvents:specversion"
|
|
38
|
+
*/
|
|
39
|
+
export function AMQPCEHeaderKey(attr) {
|
|
40
|
+
return "cloudEvents:" + attr;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* NormalizeCEHeaders rewrites incoming transport headers so that all
|
|
44
|
+
* CloudEvents attributes use the canonical "ce-" prefix. This allows
|
|
45
|
+
* consumers to accept messages with any known prefix variant:
|
|
46
|
+
* - "cloudEvents:specversion" -> "ce-specversion"
|
|
47
|
+
* - "cloudEvents_specversion" -> "ce-specversion" (JMS compat)
|
|
48
|
+
* - "ce-specversion" -> unchanged
|
|
49
|
+
*
|
|
50
|
+
* Non-CE headers are preserved unchanged. A new object is returned.
|
|
51
|
+
*/
|
|
52
|
+
export function normalizeCEHeaders(h) {
|
|
53
|
+
const out = {};
|
|
54
|
+
for (const [k, v] of Object.entries(h)) {
|
|
55
|
+
if (k.startsWith("cloudEvents:")) {
|
|
56
|
+
out["ce-" + k.slice("cloudEvents:".length)] = v;
|
|
57
|
+
}
|
|
58
|
+
else if (k.startsWith("cloudEvents_")) {
|
|
59
|
+
out["ce-" + k.slice("cloudEvents_".length)] = v;
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
out[k] = v;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return out;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* HasCEHeaders reports whether h contains at least one CE required attribute,
|
|
69
|
+
* checking for "ce-", "cloudEvents:", and "cloudEvents_" prefixes.
|
|
70
|
+
* Use this to distinguish legacy (pre-CloudEvents) messages from malformed CE messages.
|
|
71
|
+
*/
|
|
72
|
+
export function hasCEHeaders(h) {
|
|
73
|
+
for (const key of Object.keys(h)) {
|
|
74
|
+
if (key.startsWith("ce-") ||
|
|
75
|
+
key.startsWith("cloudEvents:") ||
|
|
76
|
+
key.startsWith("cloudEvents_")) {
|
|
77
|
+
return true;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return false;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* EnrichLegacyMetadata populates empty Metadata fields with synthetic
|
|
84
|
+
* CloudEvents attributes derived from transport delivery information.
|
|
85
|
+
*
|
|
86
|
+
* Fields set when empty: id (randomUUID), timestamp (now), type (from key),
|
|
87
|
+
* source (from source), dataContentType ("application/json"), specVersion ("1.0").
|
|
88
|
+
*
|
|
89
|
+
* Fields NOT set: correlationId, subject (cannot be inferred).
|
|
90
|
+
* Any non-empty fields in m are preserved (not overwritten).
|
|
91
|
+
* Returns a new Metadata object; the input is not mutated.
|
|
92
|
+
*/
|
|
93
|
+
export function enrichLegacyMetadata(m, info) {
|
|
94
|
+
return {
|
|
95
|
+
...m,
|
|
96
|
+
id: m.id || crypto.randomUUID(),
|
|
97
|
+
timestamp: m.timestamp || new Date().toISOString(),
|
|
98
|
+
type: m.type || info.key,
|
|
99
|
+
source: m.source || info.source,
|
|
100
|
+
dataContentType: m.dataContentType || "application/json",
|
|
101
|
+
specVersion: m.specVersion || CESpecVersionValue,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
/** RFC 3339 regex for timestamp validation. */
|
|
105
|
+
const RFC3339_RE = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2})$/;
|
|
106
|
+
function headerString(h, key) {
|
|
107
|
+
const v = h[key];
|
|
108
|
+
if (typeof v === "string") {
|
|
109
|
+
return v;
|
|
110
|
+
}
|
|
111
|
+
return "";
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* MetadataFromHeaders extracts CloudEvents metadata from message headers
|
|
115
|
+
* into a Metadata struct. Invalid (non-RFC3339) timestamps return empty string.
|
|
116
|
+
*/
|
|
117
|
+
export function metadataFromHeaders(h) {
|
|
118
|
+
const timeStr = headerString(h, CETime);
|
|
119
|
+
return {
|
|
120
|
+
id: headerString(h, CEID),
|
|
121
|
+
source: headerString(h, CESource),
|
|
122
|
+
type: headerString(h, CEType),
|
|
123
|
+
subject: headerString(h, CESubject),
|
|
124
|
+
dataContentType: headerString(h, CEDataContentType),
|
|
125
|
+
specVersion: headerString(h, CESpecVersion),
|
|
126
|
+
correlationId: headerString(h, CECorrelationID),
|
|
127
|
+
timestamp: RFC3339_RE.test(timeStr) ? timeStr : "",
|
|
128
|
+
};
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* ValidateCEHeaders checks that all required CloudEvents 1.0 attributes
|
|
132
|
+
* are present and are strings. Returns a list of warnings for any
|
|
133
|
+
* missing or non-string attributes.
|
|
134
|
+
*/
|
|
135
|
+
export function validateCEHeaders(h) {
|
|
136
|
+
const warnings = [];
|
|
137
|
+
for (const key of CERequiredAttributes) {
|
|
138
|
+
if (!(key in h)) {
|
|
139
|
+
warnings.push(`missing required attribute "${key}"`);
|
|
140
|
+
continue;
|
|
141
|
+
}
|
|
142
|
+
if (typeof h[key] !== "string") {
|
|
143
|
+
warnings.push(`attribute "${key}" is not a string`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return warnings;
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=cloudevents.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cloudevents.js","sourceRoot":"","sources":["../src/cloudevents.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type { Transport, EndpointDirection, ExchangeKind, Pattern, Headers, Metadata, DeliveryInfo, ConsumableEvent, Endpoint, Topology, EventHandler, RequestResponseEventHandler, NotificationSource, Notification, ErrorNotification, NotificationHandler, ErrorNotificationHandler, } from "./types.js";
|
|
2
|
+
export { ErrParseJSON } from "./types.js";
|
|
3
|
+
export { DefaultEventExchangeName, KindTopic, KindDirect, KindHeaders, topicExchangeName, serviceEventQueueName, serviceRequestExchangeName, serviceResponseExchangeName, serviceRequestQueueName, serviceResponseQueueName, natsStreamName, natsSubject, translateWildcard, } from "./naming.js";
|
|
4
|
+
export { CESpecVersion, CEType, CESource, CEID, CETime, CESpecVersionValue, CEDataContentType, CESubject, CEDataSchema, CECorrelationID, CEAttrSpecVersion, CEAttrType, CEAttrSource, CEAttrID, CEAttrTime, CEAttrDataContentType, CEAttrSubject, CEAttrCorrelationID, CERequiredAttributes, AMQPCEHeaderKey, normalizeCEHeaders, hasCEHeaders, enrichLegacyMetadata, metadataFromHeaders, validateCEHeaders, } from "./cloudevents.js";
|
|
5
|
+
export { matchRoutingKey, routingKeyOverlaps } from "./routing.js";
|
|
6
|
+
export { validate, validateTopologies } from "./validate.js";
|
|
7
|
+
export { mermaid } from "./visualize.js";
|
|
8
|
+
export {} from "./topology.js";
|
|
9
|
+
export type { MetricsRecorder, RoutingKeyMapper, MetricsOptions } from "./metrics.js";
|
|
10
|
+
export { mapRoutingKey } from "./metrics.js";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,YAAY,EACV,SAAS,EACT,iBAAiB,EACjB,YAAY,EACZ,OAAO,EACP,OAAO,EACP,QAAQ,EACR,YAAY,EACZ,eAAe,EACf,QAAQ,EACR,QAAQ,EACR,YAAY,EACZ,2BAA2B,EAC3B,kBAAkB,EAClB,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,wBAAwB,GACzB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG1C,OAAO,EACL,wBAAwB,EACxB,SAAS,EACT,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,qBAAqB,EACrB,0BAA0B,EAC1B,2BAA2B,EAC3B,uBAAuB,EACvB,wBAAwB,EACxB,cAAc,EACd,WAAW,EACX,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,aAAa,EACb,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,kBAAkB,EAClB,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,qBAAqB,EACrB,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,YAAY,EACZ,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAGnE,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAG7D,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAGzC,OAAO,EAAE,MAAM,eAAe,CAAC;AAG/B,YAAY,EAAE,eAAe,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AACtF,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// MIT License
|
|
2
|
+
// Copyright (c) 2026 sparetimecoders
|
|
3
|
+
export { ErrParseJSON } from "./types.js";
|
|
4
|
+
// Naming
|
|
5
|
+
export { DefaultEventExchangeName, KindTopic, KindDirect, KindHeaders, topicExchangeName, serviceEventQueueName, serviceRequestExchangeName, serviceResponseExchangeName, serviceRequestQueueName, serviceResponseQueueName, natsStreamName, natsSubject, translateWildcard, } from "./naming.js";
|
|
6
|
+
// CloudEvents
|
|
7
|
+
export { CESpecVersion, CEType, CESource, CEID, CETime, CESpecVersionValue, CEDataContentType, CESubject, CEDataSchema, CECorrelationID, CEAttrSpecVersion, CEAttrType, CEAttrSource, CEAttrID, CEAttrTime, CEAttrDataContentType, CEAttrSubject, CEAttrCorrelationID, CERequiredAttributes, AMQPCEHeaderKey, normalizeCEHeaders, hasCEHeaders, enrichLegacyMetadata, metadataFromHeaders, validateCEHeaders, } from "./cloudevents.js";
|
|
8
|
+
// Routing
|
|
9
|
+
export { matchRoutingKey, routingKeyOverlaps } from "./routing.js";
|
|
10
|
+
// Validation
|
|
11
|
+
export { validate, validateTopologies } from "./validate.js";
|
|
12
|
+
// Visualization
|
|
13
|
+
export { mermaid } from "./visualize.js";
|
|
14
|
+
export { mapRoutingKey } from "./metrics.js";
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc;AACd,qCAAqC;AAsBrC,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,SAAS;AACT,OAAO,EACL,wBAAwB,EACxB,SAAS,EACT,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,qBAAqB,EACrB,0BAA0B,EAC1B,2BAA2B,EAC3B,uBAAuB,EACvB,wBAAwB,EACxB,cAAc,EACd,WAAW,EACX,iBAAiB,GAClB,MAAM,aAAa,CAAC;AAErB,cAAc;AACd,OAAO,EACL,aAAa,EACb,MAAM,EACN,QAAQ,EACR,IAAI,EACJ,MAAM,EACN,kBAAkB,EAClB,iBAAiB,EACjB,SAAS,EACT,YAAY,EACZ,eAAe,EACf,iBAAiB,EACjB,UAAU,EACV,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,qBAAqB,EACrB,aAAa,EACb,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,kBAAkB,EAClB,YAAY,EACZ,oBAAoB,EACpB,mBAAmB,EACnB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAE1B,UAAU;AACV,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEnE,aAAa;AACb,OAAO,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAE7D,gBAAgB;AAChB,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAOzC,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pluggable metrics interface for messaging adapters.
|
|
3
|
+
*
|
|
4
|
+
* Users wire this to any metrics backend (prom-client, OpenTelemetry,
|
|
5
|
+
* StatsD, etc.) by implementing MetricsRecorder and passing it to
|
|
6
|
+
* ConnectionOptions.
|
|
7
|
+
*/
|
|
8
|
+
/** Records messaging metrics. Implement this interface to wire any metrics backend. */
|
|
9
|
+
export interface MetricsRecorder {
|
|
10
|
+
/** An event was received from the broker. */
|
|
11
|
+
eventReceived(queue: string, routingKey: string): void;
|
|
12
|
+
/** An event was received but no handler matched its routing key. */
|
|
13
|
+
eventWithoutHandler(queue: string, routingKey: string): void;
|
|
14
|
+
/** An event could not be parsed (invalid JSON). */
|
|
15
|
+
eventNotParsable(queue: string, routingKey: string): void;
|
|
16
|
+
/** An event was acknowledged (successfully processed). */
|
|
17
|
+
eventAck(queue: string, routingKey: string, durationMs: number): void;
|
|
18
|
+
/** An event was negatively acknowledged (handler failed). */
|
|
19
|
+
eventNack(queue: string, routingKey: string, durationMs: number): void;
|
|
20
|
+
/** A message was published successfully. */
|
|
21
|
+
publishSucceed(exchange: string, routingKey: string, durationMs: number): void;
|
|
22
|
+
/** A message failed to publish. */
|
|
23
|
+
publishFailed(exchange: string, routingKey: string, durationMs: number): void;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Maps a routing key before it is passed to metrics.
|
|
27
|
+
* Use this to normalize or redact dynamic segments (e.g. UUIDs)
|
|
28
|
+
* to prevent unbounded label cardinality.
|
|
29
|
+
*/
|
|
30
|
+
export type RoutingKeyMapper = (key: string) => string;
|
|
31
|
+
/** Options for configuring metrics behavior. */
|
|
32
|
+
export interface MetricsOptions {
|
|
33
|
+
routingKeyMapper?: RoutingKeyMapper;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Apply a routing key mapper, defaulting to identity.
|
|
37
|
+
* Empty mapped values are replaced with "unknown".
|
|
38
|
+
*/
|
|
39
|
+
export declare function mapRoutingKey(key: string, mapper?: RoutingKeyMapper): string;
|
|
40
|
+
//# sourceMappingURL=metrics.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AAEH,uFAAuF;AACvF,MAAM,WAAW,eAAe;IAC9B,6CAA6C;IAC7C,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAEvD,oEAAoE;IACpE,mBAAmB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAE7D,mDAAmD;IACnD,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAE1D,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAEtE,6DAA6D;IAC7D,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAEvE,4CAA4C;IAC5C,cAAc,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAE/E,mCAAmC;IACnC,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;CAC/E;AAED;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,CAAC;AAEvD,gDAAgD;AAChD,MAAM,WAAW,cAAc;IAC7B,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAC3B,GAAG,EAAE,MAAM,EACX,MAAM,CAAC,EAAE,gBAAgB,GACxB,MAAM,CAGR"}
|
package/dist/metrics.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// MIT License
|
|
2
|
+
// Copyright (c) 2026 sparetimecoders
|
|
3
|
+
/**
|
|
4
|
+
* Apply a routing key mapper, defaulting to identity.
|
|
5
|
+
* Empty mapped values are replaced with "unknown".
|
|
6
|
+
*/
|
|
7
|
+
export function mapRoutingKey(key, mapper) {
|
|
8
|
+
const mapped = mapper ? mapper(key) : key;
|
|
9
|
+
return mapped === "" ? "unknown" : mapped;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=metrics.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../src/metrics.ts"],"names":[],"mappings":"AAAA,cAAc;AACd,qCAAqC;AA8CrC;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,GAAW,EACX,MAAyB;IAEzB,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;IAC1C,OAAO,MAAM,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;AAC5C,CAAC"}
|
package/dist/naming.d.ts
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/** DefaultEventExchangeName is the default exchange name used for event streaming. */
|
|
2
|
+
export declare const DefaultEventExchangeName = "events";
|
|
3
|
+
/** Exchange kind constants matching AMQP exchange types. */
|
|
4
|
+
export declare const KindTopic = "topic";
|
|
5
|
+
export declare const KindDirect = "direct";
|
|
6
|
+
export declare const KindHeaders = "headers";
|
|
7
|
+
/**
|
|
8
|
+
* TopicExchangeName returns the topic exchange name for the given name.
|
|
9
|
+
* Format: `<name>.topic.exchange`
|
|
10
|
+
*/
|
|
11
|
+
export declare function topicExchangeName(name: string): string;
|
|
12
|
+
/**
|
|
13
|
+
* ServiceEventQueueName returns the durable event queue name for a service.
|
|
14
|
+
* Format: `<exchangeName>.queue.<service>`
|
|
15
|
+
*/
|
|
16
|
+
export declare function serviceEventQueueName(exchangeName: string, service: string): string;
|
|
17
|
+
/**
|
|
18
|
+
* ServiceRequestExchangeName returns the direct exchange name for requests to a service.
|
|
19
|
+
* Format: `<service>.direct.exchange.request`
|
|
20
|
+
*/
|
|
21
|
+
export declare function serviceRequestExchangeName(service: string): string;
|
|
22
|
+
/**
|
|
23
|
+
* ServiceResponseExchangeName returns the headers exchange name for responses from a service.
|
|
24
|
+
* Format: `<service>.headers.exchange.response`
|
|
25
|
+
*/
|
|
26
|
+
export declare function serviceResponseExchangeName(service: string): string;
|
|
27
|
+
/**
|
|
28
|
+
* ServiceRequestQueueName returns the queue name for requests to a service.
|
|
29
|
+
* Format: `<service>.direct.exchange.request.queue`
|
|
30
|
+
*/
|
|
31
|
+
export declare function serviceRequestQueueName(service: string): string;
|
|
32
|
+
/**
|
|
33
|
+
* ServiceResponseQueueName returns the queue name for responses from targetService to serviceName.
|
|
34
|
+
* Format: `<targetService>.headers.exchange.response.queue.<serviceName>`
|
|
35
|
+
*/
|
|
36
|
+
export declare function serviceResponseQueueName(targetService: string, serviceName: string): string;
|
|
37
|
+
/**
|
|
38
|
+
* NATSStreamName extracts the base stream name from a logical name.
|
|
39
|
+
* If the name follows the AMQP convention `<name>.topic.exchange`, the prefix is extracted.
|
|
40
|
+
* Otherwise the name is returned as-is.
|
|
41
|
+
*/
|
|
42
|
+
export declare function natsStreamName(name: string): string;
|
|
43
|
+
/**
|
|
44
|
+
* NATSSubject builds a NATS subject from a stream name and routing key.
|
|
45
|
+
* Format: `<stream>.<routingKey>`
|
|
46
|
+
*/
|
|
47
|
+
export declare function natsSubject(stream: string, routingKey: string): string;
|
|
48
|
+
/**
|
|
49
|
+
* TranslateWildcard converts AMQP-style wildcards to NATS-style wildcards.
|
|
50
|
+
* AMQP "#" (multi-level) -> NATS ">" (multi-level)
|
|
51
|
+
* AMQP "*" (single-level) stays "*" in NATS.
|
|
52
|
+
*/
|
|
53
|
+
export declare function translateWildcard(routingKey: string): string;
|
|
54
|
+
//# sourceMappingURL=naming.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming.d.ts","sourceRoot":"","sources":["../src/naming.ts"],"names":[],"mappings":"AAGA,sFAAsF;AACtF,eAAO,MAAM,wBAAwB,WAAW,CAAC;AAEjD,4DAA4D;AAC5D,eAAO,MAAM,SAAS,UAAU,CAAC;AACjC,eAAO,MAAM,UAAU,WAAW,CAAC;AACnC,eAAO,MAAM,WAAW,YAAY,CAAC;AAErC;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEtD;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,GACd,MAAM,CAER;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAElE;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE/D;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,aAAa,EAAE,MAAM,EACrB,WAAW,EAAE,MAAM,GAClB,MAAM,CAER;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAMnD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAE5D"}
|
package/dist/naming.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// MIT License
|
|
2
|
+
// Copyright (c) 2026 sparetimecoders
|
|
3
|
+
/** DefaultEventExchangeName is the default exchange name used for event streaming. */
|
|
4
|
+
export const DefaultEventExchangeName = "events";
|
|
5
|
+
/** Exchange kind constants matching AMQP exchange types. */
|
|
6
|
+
export const KindTopic = "topic";
|
|
7
|
+
export const KindDirect = "direct";
|
|
8
|
+
export const KindHeaders = "headers";
|
|
9
|
+
/**
|
|
10
|
+
* TopicExchangeName returns the topic exchange name for the given name.
|
|
11
|
+
* Format: `<name>.topic.exchange`
|
|
12
|
+
*/
|
|
13
|
+
export function topicExchangeName(name) {
|
|
14
|
+
return `${name}.${KindTopic}.exchange`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* ServiceEventQueueName returns the durable event queue name for a service.
|
|
18
|
+
* Format: `<exchangeName>.queue.<service>`
|
|
19
|
+
*/
|
|
20
|
+
export function serviceEventQueueName(exchangeName, service) {
|
|
21
|
+
return `${exchangeName}.queue.${service}`;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* ServiceRequestExchangeName returns the direct exchange name for requests to a service.
|
|
25
|
+
* Format: `<service>.direct.exchange.request`
|
|
26
|
+
*/
|
|
27
|
+
export function serviceRequestExchangeName(service) {
|
|
28
|
+
return `${service}.${KindDirect}.exchange.request`;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* ServiceResponseExchangeName returns the headers exchange name for responses from a service.
|
|
32
|
+
* Format: `<service>.headers.exchange.response`
|
|
33
|
+
*/
|
|
34
|
+
export function serviceResponseExchangeName(service) {
|
|
35
|
+
return `${service}.${KindHeaders}.exchange.response`;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* ServiceRequestQueueName returns the queue name for requests to a service.
|
|
39
|
+
* Format: `<service>.direct.exchange.request.queue`
|
|
40
|
+
*/
|
|
41
|
+
export function serviceRequestQueueName(service) {
|
|
42
|
+
return `${serviceRequestExchangeName(service)}.queue`;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* ServiceResponseQueueName returns the queue name for responses from targetService to serviceName.
|
|
46
|
+
* Format: `<targetService>.headers.exchange.response.queue.<serviceName>`
|
|
47
|
+
*/
|
|
48
|
+
export function serviceResponseQueueName(targetService, serviceName) {
|
|
49
|
+
return `${serviceResponseExchangeName(targetService)}.queue.${serviceName}`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* NATSStreamName extracts the base stream name from a logical name.
|
|
53
|
+
* If the name follows the AMQP convention `<name>.topic.exchange`, the prefix is extracted.
|
|
54
|
+
* Otherwise the name is returned as-is.
|
|
55
|
+
*/
|
|
56
|
+
export function natsStreamName(name) {
|
|
57
|
+
const suffix = ".topic.exchange";
|
|
58
|
+
if (name.endsWith(suffix)) {
|
|
59
|
+
return name.slice(0, -suffix.length);
|
|
60
|
+
}
|
|
61
|
+
return name;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* NATSSubject builds a NATS subject from a stream name and routing key.
|
|
65
|
+
* Format: `<stream>.<routingKey>`
|
|
66
|
+
*/
|
|
67
|
+
export function natsSubject(stream, routingKey) {
|
|
68
|
+
return `${stream}.${routingKey}`;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* TranslateWildcard converts AMQP-style wildcards to NATS-style wildcards.
|
|
72
|
+
* AMQP "#" (multi-level) -> NATS ">" (multi-level)
|
|
73
|
+
* AMQP "*" (single-level) stays "*" in NATS.
|
|
74
|
+
*/
|
|
75
|
+
export function translateWildcard(routingKey) {
|
|
76
|
+
return routingKey.replaceAll("#", ">");
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=naming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming.js","sourceRoot":"","sources":["../src/naming.ts"],"names":[],"mappings":"AAAA,cAAc;AACd,qCAAqC;AAErC,sFAAsF;AACtF,MAAM,CAAC,MAAM,wBAAwB,GAAG,QAAQ,CAAC;AAEjD,4DAA4D;AAC5D,MAAM,CAAC,MAAM,SAAS,GAAG,OAAO,CAAC;AACjC,MAAM,CAAC,MAAM,UAAU,GAAG,QAAQ,CAAC;AACnC,MAAM,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC;AAErC;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,OAAO,GAAG,IAAI,IAAI,SAAS,WAAW,CAAC;AACzC,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CACnC,YAAoB,EACpB,OAAe;IAEf,OAAO,GAAG,YAAY,UAAU,OAAO,EAAE,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,0BAA0B,CAAC,OAAe;IACxD,OAAO,GAAG,OAAO,IAAI,UAAU,mBAAmB,CAAC;AACrD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,2BAA2B,CAAC,OAAe;IACzD,OAAO,GAAG,OAAO,IAAI,WAAW,oBAAoB,CAAC;AACvD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,OAAe;IACrD,OAAO,GAAG,0BAA0B,CAAC,OAAO,CAAC,QAAQ,CAAC;AACxD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,wBAAwB,CACtC,aAAqB,EACrB,WAAmB;IAEnB,OAAO,GAAG,2BAA2B,CAAC,aAAa,CAAC,UAAU,WAAW,EAAE,CAAC;AAC9E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,IAAY;IACzC,MAAM,MAAM,GAAG,iBAAiB,CAAC;IACjC,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACvC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,UAAkB;IAC5D,OAAO,GAAG,MAAM,IAAI,UAAU,EAAE,CAAC;AACnC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,UAAkB;IAClD,OAAO,UAAU,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;AACzC,CAAC"}
|