@amqp-contract/client 0.10.0 → 0.12.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.
package/dist/index.cjs CHANGED
@@ -6,36 +6,16 @@ let node_util = require("node:util");
6
6
 
7
7
  //#region src/errors.ts
8
8
  /**
9
- * Base error class for client errors
10
- */
11
- var ClientError = class extends Error {
12
- constructor(message) {
13
- super(message);
14
- this.name = "ClientError";
15
- const ErrorConstructor = Error;
16
- if (typeof ErrorConstructor.captureStackTrace === "function") ErrorConstructor.captureStackTrace(this, this.constructor);
17
- }
18
- };
19
- /**
20
- * Error for technical/runtime failures that cannot be prevented by TypeScript
21
- * This includes validation failures and AMQP channel issues
22
- */
23
- var TechnicalError = class extends ClientError {
24
- constructor(message, cause) {
25
- super(message);
26
- this.cause = cause;
27
- this.name = "TechnicalError";
28
- }
29
- };
30
- /**
31
9
  * Error thrown when message validation fails
32
10
  */
33
- var MessageValidationError = class extends ClientError {
11
+ var MessageValidationError = class extends Error {
34
12
  constructor(publisherName, issues) {
35
13
  super(`Message validation failed for publisher "${publisherName}"`);
36
14
  this.publisherName = publisherName;
37
15
  this.issues = issues;
38
16
  this.name = "MessageValidationError";
17
+ const ErrorConstructor = Error;
18
+ if (typeof ErrorConstructor.captureStackTrace === "function") ErrorConstructor.captureStackTrace(this, this.constructor);
39
19
  }
40
20
  };
41
21
 
@@ -48,13 +28,12 @@ const deflateAsync = (0, node_util.promisify)(node_zlib.deflate);
48
28
  *
49
29
  * @param buffer - The buffer to compress
50
30
  * @param algorithm - The compression algorithm to use
51
- * @returns A promise that resolves to the compressed buffer
52
- * @throws Error if compression fails
31
+ * @returns A Future with the compressed buffer or a TechnicalError
53
32
  *
54
33
  * @internal
55
34
  */
56
- async function compressBuffer(buffer, algorithm) {
57
- return (0, ts_pattern.match)(algorithm).with("gzip", () => gzipAsync(buffer)).with("deflate", () => deflateAsync(buffer)).exhaustive();
35
+ function compressBuffer(buffer, algorithm) {
36
+ return (0, ts_pattern.match)(algorithm).with("gzip", () => _swan_io_boxed.Future.fromPromise(gzipAsync(buffer)).mapError((error) => new _amqp_contract_core.TechnicalError("Failed to compress with gzip", error))).with("deflate", () => _swan_io_boxed.Future.fromPromise(deflateAsync(buffer)).mapError((error) => new _amqp_contract_core.TechnicalError("Failed to compress with deflate", error))).exhaustive();
58
37
  }
59
38
 
60
39
  //#endregion
@@ -100,18 +79,18 @@ var TypedAmqpClient = class TypedAmqpClient {
100
79
  *
101
80
  * @returns Result.Ok(void) on success, or Result.Error with specific error on failure
102
81
  */
82
+ /**
83
+ * Publish a message using a defined publisher.
84
+ * TypeScript guarantees publisher exists for valid publisher names.
85
+ */
103
86
  publish(publisherName, message, options) {
104
87
  const startTime = Date.now();
105
- const publishers = this.contract.publishers;
106
- if (!publishers) return _swan_io_boxed.Future.value(_swan_io_boxed.Result.Error(new TechnicalError("No publishers defined in contract")));
107
- const publisher = publishers[publisherName];
108
- if (!publisher) return _swan_io_boxed.Future.value(_swan_io_boxed.Result.Error(new TechnicalError(`Publisher "${String(publisherName)}" not found in contract`)));
109
- const exchangeName = publisher.exchange.name;
110
- const routingKey = publisher.routingKey;
111
- const span = (0, _amqp_contract_core.startPublishSpan)(this.telemetry, exchangeName, routingKey, { "amqp.publisher.name": String(publisherName) });
88
+ const publisher = this.contract.publishers[publisherName];
89
+ const { exchange, routingKey } = publisher;
90
+ const span = (0, _amqp_contract_core.startPublishSpan)(this.telemetry, exchange.name, routingKey, { "amqp.publisher.name": String(publisherName) });
112
91
  const validateMessage = () => {
113
92
  const validationResult = publisher.message.payload["~standard"].validate(message);
114
- return _swan_io_boxed.Future.fromPromise(validationResult instanceof Promise ? validationResult : Promise.resolve(validationResult)).mapError((error) => new TechnicalError(`Validation failed`, error)).mapOkToResult((validation) => {
93
+ return _swan_io_boxed.Future.fromPromise(validationResult instanceof Promise ? validationResult : Promise.resolve(validationResult)).mapError((error) => new _amqp_contract_core.TechnicalError(`Validation failed`, error)).mapOkToResult((validation) => {
115
94
  if (validation.issues) return _swan_io_boxed.Result.Error(new MessageValidationError(String(publisherName), validation.issues));
116
95
  return _swan_io_boxed.Result.Ok(validation.value);
117
96
  });
@@ -123,12 +102,12 @@ var TypedAmqpClient = class TypedAmqpClient {
123
102
  if (compression) {
124
103
  const messageBuffer = Buffer.from(JSON.stringify(validatedMessage));
125
104
  publishOptions.contentEncoding = compression;
126
- return _swan_io_boxed.Future.fromPromise(compressBuffer(messageBuffer, compression)).mapError((error) => new TechnicalError(`Failed to compress message`, error)).map((compressedBuffer) => _swan_io_boxed.Result.Ok(compressedBuffer));
105
+ return compressBuffer(messageBuffer, compression);
127
106
  }
128
107
  return _swan_io_boxed.Future.value(_swan_io_boxed.Result.Ok(validatedMessage));
129
108
  };
130
- return preparePayload().flatMapOk((payload) => _swan_io_boxed.Future.fromPromise(this.amqpClient.channel.publish(publisher.exchange.name, publisher.routingKey ?? "", payload, publishOptions)).mapError((error) => new TechnicalError(`Failed to publish message`, error)).mapOkToResult((published) => {
131
- if (!published) return _swan_io_boxed.Result.Error(new TechnicalError(`Failed to publish message for publisher "${String(publisherName)}": Channel rejected the message (buffer full or other channel issue)`));
109
+ return preparePayload().flatMapOk((payload) => this.amqpClient.publish(publisher.exchange.name, publisher.routingKey ?? "", payload, publishOptions).mapOkToResult((published) => {
110
+ if (!published) return _swan_io_boxed.Result.Error(new _amqp_contract_core.TechnicalError(`Failed to publish message for publisher "${String(publisherName)}": Channel rejected the message (buffer full or other channel issue)`));
132
111
  this.logger?.info("Message published successfully", {
133
112
  publisherName: String(publisherName),
134
113
  exchange: publisher.exchange.name,
@@ -141,25 +120,24 @@ var TypedAmqpClient = class TypedAmqpClient {
141
120
  return validateMessage().flatMapOk((validatedMessage) => publishMessage(validatedMessage)).tapOk(() => {
142
121
  const durationMs = Date.now() - startTime;
143
122
  (0, _amqp_contract_core.endSpanSuccess)(span);
144
- (0, _amqp_contract_core.recordPublishMetric)(this.telemetry, exchangeName, routingKey, true, durationMs);
123
+ (0, _amqp_contract_core.recordPublishMetric)(this.telemetry, exchange.name, routingKey, true, durationMs);
145
124
  }).tapError((error) => {
146
125
  const durationMs = Date.now() - startTime;
147
126
  (0, _amqp_contract_core.endSpanError)(span, error);
148
- (0, _amqp_contract_core.recordPublishMetric)(this.telemetry, exchangeName, routingKey, false, durationMs);
127
+ (0, _amqp_contract_core.recordPublishMetric)(this.telemetry, exchange.name, routingKey, false, durationMs);
149
128
  });
150
129
  }
151
130
  /**
152
131
  * Close the channel and connection
153
132
  */
154
133
  close() {
155
- return _swan_io_boxed.Future.fromPromise(this.amqpClient.close()).mapError((error) => new TechnicalError("Failed to close AMQP connection", error)).mapOk(() => void 0);
134
+ return this.amqpClient.close().mapOk(() => void 0);
156
135
  }
157
136
  waitForConnectionReady() {
158
- return _swan_io_boxed.Future.fromPromise(this.amqpClient.channel.waitForConnect()).mapError((error) => new TechnicalError("Failed to wait for connection ready", error));
137
+ return this.amqpClient.waitForConnect();
159
138
  }
160
139
  };
161
140
 
162
141
  //#endregion
163
142
  exports.MessageValidationError = MessageValidationError;
164
- exports.TechnicalError = TechnicalError;
165
143
  exports.TypedAmqpClient = TypedAmqpClient;
package/dist/index.d.cts CHANGED
@@ -1,34 +1,10 @@
1
- import { Logger, TelemetryProvider } from "@amqp-contract/core";
1
+ import { Logger, TechnicalError, TelemetryProvider } from "@amqp-contract/core";
2
2
  import { AmqpConnectionManagerOptions, ConnectionUrl } from "amqp-connection-manager";
3
3
  import { CompressionAlgorithm, ContractDefinition, InferPublisherNames, PublisherDefinition } from "@amqp-contract/contract";
4
4
  import { Future, Result } from "@swan-io/boxed";
5
5
  import { StandardSchemaV1 } from "@standard-schema/spec";
6
6
  import { Options } from "amqplib";
7
7
 
8
- //#region src/errors.d.ts
9
- /**
10
- * Base error class for client errors
11
- */
12
- declare abstract class ClientError extends Error {
13
- protected constructor(message: string);
14
- }
15
- /**
16
- * Error for technical/runtime failures that cannot be prevented by TypeScript
17
- * This includes validation failures and AMQP channel issues
18
- */
19
- declare class TechnicalError extends ClientError {
20
- readonly cause?: unknown | undefined;
21
- constructor(message: string, cause?: unknown | undefined);
22
- }
23
- /**
24
- * Error thrown when message validation fails
25
- */
26
- declare class MessageValidationError extends ClientError {
27
- readonly publisherName: string;
28
- readonly issues: unknown;
29
- constructor(publisherName: string, issues: unknown);
30
- }
31
- //#endregion
32
8
  //#region src/types.d.ts
33
9
  /**
34
10
  * Infer the TypeScript type from a schema
@@ -51,6 +27,16 @@ type InferPublisher<TContract extends ContractDefinition, TName extends InferPub
51
27
  */
52
28
  type ClientInferPublisherInput<TContract extends ContractDefinition, TName extends InferPublisherNames<TContract>> = PublisherInferInput<InferPublisher<TContract, TName>>;
53
29
  //#endregion
30
+ //#region src/errors.d.ts
31
+ /**
32
+ * Error thrown when message validation fails
33
+ */
34
+ declare class MessageValidationError extends Error {
35
+ readonly publisherName: string;
36
+ readonly issues: unknown;
37
+ constructor(publisherName: string, issues: unknown);
38
+ }
39
+ //#endregion
54
40
  //#region src/client.d.ts
55
41
  /**
56
42
  * Publish options that extend amqplib's Options.Publish with optional compression support.
@@ -118,6 +104,10 @@ declare class TypedAmqpClient<TContract extends ContractDefinition> {
118
104
  *
119
105
  * @returns Result.Ok(void) on success, or Result.Error with specific error on failure
120
106
  */
107
+ /**
108
+ * Publish a message using a defined publisher.
109
+ * TypeScript guarantees publisher exists for valid publisher names.
110
+ */
121
111
  publish<TName extends InferPublisherNames<TContract>>(publisherName: TName, message: ClientInferPublisherInput<TContract, TName>, options?: PublishOptions): Future<Result<void, TechnicalError | MessageValidationError>>;
122
112
  /**
123
113
  * Close the channel and connection
@@ -126,5 +116,5 @@ declare class TypedAmqpClient<TContract extends ContractDefinition> {
126
116
  private waitForConnectionReady;
127
117
  }
128
118
  //#endregion
129
- export { type ClientInferPublisherInput, type CreateClientOptions, MessageValidationError, type PublishOptions, TechnicalError, TypedAmqpClient };
119
+ export { type ClientInferPublisherInput, type CreateClientOptions, MessageValidationError, type PublishOptions, TypedAmqpClient };
130
120
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/client.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;uBAGe,WAAA,SAAoB,KAAA;;;;;;AAkBnC;AAaa,cAbA,cAAA,SAAuB,WAAA,CAamB;;;;AC7BO;;;AAM5C,cDuBL,sBAAA,SAA+B,WAAA,CCvB1B;EAAgB,SAAA,aAAA,EAAA,MAAA;EAK7B,SAAA,MAAA,EAAA,OAAmB;EAAoB,WAAA,CAAA,aAAA,EAAA,MAAA,EAAA,MAAA,EAAA,OAAA;;;;;;;KANvC,iCAAiC,oBACpC,gBAAgB;;;;ADUlB,KCLK,mBDKuB,CAAA,mBCLgB,mBDKG,CAAA,GCLoB,gBDKpB,CCJ7C,UDI6C,CAAA,SAAA,CAAA,CAAA,SAAA,CAAA,CAAA;AAa/C;;;KCXK,kCAAkC,sBAAsB,YAAY;AAlBX;;;KAuBzD,cAjBa,CAAA,kBAkBE,kBAlBF,EAAA,cAmBF,mBAnBE,CAmBkB,SAnBlB,CAAA,CAAA,GAoBd,eApBc,CAoBE,SApBF,CAAA,CAoBa,KApBb,CAAA;;AAAgB;;AAMhC,KAmBU,yBAnBV,CAAA,kBAoBkB,kBApBlB,EAAA,cAqBc,mBArBd,CAqBkC,SArBlC,CAAA,CAAA,GAsBE,mBAtBF,CAsBsB,cAtBtB,CAsBqC,SAtBrC,EAsBgD,KAtBhD,CAAA,CAAA;;;;;ADIF;AAaa,KETD,cAAA,GAAiB,OAAA,CAAQ,OFSO,GAAA;;;;AC7BkB;;EAM5D,WAAA,CAAA,ECoBc,oBDpBd,GAAA,SAAA;CAAgB;;AAAgB;;AAMhC,KCoBU,mBDpBV,CAAA,kBCoBgD,kBDpBhD,CAAA,GAAA;EADiE,QAAA,ECsBvD,SDtBuD;EAAgB,IAAA,ECuB3E,aDvB2E,EAAA;EAO9E,iBAAA,CAAe,ECiBE,4BDjBF,GAAA,SAAA;EAAmB,MAAA,CAAA,ECkB5B,MDlB4B,GAAA,SAAA;EAAkC;;;AAAD;;EAOpC,SAAA,CAAA,ECiBtB,iBDjBsB,GAAA,SAAA;CAApB;;;;AACoB,cCsBvB,eDtBuB,CAAA,kBCsBW,kBDtBX,CAAA,CAAA;EAKxB,iBAAA,QAAA;EACQ,iBAAA,UAAA;EACgB,iBAAA,MAAA;EAApB,iBAAA,SAAA;EACuB,QAAA,WAAA,CAAA;EAAW;;;;;;;ACdlD;AAYA;;EACY,OAAA,MAAA,CAAA,kBAiCsB,kBAjCtB,CAAA,CAAA;IAAA,QAAA;IAAA,IAAA;IAAA,iBAAA;IAAA,MAAA;IAAA;EAAA,CAAA,EAuCP,mBAvCO,CAuCa,SAvCb,CAAA,CAAA,EAuC0B,MAvC1B,CAuCiC,MAvCjC,CAuCwC,eAvCxC,CAuCwD,SAvCxD,CAAA,EAuCoE,cAvCpE,CAAA,CAAA;EACJ;;;;;AAcR;;;;;;;;;EAwBK,OAAA,CAAA,cAyBmB,mBAzBnB,CAyBuC,SAzBvC,CAAA,CAAA,CAAA,aAAA,EA0Bc,KA1Bd,EAAA,OAAA,EA2BQ,yBA3BR,CA2BkC,SA3BlC,EA2B6C,KA3B7C,CAAA,EAAA,OAAA,CAAA,EA4BS,cA5BT,CAAA,EA6BA,MA7BA,CA6BO,MA7BP,CAAA,IAAA,EA6BoB,cA7BpB,GA6BqC,sBA7BrC,CAAA,CAAA;EAA+D;;;EAAvB,KAAA,CAAA,CAAA,EA6IlC,MA7IkC,CA6I3B,MA7I2B,CAAA,IAAA,EA6Id,cA7Ic,CAAA,CAAA;EAAP,QAAA,sBAAA"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;KAUK,iCAAiC,oBACpC,gBAAgB;;;AAN4C;KAWzD,mBANiC,CAAA,mBAMM,mBANN,CAAA,GAM6B,gBAN7B,CAOpC,UAPoC,CAAA,SAAA,CAAA,CAAA,SAAA,CAAA,CAAA;;;;AACJ,KAY7B,eAPA,CAAA,kBAOkC,kBAPf,CAAA,GAOqC,WAPrC,CAOiD,SAPjD,CAAA,YAAA,CAAA,CAAA;;;;KAYnB,cAZ8E,CAAA,kBAa/D,kBAb+D,EAAA,cAcnE,mBAdmE,CAc/C,SAd+C,CAAA,CAAA,GAe/E,eAf+E,CAe/D,SAf+D,CAAA,CAepD,KAfoD,CAAA;AAAA;;;AAOtB,KAajD,yBAbiD,CAAA,kBAczC,kBAdyC,EAAA,cAe7C,mBAf6C,CAezB,SAfyB,CAAA,CAAA,GAgBzD,mBAhByD,CAgBrC,cAhBqC,CAgBtB,SAhBsB,EAgBX,KAhBW,CAAA,CAAA;;;;;;cCpBhD,sBAAA,SAA+B,KAAA;;;;;;;;ADEkB;;AAM5D,KEeU,cAAA,GAAiB,OAAA,CAAQ,OFfnC,GAAA;EAAgB;;AAAgB;;;EAKiC,WAAA,CAAA,EEgBnD,oBFhBmD,GAAA,SAAA;CAAgB;AAAA;;;AAOtB,KEejD,mBFfiD,CAAA,kBEeX,kBFfW,CAAA,GAAA;EAAW,QAAA,EEgB5D,SFhB4D;EAKnE,IAAA,EEYG,aFZW,EAAA;EACC,iBAAA,CAAA,EEYE,4BFZF,GAAA,SAAA;EACgB,MAAA,CAAA,EEYzB,MFZyB,GAAA,SAAA;EAApB;;;;;EAMJ,SAAA,CAAA,EEYE,iBFZuB,GAAA,SAAA;CACjB;;;;AAE8B,cEerC,eFfqC,CAAA,kBEeH,kBFfG,CAAA,CAAA;EAA1B,iBAAA,QAAA;EAApB,iBAAA,UAAA;EAAmB,iBAAA,MAAA;;;;ACpCvB;;;;ACuBA;AAYA;;;;EAGsB,OAAA,MAAA,CAAA,kBA+BY,kBA/BZ,CAAA,CAAA;IAAA,QAAA;IAAA,IAAA;IAAA,iBAAA;IAAA,MAAA;IAAA;EAAA,CAAA,EAqCjB,mBArCiB,CAqCG,SArCH,CAAA,CAAA,EAqCgB,MArChB,CAqCuB,MArCvB,CAqC8B,eArC9B,CAqC8C,SArC9C,CAAA,EAqC0D,cArC1D,CAAA,CAAA;EACX;;;AAYX;;;;;;;;;;;EAwBoD;;;;EA6BR,OAAA,CAAA,cAApB,mBAAoB,CAAA,SAAA,CAAA,CAAA,CAAA,aAAA,EACzB,KADyB,EAAA,OAAA,EAE/B,yBAF+B,CAEL,SAFK,EAEM,KAFN,CAAA,EAAA,OAAA,CAAA,EAG9B,cAH8B,CAAA,EAIvC,MAJuC,CAIhC,MAJgC,CAAA,IAAA,EAInB,cAJmB,GAIF,sBAJE,CAAA,CAAA;EAApB;;;EAE0B,KAAA,CAAA,CAAA,EA4FvC,MA5FuC,CA4FhC,MA5FgC,CAAA,IAAA,EA4FnB,cA5FmB,CAAA,CAAA;EAArC,QAAA,sBAAA"}
package/dist/index.d.mts CHANGED
@@ -1,34 +1,10 @@
1
- import { Logger, TelemetryProvider } from "@amqp-contract/core";
1
+ import { Logger, TechnicalError, TelemetryProvider } from "@amqp-contract/core";
2
2
  import { Future, Result } from "@swan-io/boxed";
3
3
  import { AmqpConnectionManagerOptions, ConnectionUrl } from "amqp-connection-manager";
4
4
  import { CompressionAlgorithm, ContractDefinition, InferPublisherNames, PublisherDefinition } from "@amqp-contract/contract";
5
5
  import { StandardSchemaV1 } from "@standard-schema/spec";
6
6
  import { Options } from "amqplib";
7
7
 
8
- //#region src/errors.d.ts
9
- /**
10
- * Base error class for client errors
11
- */
12
- declare abstract class ClientError extends Error {
13
- protected constructor(message: string);
14
- }
15
- /**
16
- * Error for technical/runtime failures that cannot be prevented by TypeScript
17
- * This includes validation failures and AMQP channel issues
18
- */
19
- declare class TechnicalError extends ClientError {
20
- readonly cause?: unknown | undefined;
21
- constructor(message: string, cause?: unknown | undefined);
22
- }
23
- /**
24
- * Error thrown when message validation fails
25
- */
26
- declare class MessageValidationError extends ClientError {
27
- readonly publisherName: string;
28
- readonly issues: unknown;
29
- constructor(publisherName: string, issues: unknown);
30
- }
31
- //#endregion
32
8
  //#region src/types.d.ts
33
9
  /**
34
10
  * Infer the TypeScript type from a schema
@@ -51,6 +27,16 @@ type InferPublisher<TContract extends ContractDefinition, TName extends InferPub
51
27
  */
52
28
  type ClientInferPublisherInput<TContract extends ContractDefinition, TName extends InferPublisherNames<TContract>> = PublisherInferInput<InferPublisher<TContract, TName>>;
53
29
  //#endregion
30
+ //#region src/errors.d.ts
31
+ /**
32
+ * Error thrown when message validation fails
33
+ */
34
+ declare class MessageValidationError extends Error {
35
+ readonly publisherName: string;
36
+ readonly issues: unknown;
37
+ constructor(publisherName: string, issues: unknown);
38
+ }
39
+ //#endregion
54
40
  //#region src/client.d.ts
55
41
  /**
56
42
  * Publish options that extend amqplib's Options.Publish with optional compression support.
@@ -118,6 +104,10 @@ declare class TypedAmqpClient<TContract extends ContractDefinition> {
118
104
  *
119
105
  * @returns Result.Ok(void) on success, or Result.Error with specific error on failure
120
106
  */
107
+ /**
108
+ * Publish a message using a defined publisher.
109
+ * TypeScript guarantees publisher exists for valid publisher names.
110
+ */
121
111
  publish<TName extends InferPublisherNames<TContract>>(publisherName: TName, message: ClientInferPublisherInput<TContract, TName>, options?: PublishOptions): Future<Result<void, TechnicalError | MessageValidationError>>;
122
112
  /**
123
113
  * Close the channel and connection
@@ -126,5 +116,5 @@ declare class TypedAmqpClient<TContract extends ContractDefinition> {
126
116
  private waitForConnectionReady;
127
117
  }
128
118
  //#endregion
129
- export { type ClientInferPublisherInput, type CreateClientOptions, MessageValidationError, type PublishOptions, TechnicalError, TypedAmqpClient };
119
+ export { type ClientInferPublisherInput, type CreateClientOptions, MessageValidationError, type PublishOptions, TypedAmqpClient };
130
120
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/errors.ts","../src/types.ts","../src/client.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;uBAGe,WAAA,SAAoB,KAAA;;;;;;AAkBnC;AAaa,cAbA,cAAA,SAAuB,WAAA,CAamB;;;;AC7BO;;;AAM5C,cDuBL,sBAAA,SAA+B,WAAA,CCvB1B;EAAgB,SAAA,aAAA,EAAA,MAAA;EAK7B,SAAA,MAAA,EAAA,OAAmB;EAAoB,WAAA,CAAA,aAAA,EAAA,MAAA,EAAA,MAAA,EAAA,OAAA;;;;;;;KANvC,iCAAiC,oBACpC,gBAAgB;;;;ADUlB,KCLK,mBDKuB,CAAA,mBCLgB,mBDKG,CAAA,GCLoB,gBDKpB,CCJ7C,UDI6C,CAAA,SAAA,CAAA,CAAA,SAAA,CAAA,CAAA;AAa/C;;;KCXK,kCAAkC,sBAAsB,YAAY;AAlBX;;;KAuBzD,cAjBa,CAAA,kBAkBE,kBAlBF,EAAA,cAmBF,mBAnBE,CAmBkB,SAnBlB,CAAA,CAAA,GAoBd,eApBc,CAoBE,SApBF,CAAA,CAoBa,KApBb,CAAA;;AAAgB;;AAMhC,KAmBU,yBAnBV,CAAA,kBAoBkB,kBApBlB,EAAA,cAqBc,mBArBd,CAqBkC,SArBlC,CAAA,CAAA,GAsBE,mBAtBF,CAsBsB,cAtBtB,CAsBqC,SAtBrC,EAsBgD,KAtBhD,CAAA,CAAA;;;;;ADIF;AAaa,KETD,cAAA,GAAiB,OAAA,CAAQ,OFSO,GAAA;;;;AC7BkB;;EAM5D,WAAA,CAAA,ECoBc,oBDpBd,GAAA,SAAA;CAAgB;;AAAgB;;AAMhC,KCoBU,mBDpBV,CAAA,kBCoBgD,kBDpBhD,CAAA,GAAA;EADiE,QAAA,ECsBvD,SDtBuD;EAAgB,IAAA,ECuB3E,aDvB2E,EAAA;EAO9E,iBAAA,CAAe,ECiBE,4BDjBF,GAAA,SAAA;EAAmB,MAAA,CAAA,ECkB5B,MDlB4B,GAAA,SAAA;EAAkC;;;AAAD;;EAOpC,SAAA,CAAA,ECiBtB,iBDjBsB,GAAA,SAAA;CAApB;;;;AACoB,cCsBvB,eDtBuB,CAAA,kBCsBW,kBDtBX,CAAA,CAAA;EAKxB,iBAAA,QAAA;EACQ,iBAAA,UAAA;EACgB,iBAAA,MAAA;EAApB,iBAAA,SAAA;EACuB,QAAA,WAAA,CAAA;EAAW;;;;;;;ACdlD;AAYA;;EACY,OAAA,MAAA,CAAA,kBAiCsB,kBAjCtB,CAAA,CAAA;IAAA,QAAA;IAAA,IAAA;IAAA,iBAAA;IAAA,MAAA;IAAA;EAAA,CAAA,EAuCP,mBAvCO,CAuCa,SAvCb,CAAA,CAAA,EAuC0B,MAvC1B,CAuCiC,MAvCjC,CAuCwC,eAvCxC,CAuCwD,SAvCxD,CAAA,EAuCoE,cAvCpE,CAAA,CAAA;EACJ;;;;;AAcR;;;;;;;;;EAwBK,OAAA,CAAA,cAyBmB,mBAzBnB,CAyBuC,SAzBvC,CAAA,CAAA,CAAA,aAAA,EA0Bc,KA1Bd,EAAA,OAAA,EA2BQ,yBA3BR,CA2BkC,SA3BlC,EA2B6C,KA3B7C,CAAA,EAAA,OAAA,CAAA,EA4BS,cA5BT,CAAA,EA6BA,MA7BA,CA6BO,MA7BP,CAAA,IAAA,EA6BoB,cA7BpB,GA6BqC,sBA7BrC,CAAA,CAAA;EAA+D;;;EAAvB,KAAA,CAAA,CAAA,EA6IlC,MA7IkC,CA6I3B,MA7I2B,CAAA,IAAA,EA6Id,cA7Ic,CAAA,CAAA;EAAP,QAAA,sBAAA"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/errors.ts","../src/client.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;KAUK,iCAAiC,oBACpC,gBAAgB;;;AAN4C;KAWzD,mBANiC,CAAA,mBAMM,mBANN,CAAA,GAM6B,gBAN7B,CAOpC,UAPoC,CAAA,SAAA,CAAA,CAAA,SAAA,CAAA,CAAA;;;;AACJ,KAY7B,eAPA,CAAA,kBAOkC,kBAPf,CAAA,GAOqC,WAPrC,CAOiD,SAPjD,CAAA,YAAA,CAAA,CAAA;;;;KAYnB,cAZ8E,CAAA,kBAa/D,kBAb+D,EAAA,cAcnE,mBAdmE,CAc/C,SAd+C,CAAA,CAAA,GAe/E,eAf+E,CAe/D,SAf+D,CAAA,CAepD,KAfoD,CAAA;AAAA;;;AAOtB,KAajD,yBAbiD,CAAA,kBAczC,kBAdyC,EAAA,cAe7C,mBAf6C,CAezB,SAfyB,CAAA,CAAA,GAgBzD,mBAhByD,CAgBrC,cAhBqC,CAgBtB,SAhBsB,EAgBX,KAhBW,CAAA,CAAA;;;;;;cCpBhD,sBAAA,SAA+B,KAAA;;;;;;;;ADEkB;;AAM5D,KEeU,cAAA,GAAiB,OAAA,CAAQ,OFfnC,GAAA;EAAgB;;AAAgB;;;EAKiC,WAAA,CAAA,EEgBnD,oBFhBmD,GAAA,SAAA;CAAgB;AAAA;;;AAOtB,KEejD,mBFfiD,CAAA,kBEeX,kBFfW,CAAA,GAAA;EAAW,QAAA,EEgB5D,SFhB4D;EAKnE,IAAA,EEYG,aFZW,EAAA;EACC,iBAAA,CAAA,EEYE,4BFZF,GAAA,SAAA;EACgB,MAAA,CAAA,EEYzB,MFZyB,GAAA,SAAA;EAApB;;;;;EAMJ,SAAA,CAAA,EEYE,iBFZuB,GAAA,SAAA;CACjB;;;;AAE8B,cEerC,eFfqC,CAAA,kBEeH,kBFfG,CAAA,CAAA;EAA1B,iBAAA,QAAA;EAApB,iBAAA,UAAA;EAAmB,iBAAA,MAAA;;;;ACpCvB;;;;ACuBA;AAYA;;;;EAGsB,OAAA,MAAA,CAAA,kBA+BY,kBA/BZ,CAAA,CAAA;IAAA,QAAA;IAAA,IAAA;IAAA,iBAAA;IAAA,MAAA;IAAA;EAAA,CAAA,EAqCjB,mBArCiB,CAqCG,SArCH,CAAA,CAAA,EAqCgB,MArChB,CAqCuB,MArCvB,CAqC8B,eArC9B,CAqC8C,SArC9C,CAAA,EAqC0D,cArC1D,CAAA,CAAA;EACX;;;AAYX;;;;;;;;;;;EAwBoD;;;;EA6BR,OAAA,CAAA,cAApB,mBAAoB,CAAA,SAAA,CAAA,CAAA,CAAA,aAAA,EACzB,KADyB,EAAA,OAAA,EAE/B,yBAF+B,CAEL,SAFK,EAEM,KAFN,CAAA,EAAA,OAAA,CAAA,EAG9B,cAH8B,CAAA,EAIvC,MAJuC,CAIhC,MAJgC,CAAA,IAAA,EAInB,cAJmB,GAIF,sBAJE,CAAA,CAAA;EAApB;;;EAE0B,KAAA,CAAA,CAAA,EA4FvC,MA5FuC,CA4FhC,MA5FgC,CAAA,IAAA,EA4FnB,cA5FmB,CAAA,CAAA;EAArC,QAAA,sBAAA"}
package/dist/index.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { AmqpClient, defaultTelemetryProvider, endSpanError, endSpanSuccess, recordPublishMetric, startPublishSpan } from "@amqp-contract/core";
1
+ import { AmqpClient, TechnicalError, defaultTelemetryProvider, endSpanError, endSpanSuccess, recordPublishMetric, startPublishSpan } from "@amqp-contract/core";
2
2
  import { Future, Result } from "@swan-io/boxed";
3
3
  import { deflate, gzip } from "node:zlib";
4
4
  import { match } from "ts-pattern";
@@ -6,36 +6,16 @@ import { promisify } from "node:util";
6
6
 
7
7
  //#region src/errors.ts
8
8
  /**
9
- * Base error class for client errors
10
- */
11
- var ClientError = class extends Error {
12
- constructor(message) {
13
- super(message);
14
- this.name = "ClientError";
15
- const ErrorConstructor = Error;
16
- if (typeof ErrorConstructor.captureStackTrace === "function") ErrorConstructor.captureStackTrace(this, this.constructor);
17
- }
18
- };
19
- /**
20
- * Error for technical/runtime failures that cannot be prevented by TypeScript
21
- * This includes validation failures and AMQP channel issues
22
- */
23
- var TechnicalError = class extends ClientError {
24
- constructor(message, cause) {
25
- super(message);
26
- this.cause = cause;
27
- this.name = "TechnicalError";
28
- }
29
- };
30
- /**
31
9
  * Error thrown when message validation fails
32
10
  */
33
- var MessageValidationError = class extends ClientError {
11
+ var MessageValidationError = class extends Error {
34
12
  constructor(publisherName, issues) {
35
13
  super(`Message validation failed for publisher "${publisherName}"`);
36
14
  this.publisherName = publisherName;
37
15
  this.issues = issues;
38
16
  this.name = "MessageValidationError";
17
+ const ErrorConstructor = Error;
18
+ if (typeof ErrorConstructor.captureStackTrace === "function") ErrorConstructor.captureStackTrace(this, this.constructor);
39
19
  }
40
20
  };
41
21
 
@@ -48,13 +28,12 @@ const deflateAsync = promisify(deflate);
48
28
  *
49
29
  * @param buffer - The buffer to compress
50
30
  * @param algorithm - The compression algorithm to use
51
- * @returns A promise that resolves to the compressed buffer
52
- * @throws Error if compression fails
31
+ * @returns A Future with the compressed buffer or a TechnicalError
53
32
  *
54
33
  * @internal
55
34
  */
56
- async function compressBuffer(buffer, algorithm) {
57
- return match(algorithm).with("gzip", () => gzipAsync(buffer)).with("deflate", () => deflateAsync(buffer)).exhaustive();
35
+ function compressBuffer(buffer, algorithm) {
36
+ return match(algorithm).with("gzip", () => Future.fromPromise(gzipAsync(buffer)).mapError((error) => new TechnicalError("Failed to compress with gzip", error))).with("deflate", () => Future.fromPromise(deflateAsync(buffer)).mapError((error) => new TechnicalError("Failed to compress with deflate", error))).exhaustive();
58
37
  }
59
38
 
60
39
  //#endregion
@@ -100,15 +79,15 @@ var TypedAmqpClient = class TypedAmqpClient {
100
79
  *
101
80
  * @returns Result.Ok(void) on success, or Result.Error with specific error on failure
102
81
  */
82
+ /**
83
+ * Publish a message using a defined publisher.
84
+ * TypeScript guarantees publisher exists for valid publisher names.
85
+ */
103
86
  publish(publisherName, message, options) {
104
87
  const startTime = Date.now();
105
- const publishers = this.contract.publishers;
106
- if (!publishers) return Future.value(Result.Error(new TechnicalError("No publishers defined in contract")));
107
- const publisher = publishers[publisherName];
108
- if (!publisher) return Future.value(Result.Error(new TechnicalError(`Publisher "${String(publisherName)}" not found in contract`)));
109
- const exchangeName = publisher.exchange.name;
110
- const routingKey = publisher.routingKey;
111
- const span = startPublishSpan(this.telemetry, exchangeName, routingKey, { "amqp.publisher.name": String(publisherName) });
88
+ const publisher = this.contract.publishers[publisherName];
89
+ const { exchange, routingKey } = publisher;
90
+ const span = startPublishSpan(this.telemetry, exchange.name, routingKey, { "amqp.publisher.name": String(publisherName) });
112
91
  const validateMessage = () => {
113
92
  const validationResult = publisher.message.payload["~standard"].validate(message);
114
93
  return Future.fromPromise(validationResult instanceof Promise ? validationResult : Promise.resolve(validationResult)).mapError((error) => new TechnicalError(`Validation failed`, error)).mapOkToResult((validation) => {
@@ -123,11 +102,11 @@ var TypedAmqpClient = class TypedAmqpClient {
123
102
  if (compression) {
124
103
  const messageBuffer = Buffer.from(JSON.stringify(validatedMessage));
125
104
  publishOptions.contentEncoding = compression;
126
- return Future.fromPromise(compressBuffer(messageBuffer, compression)).mapError((error) => new TechnicalError(`Failed to compress message`, error)).map((compressedBuffer) => Result.Ok(compressedBuffer));
105
+ return compressBuffer(messageBuffer, compression);
127
106
  }
128
107
  return Future.value(Result.Ok(validatedMessage));
129
108
  };
130
- return preparePayload().flatMapOk((payload) => Future.fromPromise(this.amqpClient.channel.publish(publisher.exchange.name, publisher.routingKey ?? "", payload, publishOptions)).mapError((error) => new TechnicalError(`Failed to publish message`, error)).mapOkToResult((published) => {
109
+ return preparePayload().flatMapOk((payload) => this.amqpClient.publish(publisher.exchange.name, publisher.routingKey ?? "", payload, publishOptions).mapOkToResult((published) => {
131
110
  if (!published) return Result.Error(new TechnicalError(`Failed to publish message for publisher "${String(publisherName)}": Channel rejected the message (buffer full or other channel issue)`));
132
111
  this.logger?.info("Message published successfully", {
133
112
  publisherName: String(publisherName),
@@ -141,24 +120,24 @@ var TypedAmqpClient = class TypedAmqpClient {
141
120
  return validateMessage().flatMapOk((validatedMessage) => publishMessage(validatedMessage)).tapOk(() => {
142
121
  const durationMs = Date.now() - startTime;
143
122
  endSpanSuccess(span);
144
- recordPublishMetric(this.telemetry, exchangeName, routingKey, true, durationMs);
123
+ recordPublishMetric(this.telemetry, exchange.name, routingKey, true, durationMs);
145
124
  }).tapError((error) => {
146
125
  const durationMs = Date.now() - startTime;
147
126
  endSpanError(span, error);
148
- recordPublishMetric(this.telemetry, exchangeName, routingKey, false, durationMs);
127
+ recordPublishMetric(this.telemetry, exchange.name, routingKey, false, durationMs);
149
128
  });
150
129
  }
151
130
  /**
152
131
  * Close the channel and connection
153
132
  */
154
133
  close() {
155
- return Future.fromPromise(this.amqpClient.close()).mapError((error) => new TechnicalError("Failed to close AMQP connection", error)).mapOk(() => void 0);
134
+ return this.amqpClient.close().mapOk(() => void 0);
156
135
  }
157
136
  waitForConnectionReady() {
158
- return Future.fromPromise(this.amqpClient.channel.waitForConnect()).mapError((error) => new TechnicalError("Failed to wait for connection ready", error));
137
+ return this.amqpClient.waitForConnect();
159
138
  }
160
139
  };
161
140
 
162
141
  //#endregion
163
- export { MessageValidationError, TechnicalError, TypedAmqpClient };
142
+ export { MessageValidationError, TypedAmqpClient };
164
143
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":[],"sources":["../src/errors.ts","../src/compression.ts","../src/client.ts"],"sourcesContent":["/**\n * Base error class for client errors\n */\nabstract class ClientError extends Error {\n protected constructor(message: string) {\n super(message);\n this.name = \"ClientError\";\n // Node.js specific stack trace capture\n const ErrorConstructor = Error as unknown as {\n captureStackTrace?: (target: object, constructor: Function) => void;\n };\n if (typeof ErrorConstructor.captureStackTrace === \"function\") {\n ErrorConstructor.captureStackTrace(this, this.constructor);\n }\n }\n}\n\n/**\n * Error for technical/runtime failures that cannot be prevented by TypeScript\n * This includes validation failures and AMQP channel issues\n */\nexport class TechnicalError extends ClientError {\n constructor(\n message: string,\n public override readonly cause?: unknown,\n ) {\n super(message);\n this.name = \"TechnicalError\";\n }\n}\n\n/**\n * Error thrown when message validation fails\n */\nexport class MessageValidationError extends ClientError {\n constructor(\n public readonly publisherName: string,\n public readonly issues: unknown,\n ) {\n super(`Message validation failed for publisher \"${publisherName}\"`);\n this.name = \"MessageValidationError\";\n }\n}\n","import { deflate, gzip } from \"node:zlib\";\nimport type { CompressionAlgorithm } from \"@amqp-contract/contract\";\nimport { match } from \"ts-pattern\";\nimport { promisify } from \"node:util\";\n\nconst gzipAsync = promisify(gzip);\nconst deflateAsync = promisify(deflate);\n\n/**\n * Compress a buffer using the specified compression algorithm.\n *\n * @param buffer - The buffer to compress\n * @param algorithm - The compression algorithm to use\n * @returns A promise that resolves to the compressed buffer\n * @throws Error if compression fails\n *\n * @internal\n */\nexport async function compressBuffer(\n buffer: Buffer,\n algorithm: CompressionAlgorithm,\n): Promise<Buffer> {\n return match(algorithm)\n .with(\"gzip\", () => gzipAsync(buffer))\n .with(\"deflate\", () => deflateAsync(buffer))\n .exhaustive();\n}\n","import {\n AmqpClient,\n type Logger,\n type TelemetryProvider,\n defaultTelemetryProvider,\n endSpanError,\n endSpanSuccess,\n recordPublishMetric,\n startPublishSpan,\n} from \"@amqp-contract/core\";\nimport type { AmqpConnectionManagerOptions, ConnectionUrl } from \"amqp-connection-manager\";\nimport type {\n CompressionAlgorithm,\n ContractDefinition,\n InferPublisherNames,\n} from \"@amqp-contract/contract\";\nimport { Future, Result } from \"@swan-io/boxed\";\nimport { MessageValidationError, TechnicalError } from \"./errors.js\";\nimport type { ClientInferPublisherInput } from \"./types.js\";\nimport type { Options } from \"amqplib\";\nimport { compressBuffer } from \"./compression.js\";\n\n/**\n * Publish options that extend amqplib's Options.Publish with optional compression support.\n */\nexport type PublishOptions = Options.Publish & {\n /**\n * Optional compression algorithm to use for the message payload.\n * When specified, the message will be compressed using the chosen algorithm\n * and the contentEncoding header will be set automatically.\n */\n compression?: CompressionAlgorithm | undefined;\n};\n\n/**\n * Options for creating a client\n */\nexport type CreateClientOptions<TContract extends ContractDefinition> = {\n contract: TContract;\n urls: ConnectionUrl[];\n connectionOptions?: AmqpConnectionManagerOptions | undefined;\n logger?: Logger | undefined;\n /**\n * Optional telemetry provider for tracing and metrics.\n * If not provided, uses the default provider which attempts to load OpenTelemetry.\n * OpenTelemetry instrumentation is automatically enabled if @opentelemetry/api is installed.\n */\n telemetry?: TelemetryProvider | undefined;\n};\n\n/**\n * Type-safe AMQP client for publishing messages\n */\nexport class TypedAmqpClient<TContract extends ContractDefinition> {\n private constructor(\n private readonly contract: TContract,\n private readonly amqpClient: AmqpClient,\n private readonly logger?: Logger,\n private readonly telemetry: TelemetryProvider = defaultTelemetryProvider,\n ) {}\n\n /**\n * Create a type-safe AMQP client from a contract.\n *\n * Connection management (including automatic reconnection) is handled internally\n * by amqp-connection-manager via the {@link AmqpClient}. The client establishes\n * infrastructure asynchronously in the background once the connection is ready.\n *\n * Connections are automatically shared across clients with the same URLs and\n * connection options, following RabbitMQ best practices.\n */\n static create<TContract extends ContractDefinition>({\n contract,\n urls,\n connectionOptions,\n logger,\n telemetry,\n }: CreateClientOptions<TContract>): Future<Result<TypedAmqpClient<TContract>, TechnicalError>> {\n const client = new TypedAmqpClient(\n contract,\n new AmqpClient(contract, { urls, connectionOptions }),\n logger,\n telemetry ?? defaultTelemetryProvider,\n );\n\n return client.waitForConnectionReady().mapOk(() => client);\n }\n\n /**\n * Publish a message using a defined publisher\n *\n * @param publisherName - The name of the publisher to use\n * @param message - The message to publish\n * @param options - Optional publish options including compression, headers, priority, etc.\n *\n * @remarks\n * If `options.compression` is specified, the message will be compressed before publishing\n * and the `contentEncoding` property will be set automatically. Any `contentEncoding`\n * value already in options will be overwritten by the compression algorithm.\n *\n * @returns Result.Ok(void) on success, or Result.Error with specific error on failure\n */\n publish<TName extends InferPublisherNames<TContract>>(\n publisherName: TName,\n message: ClientInferPublisherInput<TContract, TName>,\n options?: PublishOptions,\n ): Future<Result<void, TechnicalError | MessageValidationError>> {\n const startTime = Date.now();\n const publishers = this.contract.publishers;\n if (!publishers) {\n return Future.value(Result.Error(new TechnicalError(\"No publishers defined in contract\")));\n }\n\n const publisher = publishers[publisherName as string];\n if (!publisher) {\n return Future.value(\n Result.Error(\n new TechnicalError(`Publisher \"${String(publisherName)}\" not found in contract`),\n ),\n );\n }\n\n const exchangeName = publisher.exchange.name;\n const routingKey = publisher.routingKey;\n\n // Start telemetry span\n const span = startPublishSpan(this.telemetry, exchangeName, routingKey, {\n \"amqp.publisher.name\": String(publisherName),\n });\n\n const validateMessage = () => {\n const validationResult = publisher.message.payload[\"~standard\"].validate(message);\n return Future.fromPromise(\n validationResult instanceof Promise ? validationResult : Promise.resolve(validationResult),\n )\n .mapError((error) => new TechnicalError(`Validation failed`, error))\n .mapOkToResult((validation) => {\n if (validation.issues) {\n return Result.Error(\n new MessageValidationError(String(publisherName), validation.issues),\n );\n }\n\n return Result.Ok(validation.value);\n });\n };\n\n const publishMessage = (validatedMessage: unknown): Future<Result<void, TechnicalError>> => {\n // Extract compression from options and create publish options without it\n const { compression, ...restOptions } = options ?? {};\n const publishOptions: Options.Publish = { ...restOptions };\n\n // Prepare payload and options based on compression configuration\n const preparePayload = (): Future<Result<Buffer | unknown, TechnicalError>> => {\n if (compression) {\n // Compress the message payload\n const messageBuffer = Buffer.from(JSON.stringify(validatedMessage));\n publishOptions.contentEncoding = compression;\n\n return Future.fromPromise(compressBuffer(messageBuffer, compression))\n .mapError((error) => new TechnicalError(`Failed to compress message`, error))\n .map((compressedBuffer) => Result.Ok(compressedBuffer));\n }\n\n // No compression: use the channel's built-in JSON serialization\n return Future.value(Result.Ok(validatedMessage));\n };\n\n // Publish the prepared payload\n return preparePayload().flatMapOk((payload) =>\n Future.fromPromise(\n this.amqpClient.channel.publish(\n publisher.exchange.name,\n publisher.routingKey ?? \"\",\n payload,\n publishOptions,\n ),\n )\n .mapError((error) => new TechnicalError(`Failed to publish message`, error))\n .mapOkToResult((published) => {\n if (!published) {\n return Result.Error(\n new TechnicalError(\n `Failed to publish message for publisher \"${String(publisherName)}\": Channel rejected the message (buffer full or other channel issue)`,\n ),\n );\n }\n\n this.logger?.info(\"Message published successfully\", {\n publisherName: String(publisherName),\n exchange: publisher.exchange.name,\n routingKey: publisher.routingKey,\n compressed: !!compression,\n });\n\n return Result.Ok(undefined);\n }),\n );\n };\n\n // Validate message using schema\n return validateMessage()\n .flatMapOk((validatedMessage) => publishMessage(validatedMessage))\n .tapOk(() => {\n const durationMs = Date.now() - startTime;\n endSpanSuccess(span);\n recordPublishMetric(this.telemetry, exchangeName, routingKey, true, durationMs);\n })\n .tapError((error) => {\n const durationMs = Date.now() - startTime;\n endSpanError(span, error);\n recordPublishMetric(this.telemetry, exchangeName, routingKey, false, durationMs);\n });\n }\n\n /**\n * Close the channel and connection\n */\n close(): Future<Result<void, TechnicalError>> {\n return Future.fromPromise(this.amqpClient.close())\n .mapError((error) => new TechnicalError(\"Failed to close AMQP connection\", error))\n .mapOk(() => undefined);\n }\n\n private waitForConnectionReady(): Future<Result<void, TechnicalError>> {\n return Future.fromPromise(this.amqpClient.channel.waitForConnect()).mapError(\n (error) => new TechnicalError(\"Failed to wait for connection ready\", error),\n );\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../src/errors.ts","../src/compression.ts","../src/client.ts"],"sourcesContent":["/**\n * Error thrown when message validation fails\n */\nexport class MessageValidationError extends Error {\n constructor(\n public readonly publisherName: string,\n public readonly issues: unknown,\n ) {\n super(`Message validation failed for publisher \"${publisherName}\"`);\n this.name = \"MessageValidationError\";\n // Node.js specific stack trace capture\n const ErrorConstructor = Error as unknown as {\n captureStackTrace?: (target: object, constructor: Function) => void;\n };\n if (typeof ErrorConstructor.captureStackTrace === \"function\") {\n ErrorConstructor.captureStackTrace(this, this.constructor);\n }\n }\n}\n","import { Future, Result } from \"@swan-io/boxed\";\nimport { deflate, gzip } from \"node:zlib\";\nimport type { CompressionAlgorithm } from \"@amqp-contract/contract\";\nimport { TechnicalError } from \"@amqp-contract/core\";\nimport { match } from \"ts-pattern\";\nimport { promisify } from \"node:util\";\n\nconst gzipAsync = promisify(gzip);\nconst deflateAsync = promisify(deflate);\n\n/**\n * Compress a buffer using the specified compression algorithm.\n *\n * @param buffer - The buffer to compress\n * @param algorithm - The compression algorithm to use\n * @returns A Future with the compressed buffer or a TechnicalError\n *\n * @internal\n */\nexport function compressBuffer(\n buffer: Buffer,\n algorithm: CompressionAlgorithm,\n): Future<Result<Buffer, TechnicalError>> {\n return match(algorithm)\n .with(\"gzip\", () =>\n Future.fromPromise(gzipAsync(buffer)).mapError(\n (error) => new TechnicalError(\"Failed to compress with gzip\", error),\n ),\n )\n .with(\"deflate\", () =>\n Future.fromPromise(deflateAsync(buffer)).mapError(\n (error) => new TechnicalError(\"Failed to compress with deflate\", error),\n ),\n )\n .exhaustive();\n}\n","import {\n AmqpClient,\n type Logger,\n TechnicalError,\n type TelemetryProvider,\n defaultTelemetryProvider,\n endSpanError,\n endSpanSuccess,\n recordPublishMetric,\n startPublishSpan,\n} from \"@amqp-contract/core\";\nimport type { AmqpConnectionManagerOptions, ConnectionUrl } from \"amqp-connection-manager\";\nimport type {\n CompressionAlgorithm,\n ContractDefinition,\n InferPublisherNames,\n} from \"@amqp-contract/contract\";\nimport { Future, Result } from \"@swan-io/boxed\";\nimport type { ClientInferPublisherInput } from \"./types.js\";\nimport { MessageValidationError } from \"./errors.js\";\nimport type { Options } from \"amqplib\";\nimport { compressBuffer } from \"./compression.js\";\n\n/**\n * Publish options that extend amqplib's Options.Publish with optional compression support.\n */\nexport type PublishOptions = Options.Publish & {\n /**\n * Optional compression algorithm to use for the message payload.\n * When specified, the message will be compressed using the chosen algorithm\n * and the contentEncoding header will be set automatically.\n */\n compression?: CompressionAlgorithm | undefined;\n};\n\n/**\n * Options for creating a client\n */\nexport type CreateClientOptions<TContract extends ContractDefinition> = {\n contract: TContract;\n urls: ConnectionUrl[];\n connectionOptions?: AmqpConnectionManagerOptions | undefined;\n logger?: Logger | undefined;\n /**\n * Optional telemetry provider for tracing and metrics.\n * If not provided, uses the default provider which attempts to load OpenTelemetry.\n * OpenTelemetry instrumentation is automatically enabled if @opentelemetry/api is installed.\n */\n telemetry?: TelemetryProvider | undefined;\n};\n\n/**\n * Type-safe AMQP client for publishing messages\n */\nexport class TypedAmqpClient<TContract extends ContractDefinition> {\n private constructor(\n private readonly contract: TContract,\n private readonly amqpClient: AmqpClient,\n private readonly logger?: Logger,\n private readonly telemetry: TelemetryProvider = defaultTelemetryProvider,\n ) {}\n\n /**\n * Create a type-safe AMQP client from a contract.\n *\n * Connection management (including automatic reconnection) is handled internally\n * by amqp-connection-manager via the {@link AmqpClient}. The client establishes\n * infrastructure asynchronously in the background once the connection is ready.\n *\n * Connections are automatically shared across clients with the same URLs and\n * connection options, following RabbitMQ best practices.\n */\n static create<TContract extends ContractDefinition>({\n contract,\n urls,\n connectionOptions,\n logger,\n telemetry,\n }: CreateClientOptions<TContract>): Future<Result<TypedAmqpClient<TContract>, TechnicalError>> {\n const client = new TypedAmqpClient(\n contract,\n new AmqpClient(contract, { urls, connectionOptions }),\n logger,\n telemetry ?? defaultTelemetryProvider,\n );\n\n return client.waitForConnectionReady().mapOk(() => client);\n }\n\n /**\n * Publish a message using a defined publisher\n *\n * @param publisherName - The name of the publisher to use\n * @param message - The message to publish\n * @param options - Optional publish options including compression, headers, priority, etc.\n *\n * @remarks\n * If `options.compression` is specified, the message will be compressed before publishing\n * and the `contentEncoding` property will be set automatically. Any `contentEncoding`\n * value already in options will be overwritten by the compression algorithm.\n *\n * @returns Result.Ok(void) on success, or Result.Error with specific error on failure\n */\n /**\n * Publish a message using a defined publisher.\n * TypeScript guarantees publisher exists for valid publisher names.\n */\n publish<TName extends InferPublisherNames<TContract>>(\n publisherName: TName,\n message: ClientInferPublisherInput<TContract, TName>,\n options?: PublishOptions,\n ): Future<Result<void, TechnicalError | MessageValidationError>> {\n const startTime = Date.now();\n // Non-null assertions safe: TypeScript guarantees these exist for valid TName\n const publisher = this.contract.publishers![publisherName as string]!;\n const { exchange, routingKey } = publisher;\n\n // Start telemetry span\n const span = startPublishSpan(this.telemetry, exchange.name, routingKey, {\n \"amqp.publisher.name\": String(publisherName),\n });\n\n const validateMessage = () => {\n const validationResult = publisher.message.payload[\"~standard\"].validate(message);\n return Future.fromPromise(\n validationResult instanceof Promise ? validationResult : Promise.resolve(validationResult),\n )\n .mapError((error) => new TechnicalError(`Validation failed`, error))\n .mapOkToResult((validation) => {\n if (validation.issues) {\n return Result.Error(\n new MessageValidationError(String(publisherName), validation.issues),\n );\n }\n\n return Result.Ok(validation.value);\n });\n };\n\n const publishMessage = (validatedMessage: unknown): Future<Result<void, TechnicalError>> => {\n // Extract compression from options and create publish options without it\n const { compression, ...restOptions } = options ?? {};\n const publishOptions: Options.Publish = { ...restOptions };\n\n // Prepare payload and options based on compression configuration\n const preparePayload = (): Future<Result<Buffer | unknown, TechnicalError>> => {\n if (compression) {\n // Compress the message payload\n const messageBuffer = Buffer.from(JSON.stringify(validatedMessage));\n publishOptions.contentEncoding = compression;\n\n return compressBuffer(messageBuffer, compression);\n }\n\n // No compression: use the channel's built-in JSON serialization\n return Future.value(Result.Ok(validatedMessage));\n };\n\n // Publish the prepared payload\n return preparePayload().flatMapOk((payload) =>\n this.amqpClient\n .publish(publisher.exchange.name, publisher.routingKey ?? \"\", payload, publishOptions)\n .mapOkToResult((published) => {\n if (!published) {\n return Result.Error(\n new TechnicalError(\n `Failed to publish message for publisher \"${String(publisherName)}\": Channel rejected the message (buffer full or other channel issue)`,\n ),\n );\n }\n\n this.logger?.info(\"Message published successfully\", {\n publisherName: String(publisherName),\n exchange: publisher.exchange.name,\n routingKey: publisher.routingKey,\n compressed: !!compression,\n });\n\n return Result.Ok(undefined);\n }),\n );\n };\n\n // Validate message using schema\n return validateMessage()\n .flatMapOk((validatedMessage) => publishMessage(validatedMessage))\n .tapOk(() => {\n const durationMs = Date.now() - startTime;\n endSpanSuccess(span);\n recordPublishMetric(this.telemetry, exchange.name, routingKey, true, durationMs);\n })\n .tapError((error) => {\n const durationMs = Date.now() - startTime;\n endSpanError(span, error);\n recordPublishMetric(this.telemetry, exchange.name, routingKey, false, durationMs);\n });\n }\n\n /**\n * Close the channel and connection\n */\n close(): Future<Result<void, TechnicalError>> {\n return this.amqpClient.close().mapOk(() => undefined);\n }\n\n private waitForConnectionReady(): Future<Result<void, TechnicalError>> {\n return this.amqpClient.waitForConnect();\n }\n}\n"],"mappings":"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"}
package/docs/index.md CHANGED
@@ -8,13 +8,13 @@
8
8
 
9
9
  ### MessageValidationError
10
10
 
11
- Defined in: [packages/client/src/errors.ts:35](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/errors.ts#L35)
11
+ Defined in: [packages/client/src/errors.ts:4](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/errors.ts#L4)
12
12
 
13
13
  Error thrown when message validation fails
14
14
 
15
15
  #### Extends
16
16
 
17
- - `ClientError`
17
+ - `Error`
18
18
 
19
19
  #### Constructors
20
20
 
@@ -24,7 +24,7 @@ Error thrown when message validation fails
24
24
  new MessageValidationError(publisherName, issues): MessageValidationError;
25
25
  ```
26
26
 
27
- Defined in: [packages/client/src/errors.ts:36](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/errors.ts#L36)
27
+ Defined in: [packages/client/src/errors.ts:5](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/errors.ts#L5)
28
28
 
29
29
  ###### Parameters
30
30
 
@@ -40,20 +40,20 @@ Defined in: [packages/client/src/errors.ts:36](https://github.com/btravers/amqp-
40
40
  ###### Overrides
41
41
 
42
42
  ```ts
43
- ClientError.constructor
43
+ Error.constructor
44
44
  ```
45
45
 
46
46
  #### Properties
47
47
 
48
48
  | Property | Modifier | Type | Description | Inherited from | Defined in |
49
49
  | ------ | ------ | ------ | ------ | ------ | ------ |
50
- | <a id="cause"></a> `cause?` | `public` | `unknown` | - | `ClientError.cause` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es2022.error.d.ts:26 |
51
- | <a id="issues"></a> `issues` | `readonly` | `unknown` | - | - | [packages/client/src/errors.ts:38](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/errors.ts#L38) |
52
- | <a id="message"></a> `message` | `public` | `string` | - | `ClientError.message` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1077 |
53
- | <a id="name"></a> `name` | `public` | `string` | - | `ClientError.name` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 |
54
- | <a id="publishername"></a> `publisherName` | `readonly` | `string` | - | - | [packages/client/src/errors.ts:37](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/errors.ts#L37) |
55
- | <a id="stack"></a> `stack?` | `public` | `string` | - | `ClientError.stack` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1078 |
56
- | <a id="stacktracelimit"></a> `stackTraceLimit` | `static` | `number` | The `Error.stackTraceLimit` property specifies the number of stack frames collected by a stack trace (whether generated by `new Error().stack` or `Error.captureStackTrace(obj)`). The default value is `10` but may be set to any valid JavaScript number. Changes will affect any stack trace captured _after_ the value has been changed. If set to a non-number value, or set to a negative number, stack traces will not capture any frames. | `ClientError.stackTraceLimit` | node\_modules/.pnpm/@types+node@25.0.5/node\_modules/@types/node/globals.d.ts:67 |
50
+ | <a id="cause"></a> `cause?` | `public` | `unknown` | - | `Error.cause` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es2022.error.d.ts:26 |
51
+ | <a id="issues"></a> `issues` | `readonly` | `unknown` | - | - | [packages/client/src/errors.ts:7](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/errors.ts#L7) |
52
+ | <a id="message"></a> `message` | `public` | `string` | - | `Error.message` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1077 |
53
+ | <a id="name"></a> `name` | `public` | `string` | - | `Error.name` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 |
54
+ | <a id="publishername"></a> `publisherName` | `readonly` | `string` | - | - | [packages/client/src/errors.ts:6](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/errors.ts#L6) |
55
+ | <a id="stack"></a> `stack?` | `public` | `string` | - | `Error.stack` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1078 |
56
+ | <a id="stacktracelimit"></a> `stackTraceLimit` | `static` | `number` | The `Error.stackTraceLimit` property specifies the number of stack frames collected by a stack trace (whether generated by `new Error().stack` or `Error.captureStackTrace(obj)`). The default value is `10` but may be set to any valid JavaScript number. Changes will affect any stack trace captured _after_ the value has been changed. If set to a non-number value, or set to a negative number, stack traces will not capture any frames. | `Error.stackTraceLimit` | node\_modules/.pnpm/@types+node@25.0.9/node\_modules/@types/node/globals.d.ts:67 |
57
57
 
58
58
  #### Methods
59
59
 
@@ -63,7 +63,7 @@ ClientError.constructor
63
63
  static captureStackTrace(targetObject, constructorOpt?): void;
64
64
  ```
65
65
 
66
- Defined in: node\_modules/.pnpm/@types+node@25.0.5/node\_modules/@types/node/globals.d.ts:51
66
+ Defined in: node\_modules/.pnpm/@types+node@25.0.9/node\_modules/@types/node/globals.d.ts:51
67
67
 
68
68
  Creates a `.stack` property on `targetObject`, which when accessed returns
69
69
  a string representing the location in the code at which
@@ -123,7 +123,7 @@ a();
123
123
  ###### Inherited from
124
124
 
125
125
  ```ts
126
- ClientError.captureStackTrace
126
+ Error.captureStackTrace
127
127
  ```
128
128
 
129
129
  ##### prepareStackTrace()
@@ -132,7 +132,7 @@ ClientError.captureStackTrace
132
132
  static prepareStackTrace(err, stackTraces): any;
133
133
  ```
134
134
 
135
- Defined in: node\_modules/.pnpm/@types+node@25.0.5/node\_modules/@types/node/globals.d.ts:55
135
+ Defined in: node\_modules/.pnpm/@types+node@25.0.9/node\_modules/@types/node/globals.d.ts:55
136
136
 
137
137
  ###### Parameters
138
138
 
@@ -152,164 +152,14 @@ https://v8.dev/docs/stack-trace-api#customizing-stack-traces
152
152
  ###### Inherited from
153
153
 
154
154
  ```ts
155
- ClientError.prepareStackTrace
156
- ```
157
-
158
- ***
159
-
160
- ### TechnicalError
161
-
162
- Defined in: [packages/client/src/errors.ts:22](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/errors.ts#L22)
163
-
164
- Error for technical/runtime failures that cannot be prevented by TypeScript
165
- This includes validation failures and AMQP channel issues
166
-
167
- #### Extends
168
-
169
- - `ClientError`
170
-
171
- #### Constructors
172
-
173
- ##### Constructor
174
-
175
- ```ts
176
- new TechnicalError(message, cause?): TechnicalError;
177
- ```
178
-
179
- Defined in: [packages/client/src/errors.ts:23](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/errors.ts#L23)
180
-
181
- ###### Parameters
182
-
183
- | Parameter | Type |
184
- | ------ | ------ |
185
- | `message` | `string` |
186
- | `cause?` | `unknown` |
187
-
188
- ###### Returns
189
-
190
- [`TechnicalError`](#technicalerror)
191
-
192
- ###### Overrides
193
-
194
- ```ts
195
- ClientError.constructor
196
- ```
197
-
198
- #### Properties
199
-
200
- | Property | Modifier | Type | Description | Inherited from | Defined in |
201
- | ------ | ------ | ------ | ------ | ------ | ------ |
202
- | <a id="cause-1"></a> `cause?` | `readonly` | `unknown` | - | `ClientError.cause` | [packages/client/src/errors.ts:25](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/errors.ts#L25) |
203
- | <a id="message-1"></a> `message` | `public` | `string` | - | `ClientError.message` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1077 |
204
- | <a id="name-1"></a> `name` | `public` | `string` | - | `ClientError.name` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1076 |
205
- | <a id="stack-1"></a> `stack?` | `public` | `string` | - | `ClientError.stack` | node\_modules/.pnpm/typescript@5.9.3/node\_modules/typescript/lib/lib.es5.d.ts:1078 |
206
- | <a id="stacktracelimit-1"></a> `stackTraceLimit` | `static` | `number` | The `Error.stackTraceLimit` property specifies the number of stack frames collected by a stack trace (whether generated by `new Error().stack` or `Error.captureStackTrace(obj)`). The default value is `10` but may be set to any valid JavaScript number. Changes will affect any stack trace captured _after_ the value has been changed. If set to a non-number value, or set to a negative number, stack traces will not capture any frames. | `ClientError.stackTraceLimit` | node\_modules/.pnpm/@types+node@25.0.5/node\_modules/@types/node/globals.d.ts:67 |
207
-
208
- #### Methods
209
-
210
- ##### captureStackTrace()
211
-
212
- ```ts
213
- static captureStackTrace(targetObject, constructorOpt?): void;
214
- ```
215
-
216
- Defined in: node\_modules/.pnpm/@types+node@25.0.5/node\_modules/@types/node/globals.d.ts:51
217
-
218
- Creates a `.stack` property on `targetObject`, which when accessed returns
219
- a string representing the location in the code at which
220
- `Error.captureStackTrace()` was called.
221
-
222
- ```js
223
- const myObject = {};
224
- Error.captureStackTrace(myObject);
225
- myObject.stack; // Similar to `new Error().stack`
226
- ```
227
-
228
- The first line of the trace will be prefixed with
229
- `${myObject.name}: ${myObject.message}`.
230
-
231
- The optional `constructorOpt` argument accepts a function. If given, all frames
232
- above `constructorOpt`, including `constructorOpt`, will be omitted from the
233
- generated stack trace.
234
-
235
- The `constructorOpt` argument is useful for hiding implementation
236
- details of error generation from the user. For instance:
237
-
238
- ```js
239
- function a() {
240
- b();
241
- }
242
-
243
- function b() {
244
- c();
245
- }
246
-
247
- function c() {
248
- // Create an error without stack trace to avoid calculating the stack trace twice.
249
- const { stackTraceLimit } = Error;
250
- Error.stackTraceLimit = 0;
251
- const error = new Error();
252
- Error.stackTraceLimit = stackTraceLimit;
253
-
254
- // Capture the stack trace above function b
255
- Error.captureStackTrace(error, b); // Neither function c, nor b is included in the stack trace
256
- throw error;
257
- }
258
-
259
- a();
260
- ```
261
-
262
- ###### Parameters
263
-
264
- | Parameter | Type |
265
- | ------ | ------ |
266
- | `targetObject` | `object` |
267
- | `constructorOpt?` | `Function` |
268
-
269
- ###### Returns
270
-
271
- `void`
272
-
273
- ###### Inherited from
274
-
275
- ```ts
276
- ClientError.captureStackTrace
277
- ```
278
-
279
- ##### prepareStackTrace()
280
-
281
- ```ts
282
- static prepareStackTrace(err, stackTraces): any;
283
- ```
284
-
285
- Defined in: node\_modules/.pnpm/@types+node@25.0.5/node\_modules/@types/node/globals.d.ts:55
286
-
287
- ###### Parameters
288
-
289
- | Parameter | Type |
290
- | ------ | ------ |
291
- | `err` | `Error` |
292
- | `stackTraces` | `CallSite`[] |
293
-
294
- ###### Returns
295
-
296
- `any`
297
-
298
- ###### See
299
-
300
- https://v8.dev/docs/stack-trace-api#customizing-stack-traces
301
-
302
- ###### Inherited from
303
-
304
- ```ts
305
- ClientError.prepareStackTrace
155
+ Error.prepareStackTrace
306
156
  ```
307
157
 
308
158
  ***
309
159
 
310
160
  ### TypedAmqpClient
311
161
 
312
- Defined in: [packages/client/src/client.ts:54](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/client.ts#L54)
162
+ Defined in: [packages/client/src/client.ts:55](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/client.ts#L55)
313
163
 
314
164
  Type-safe AMQP client for publishing messages
315
165
 
@@ -327,13 +177,13 @@ Type-safe AMQP client for publishing messages
327
177
  close(): Future<Result<void, TechnicalError>>;
328
178
  ```
329
179
 
330
- Defined in: [packages/client/src/client.ts:219](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/client.ts#L219)
180
+ Defined in: [packages/client/src/client.ts:202](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/client.ts#L202)
331
181
 
332
182
  Close the channel and connection
333
183
 
334
184
  ###### Returns
335
185
 
336
- `Future`\<`Result`\<`void`, [`TechnicalError`](#technicalerror)\>\>
186
+ `Future`&lt;`Result`&lt;`void`, `TechnicalError`&gt;&gt;
337
187
 
338
188
  ##### publish()
339
189
 
@@ -341,14 +191,13 @@ Close the channel and connection
341
191
  publish<TName>(
342
192
  publisherName,
343
193
  message,
344
- options?): Future<Result<void,
345
- | TechnicalError
346
- | MessageValidationError>>;
194
+ options?): Future<Result<void, TechnicalError | MessageValidationError>>;
347
195
  ```
348
196
 
349
- Defined in: [packages/client/src/client.ts:103](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/client.ts#L103)
197
+ Defined in: [packages/client/src/client.ts:108](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/client.ts#L108)
350
198
 
351
- Publish a message using a defined publisher
199
+ Publish a message using a defined publisher.
200
+ TypeScript guarantees publisher exists for valid publisher names.
352
201
 
353
202
  ###### Type Parameters
354
203
 
@@ -358,25 +207,15 @@ Publish a message using a defined publisher
358
207
 
359
208
  ###### Parameters
360
209
 
361
- | Parameter | Type | Description |
362
- | ------ | ------ | ------ |
363
- | `publisherName` | `TName` | The name of the publisher to use |
364
- | `message` | [`ClientInferPublisherInput`](#clientinferpublisherinput)\<`TContract`, `TName`\> | The message to publish |
365
- | `options?` | [`PublishOptions`](#publishoptions) | Optional publish options including compression, headers, priority, etc. |
210
+ | Parameter | Type |
211
+ | ------ | ------ |
212
+ | `publisherName` | `TName` |
213
+ | `message` | [`ClientInferPublisherInput`](#clientinferpublisherinput)&lt;`TContract`, `TName`&gt; |
214
+ | `options?` | [`PublishOptions`](#publishoptions) |
366
215
 
367
216
  ###### Returns
368
217
 
369
- `Future`\<`Result`\<`void`,
370
- \| [`TechnicalError`](#technicalerror)
371
- \| [`MessageValidationError`](#messagevalidationerror)\>\>
372
-
373
- Result.Ok(void) on success, or Result.Error with specific error on failure
374
-
375
- ###### Remarks
376
-
377
- If `options.compression` is specified, the message will be compressed before publishing
378
- and the `contentEncoding` property will be set automatically. Any `contentEncoding`
379
- value already in options will be overwritten by the compression algorithm.
218
+ `Future`&lt;`Result`&lt;`void`, `TechnicalError` \| [`MessageValidationError`](#messagevalidationerror)&gt;&gt;
380
219
 
381
220
  ##### create()
382
221
 
@@ -384,7 +223,7 @@ value already in options will be overwritten by the compression algorithm.
384
223
  static create<TContract>(__namedParameters): Future<Result<TypedAmqpClient<TContract>, TechnicalError>>;
385
224
  ```
386
225
 
387
- Defined in: [packages/client/src/client.ts:72](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/client.ts#L72)
226
+ Defined in: [packages/client/src/client.ts:73](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/client.ts#L73)
388
227
 
389
228
  Create a type-safe AMQP client from a contract.
390
229
 
@@ -405,11 +244,11 @@ connection options, following RabbitMQ best practices.
405
244
 
406
245
  | Parameter | Type |
407
246
  | ------ | ------ |
408
- | `__namedParameters` | [`CreateClientOptions`](#createclientoptions)\<`TContract`\> |
247
+ | `__namedParameters` | [`CreateClientOptions`](#createclientoptions)&lt;`TContract`&gt; |
409
248
 
410
249
  ###### Returns
411
250
 
412
- `Future`\<`Result`\<[`TypedAmqpClient`](#typedamqpclient)\<`TContract`\>, [`TechnicalError`](#technicalerror)\>\>
251
+ `Future`&lt;`Result`&lt;[`TypedAmqpClient`](#typedamqpclient)&lt;`TContract`&gt;, `TechnicalError`&gt;&gt;
413
252
 
414
253
  ## Type Aliases
415
254
 
@@ -419,7 +258,7 @@ connection options, following RabbitMQ best practices.
419
258
  type ClientInferPublisherInput<TContract, TName> = PublisherInferInput<InferPublisher<TContract, TName>>;
420
259
  ```
421
260
 
422
- Defined in: [packages/client/src/types.ts:37](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/types.ts#L37)
261
+ Defined in: [packages/client/src/types.ts:37](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/types.ts#L37)
423
262
 
424
263
  Infer publisher input type (message payload) for a specific publisher in a contract
425
264
 
@@ -428,7 +267,7 @@ Infer publisher input type (message payload) for a specific publisher in a contr
428
267
  | Type Parameter |
429
268
  | ------ |
430
269
  | `TContract` *extends* `ContractDefinition` |
431
- | `TName` *extends* `InferPublisherNames`\<`TContract`\> |
270
+ | `TName` *extends* `InferPublisherNames`&lt;`TContract`&gt; |
432
271
 
433
272
  ***
434
273
 
@@ -438,7 +277,7 @@ Infer publisher input type (message payload) for a specific publisher in a contr
438
277
  type CreateClientOptions<TContract> = object;
439
278
  ```
440
279
 
441
- Defined in: [packages/client/src/client.ts:38](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/client.ts#L38)
280
+ Defined in: [packages/client/src/client.ts:39](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/client.ts#L39)
442
281
 
443
282
  Options for creating a client
444
283
 
@@ -452,11 +291,11 @@ Options for creating a client
452
291
 
453
292
  | Property | Type | Description | Defined in |
454
293
  | ------ | ------ | ------ | ------ |
455
- | <a id="connectionoptions"></a> `connectionOptions?` | `AmqpConnectionManagerOptions` | - | [packages/client/src/client.ts:41](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/client.ts#L41) |
456
- | <a id="contract"></a> `contract` | `TContract` | - | [packages/client/src/client.ts:39](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/client.ts#L39) |
457
- | <a id="logger"></a> `logger?` | `Logger` | - | [packages/client/src/client.ts:42](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/client.ts#L42) |
458
- | <a id="telemetry"></a> `telemetry?` | `TelemetryProvider` | Optional telemetry provider for tracing and metrics. If not provided, uses the default provider which attempts to load OpenTelemetry. OpenTelemetry instrumentation is automatically enabled if @opentelemetry/api is installed. | [packages/client/src/client.ts:48](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/client.ts#L48) |
459
- | <a id="urls"></a> `urls` | `ConnectionUrl`[] | - | [packages/client/src/client.ts:40](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/client.ts#L40) |
294
+ | <a id="connectionoptions"></a> `connectionOptions?` | `AmqpConnectionManagerOptions` | - | [packages/client/src/client.ts:42](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/client.ts#L42) |
295
+ | <a id="contract"></a> `contract` | `TContract` | - | [packages/client/src/client.ts:40](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/client.ts#L40) |
296
+ | <a id="logger"></a> `logger?` | `Logger` | - | [packages/client/src/client.ts:43](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/client.ts#L43) |
297
+ | <a id="telemetry"></a> `telemetry?` | `TelemetryProvider` | Optional telemetry provider for tracing and metrics. If not provided, uses the default provider which attempts to load OpenTelemetry. OpenTelemetry instrumentation is automatically enabled if @opentelemetry/api is installed. | [packages/client/src/client.ts:49](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/client.ts#L49) |
298
+ | <a id="urls"></a> `urls` | `ConnectionUrl`[] | - | [packages/client/src/client.ts:41](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/client.ts#L41) |
460
299
 
461
300
  ***
462
301
 
@@ -466,7 +305,7 @@ Options for creating a client
466
305
  type PublishOptions = Options.Publish & object;
467
306
  ```
468
307
 
469
- Defined in: [packages/client/src/client.ts:26](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/client.ts#L26)
308
+ Defined in: [packages/client/src/client.ts:27](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/client.ts#L27)
470
309
 
471
310
  Publish options that extend amqplib's Options.Publish with optional compression support.
472
311
 
@@ -474,4 +313,4 @@ Publish options that extend amqplib's Options.Publish with optional compression
474
313
 
475
314
  | Name | Type | Description | Defined in |
476
315
  | ------ | ------ | ------ | ------ |
477
- | `compression?` | `CompressionAlgorithm` | Optional compression algorithm to use for the message payload. When specified, the message will be compressed using the chosen algorithm and the contentEncoding header will be set automatically. | [packages/client/src/client.ts:32](https://github.com/btravers/amqp-contract/blob/00468eb63a019d6161c43f07dab8b68232bbb383/packages/client/src/client.ts#L32) |
316
+ | `compression?` | `CompressionAlgorithm` | Optional compression algorithm to use for the message payload. When specified, the message will be compressed using the chosen algorithm and the contentEncoding header will be set automatically. | [packages/client/src/client.ts:33](https://github.com/btravers/amqp-contract/blob/c50b9d5f661ce899d34d7eebcfafa47844bd1087/packages/client/src/client.ts#L33) |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@amqp-contract/client",
3
- "version": "0.10.0",
3
+ "version": "0.12.0",
4
4
  "description": "Client utilities for publishing messages using amqp-contract",
5
5
  "keywords": [
6
6
  "amqp",
@@ -53,22 +53,22 @@
53
53
  "@standard-schema/spec": "1.1.0",
54
54
  "@swan-io/boxed": "3.2.1",
55
55
  "ts-pattern": "5.9.0",
56
- "@amqp-contract/contract": "0.10.0",
57
- "@amqp-contract/core": "0.10.0"
56
+ "@amqp-contract/contract": "0.12.0",
57
+ "@amqp-contract/core": "0.12.0"
58
58
  },
59
59
  "devDependencies": {
60
60
  "@types/amqplib": "0.10.8",
61
- "@types/node": "25.0.5",
62
- "@vitest/coverage-v8": "4.0.16",
61
+ "@types/node": "25.0.9",
62
+ "@vitest/coverage-v8": "4.0.17",
63
63
  "amqp-connection-manager": "5.0.0",
64
64
  "amqplib": "0.10.9",
65
65
  "tsdown": "0.19.0",
66
- "typedoc": "0.28.15",
66
+ "typedoc": "0.28.16",
67
67
  "typedoc-plugin-markdown": "4.9.0",
68
68
  "typescript": "5.9.3",
69
- "vitest": "4.0.16",
69
+ "vitest": "4.0.17",
70
70
  "zod": "4.3.5",
71
- "@amqp-contract/testing": "0.10.0",
71
+ "@amqp-contract/testing": "0.12.0",
72
72
  "@amqp-contract/tsconfig": "0.1.0",
73
73
  "@amqp-contract/typedoc": "0.1.0"
74
74
  },