@amqp-contract/client 0.6.0 → 0.8.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/README.md CHANGED
@@ -19,37 +19,24 @@ pnpm add @amqp-contract/client
19
19
  ## Usage
20
20
 
21
21
  ```typescript
22
- import { TypedAmqpClient } from '@amqp-contract/client';
23
- import { contract } from './contract';
22
+ import { TypedAmqpClient } from "@amqp-contract/client";
23
+ import { contract } from "./contract";
24
24
 
25
25
  // Create client from contract (automatically connects and waits for connection)
26
- const clientResult = await TypedAmqpClient.create({
26
+ const client = await TypedAmqpClient.create({
27
27
  contract,
28
- urls: ['amqp://localhost']
29
- });
30
-
31
- // Handle connection errors
32
- if (clientResult.isError()) {
33
- console.error('Failed to create client:', clientResult.error);
34
- throw clientResult.error; // or handle appropriately
35
- }
36
-
37
- const client = clientResult.get();
28
+ urls: ["amqp://localhost"],
29
+ }).resultToPromise();
38
30
 
39
31
  // Publish message with explicit error handling
40
- const result = await client.publish('orderCreated', {
41
- orderId: 'ORD-123',
42
- amount: 99.99,
43
- });
44
-
45
- // Handle errors explicitly - no exceptions thrown
46
- if (result.isError()) {
47
- console.error('Failed to publish:', result.error);
48
- // result.error is either TechnicalError or MessageValidationError
49
- return;
50
- }
51
-
52
- console.log('Published successfully');
32
+ const result = await client
33
+ .publish("orderCreated", {
34
+ orderId: "ORD-123",
35
+ amount: 99.99,
36
+ })
37
+ .resultToPromise();
38
+
39
+ console.log("Published successfully");
53
40
 
54
41
  // Clean up
55
42
  await client.close();
package/dist/index.cjs CHANGED
@@ -1,5 +1,8 @@
1
1
  let _amqp_contract_core = require("@amqp-contract/core");
2
2
  let _swan_io_boxed = require("@swan-io/boxed");
3
+ let node_zlib = require("node:zlib");
4
+ let ts_pattern = require("ts-pattern");
5
+ let node_util = require("node:util");
3
6
 
4
7
  //#region src/errors.ts
5
8
  /**
@@ -36,6 +39,24 @@ var MessageValidationError = class extends ClientError {
36
39
  }
37
40
  };
38
41
 
42
+ //#endregion
43
+ //#region src/compression.ts
44
+ const gzipAsync = (0, node_util.promisify)(node_zlib.gzip);
45
+ const deflateAsync = (0, node_util.promisify)(node_zlib.deflate);
46
+ /**
47
+ * Compress a buffer using the specified compression algorithm.
48
+ *
49
+ * @param buffer - The buffer to compress
50
+ * @param algorithm - The compression algorithm to use
51
+ * @returns A promise that resolves to the compressed buffer
52
+ * @throws Error if compression fails
53
+ *
54
+ * @internal
55
+ */
56
+ async function compressBuffer(buffer, algorithm) {
57
+ return (0, ts_pattern.match)(algorithm).with("gzip", () => gzipAsync(buffer)).with("deflate", () => deflateAsync(buffer)).exhaustive();
58
+ }
59
+
39
60
  //#endregion
40
61
  //#region src/client.ts
41
62
  /**
@@ -66,7 +87,17 @@ var TypedAmqpClient = class TypedAmqpClient {
66
87
  }
67
88
  /**
68
89
  * Publish a message using a defined publisher
69
- * Returns Result.Ok(true) on success, or Result.Error with specific error on failure
90
+ *
91
+ * @param publisherName - The name of the publisher to use
92
+ * @param message - The message to publish
93
+ * @param options - Optional publish options including compression, headers, priority, etc.
94
+ *
95
+ * @remarks
96
+ * If `options.compression` is specified, the message will be compressed before publishing
97
+ * and the `contentEncoding` property will be set automatically. Any `contentEncoding`
98
+ * value already in options will be overwritten by the compression algorithm.
99
+ *
100
+ * @returns Result.Ok(void) on success, or Result.Error with specific error on failure
70
101
  */
71
102
  publish(publisherName, message, options) {
72
103
  const publishers = this.contract.publishers;
@@ -81,15 +112,26 @@ var TypedAmqpClient = class TypedAmqpClient {
81
112
  });
82
113
  };
83
114
  const publishMessage = (validatedMessage) => {
84
- return _swan_io_boxed.Future.fromPromise(this.amqpClient.channel.publish(publisher.exchange.name, publisher.routingKey ?? "", validatedMessage, options)).mapError((error) => new TechnicalError(`Failed to publish message`, error)).mapOkToResult((published) => {
115
+ const { compression, ...restOptions } = options ?? {};
116
+ const publishOptions = { ...restOptions };
117
+ const preparePayload = () => {
118
+ if (compression) {
119
+ const messageBuffer = Buffer.from(JSON.stringify(validatedMessage));
120
+ publishOptions.contentEncoding = compression;
121
+ 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));
122
+ }
123
+ return _swan_io_boxed.Future.value(_swan_io_boxed.Result.Ok(validatedMessage));
124
+ };
125
+ 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) => {
85
126
  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)`));
86
127
  this.logger?.info("Message published successfully", {
87
128
  publisherName: String(publisherName),
88
129
  exchange: publisher.exchange.name,
89
- routingKey: publisher.routingKey
130
+ routingKey: publisher.routingKey,
131
+ compressed: !!compression
90
132
  });
91
133
  return _swan_io_boxed.Result.Ok(void 0);
92
- });
134
+ }));
93
135
  };
94
136
  return validateMessage().flatMapOk((validatedMessage) => publishMessage(validatedMessage));
95
137
  }
package/dist/index.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Logger } from "@amqp-contract/core";
2
2
  import { AmqpConnectionManagerOptions, ConnectionUrl } from "amqp-connection-manager";
3
- import { ContractDefinition, InferPublisherNames, PublisherDefinition } from "@amqp-contract/contract";
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";
@@ -52,6 +52,17 @@ type InferPublisher<TContract extends ContractDefinition, TName extends InferPub
52
52
  type ClientInferPublisherInput<TContract extends ContractDefinition, TName extends InferPublisherNames<TContract>> = PublisherInferInput<InferPublisher<TContract, TName>>;
53
53
  //#endregion
54
54
  //#region src/client.d.ts
55
+ /**
56
+ * Publish options that extend amqplib's Options.Publish with optional compression support.
57
+ */
58
+ type PublishOptions = Options.Publish & {
59
+ /**
60
+ * Optional compression algorithm to use for the message payload.
61
+ * When specified, the message will be compressed using the chosen algorithm
62
+ * and the contentEncoding header will be set automatically.
63
+ */
64
+ compression?: CompressionAlgorithm | undefined;
65
+ };
55
66
  /**
56
67
  * Options for creating a client
57
68
  */
@@ -87,9 +98,19 @@ declare class TypedAmqpClient<TContract extends ContractDefinition> {
87
98
  }: CreateClientOptions<TContract>): Future<Result<TypedAmqpClient<TContract>, TechnicalError>>;
88
99
  /**
89
100
  * Publish a message using a defined publisher
90
- * Returns Result.Ok(true) on success, or Result.Error with specific error on failure
101
+ *
102
+ * @param publisherName - The name of the publisher to use
103
+ * @param message - The message to publish
104
+ * @param options - Optional publish options including compression, headers, priority, etc.
105
+ *
106
+ * @remarks
107
+ * If `options.compression` is specified, the message will be compressed before publishing
108
+ * and the `contentEncoding` property will be set automatically. Any `contentEncoding`
109
+ * value already in options will be overwritten by the compression algorithm.
110
+ *
111
+ * @returns Result.Ok(void) on success, or Result.Error with specific error on failure
91
112
  */
92
- publish<TName extends InferPublisherNames<TContract>>(publisherName: TName, message: ClientInferPublisherInput<TContract, TName>, options?: Options.Publish): Future<Result<void, TechnicalError | MessageValidationError>>;
113
+ publish<TName extends InferPublisherNames<TContract>>(publisherName: TName, message: ClientInferPublisherInput<TContract, TName>, options?: PublishOptions): Future<Result<void, TechnicalError | MessageValidationError>>;
93
114
  /**
94
115
  * Close the channel and connection
95
116
  */
@@ -97,5 +118,5 @@ declare class TypedAmqpClient<TContract extends ContractDefinition> {
97
118
  private waitForConnectionReady;
98
119
  }
99
120
  //#endregion
100
- export { type ClientInferPublisherInput, type CreateClientOptions, MessageValidationError, TechnicalError, TypedAmqpClient };
121
+ export { type ClientInferPublisherInput, type CreateClientOptions, MessageValidationError, type PublishOptions, TechnicalError, TypedAmqpClient };
101
122
  //# 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,KEvBD,mBFuBwB,CAAA,kBEvBc,kBFuBK,CAAA,GAAA;YEtB3C;QACJ;sBACc;EDJjB,MAAA,CAAA,ECKM,MDLN,GAAA,SAAgB;CAAiB;;;;AAMjC,cCKQ,eDLW,CAAA,kBCKuB,kBDLvB,CAAA,CAAA;EAAoB,iBAAA,QAAA;EAC1C,iBAAA,UAAA;EADiE,iBAAA,MAAA;EAAgB,QAAA,WAAA,CAAA;EAO9E;;;;;AAAmE;;;;;EAQpE,OAAA,MAAA,CAAA,kBCO8B,kBDP9B,CAAA,CAAA;IAAA,QAAA;IAAA,IAAA;IAAA,iBAAA;IAAA;EAAA,CAAA,ECYC,mBDZD,CCYqB,SDZrB,CAAA,CAAA,ECYkC,MDZlC,CCYyC,MDZzC,CCYgD,eDZhD,CCYgE,SDZhE,CAAA,ECY4E,cDZ5E,CAAA,CAAA;EAA2B;;AAK/B;;EAEoC,OAAA,CAAA,cCmBZ,mBDnBY,CCmBQ,SDnBR,CAAA,CAAA,CAAA,aAAA,ECoBjB,KDpBiB,EAAA,OAAA,ECqBvB,yBDrBuB,CCqBG,SDrBH,ECqBc,KDrBd,CAAA,EAAA,OAAA,CAAA,ECsBtB,OAAA,CAAQ,ODtBc,CAAA,ECuB/B,MDvB+B,CCuBxB,MDvBwB,CAAA,IAAA,ECuBX,cDvBW,GCuBM,sBDvBN,CAAA,CAAA;EAApB;;;EACQ,KAAA,CAAA,CAAA,EC0Fb,MD1Fa,CC0FN,MD1FM,CAAA,IAAA,EC0FO,cD1FP,CAAA,CAAA;EAApB,QAAA,sBAAA"}
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,KElBD,cAAA,GAAiB,OAAA,CAAQ,OFkBO,GAAA;;;;AC7BkB;;EAM5D,WAAA,CAAA,ECWc,oBDXd,GAAA,SAAA;CAAgB;;AAAgB;;AAMhC,KCWU,mBDXV,CAAA,kBCWgD,kBDXhD,CAAA,GAAA;EADiE,QAAA,ECavD,SDbuD;EAAgB,IAAA,ECc3E,aDd2E,EAAA;EAO9E,iBAAA,CAAe,ECQE,4BDRF,GAAA,SAAA;EAAmB,MAAA,CAAA,ECS5B,MDT4B,GAAA,SAAA;CAAkC;;;AAAD;AAMpD,cCSP,eDTO,CAAA,kBCS2B,kBDT3B,CAAA,CAAA;EACgB,iBAAA,QAAA;EAApB,iBAAA,UAAA;EACI,iBAAA,MAAA;EAAhB,QAAA,WAAA,CAAA;EAA2B;;AAK/B;;;;;;;;EAGuB,OAAA,MAAA,CAAA,kBCgBW,kBDhBX,CAAA,CAAA;IAAA,QAAA;IAAA,IAAA;IAAA,iBAAA;IAAA;EAAA,CAAA,ECqBlB,mBDrBkB,CCqBE,SDrBF,CAAA,CAAA,ECqBe,MDrBf,CCqBsB,MDrBtB,CCqB6B,eDrB7B,CCqB6C,SDrB7C,CAAA,ECqByD,cDrBzD,CAAA,CAAA;;;;ACvBvB;AAYA;;;;;;;AAUA;;;EAkBI,OAAA,CAAA,cA4BoB,mBA5BpB,CA4BwC,SA5BxC,CAAA,CAAA,CAAA,aAAA,EA6Be,KA7Bf,EAAA,OAAA,EA8BS,yBA9BT,CA8BmC,SA9BnC,EA8B8C,KA9B9C,CAAA,EAAA,OAAA,CAAA,EA+BU,cA/BV,CAAA,EAgCC,MAhCD,CAgCQ,MAhCR,CAAA,IAAA,EAgCqB,cAhCrB,GAgCsC,sBAhCtC,CAAA,CAAA;EACA;;;EAGqB,KAAA,CAAA,CAAA,EAwHd,MAxHc,CAwHP,MAxHO,CAAA,IAAA,EAwHM,cAxHN,CAAA,CAAA;EAApB,QAAA,sBAAA"}
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Logger } from "@amqp-contract/core";
2
2
  import { Future, Result } from "@swan-io/boxed";
3
3
  import { AmqpConnectionManagerOptions, ConnectionUrl } from "amqp-connection-manager";
4
- import { ContractDefinition, InferPublisherNames, PublisherDefinition } from "@amqp-contract/contract";
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
 
@@ -52,6 +52,17 @@ type InferPublisher<TContract extends ContractDefinition, TName extends InferPub
52
52
  type ClientInferPublisherInput<TContract extends ContractDefinition, TName extends InferPublisherNames<TContract>> = PublisherInferInput<InferPublisher<TContract, TName>>;
53
53
  //#endregion
54
54
  //#region src/client.d.ts
55
+ /**
56
+ * Publish options that extend amqplib's Options.Publish with optional compression support.
57
+ */
58
+ type PublishOptions = Options.Publish & {
59
+ /**
60
+ * Optional compression algorithm to use for the message payload.
61
+ * When specified, the message will be compressed using the chosen algorithm
62
+ * and the contentEncoding header will be set automatically.
63
+ */
64
+ compression?: CompressionAlgorithm | undefined;
65
+ };
55
66
  /**
56
67
  * Options for creating a client
57
68
  */
@@ -87,9 +98,19 @@ declare class TypedAmqpClient<TContract extends ContractDefinition> {
87
98
  }: CreateClientOptions<TContract>): Future<Result<TypedAmqpClient<TContract>, TechnicalError>>;
88
99
  /**
89
100
  * Publish a message using a defined publisher
90
- * Returns Result.Ok(true) on success, or Result.Error with specific error on failure
101
+ *
102
+ * @param publisherName - The name of the publisher to use
103
+ * @param message - The message to publish
104
+ * @param options - Optional publish options including compression, headers, priority, etc.
105
+ *
106
+ * @remarks
107
+ * If `options.compression` is specified, the message will be compressed before publishing
108
+ * and the `contentEncoding` property will be set automatically. Any `contentEncoding`
109
+ * value already in options will be overwritten by the compression algorithm.
110
+ *
111
+ * @returns Result.Ok(void) on success, or Result.Error with specific error on failure
91
112
  */
92
- publish<TName extends InferPublisherNames<TContract>>(publisherName: TName, message: ClientInferPublisherInput<TContract, TName>, options?: Options.Publish): Future<Result<void, TechnicalError | MessageValidationError>>;
113
+ publish<TName extends InferPublisherNames<TContract>>(publisherName: TName, message: ClientInferPublisherInput<TContract, TName>, options?: PublishOptions): Future<Result<void, TechnicalError | MessageValidationError>>;
93
114
  /**
94
115
  * Close the channel and connection
95
116
  */
@@ -97,5 +118,5 @@ declare class TypedAmqpClient<TContract extends ContractDefinition> {
97
118
  private waitForConnectionReady;
98
119
  }
99
120
  //#endregion
100
- export { type ClientInferPublisherInput, type CreateClientOptions, MessageValidationError, TechnicalError, TypedAmqpClient };
121
+ export { type ClientInferPublisherInput, type CreateClientOptions, MessageValidationError, type PublishOptions, TechnicalError, TypedAmqpClient };
101
122
  //# 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,KEvBD,mBFuBwB,CAAA,kBEvBc,kBFuBK,CAAA,GAAA;YEtB3C;QACJ;sBACc;EDJjB,MAAA,CAAA,ECKM,MDLN,GAAA,SAAgB;CAAiB;;;;AAMjC,cCKQ,eDLW,CAAA,kBCKuB,kBDLvB,CAAA,CAAA;EAAoB,iBAAA,QAAA;EAC1C,iBAAA,UAAA;EADiE,iBAAA,MAAA;EAAgB,QAAA,WAAA,CAAA;EAO9E;;;;;AAAmE;;;;;EAQpE,OAAA,MAAA,CAAA,kBCO8B,kBDP9B,CAAA,CAAA;IAAA,QAAA;IAAA,IAAA;IAAA,iBAAA;IAAA;EAAA,CAAA,ECYC,mBDZD,CCYqB,SDZrB,CAAA,CAAA,ECYkC,MDZlC,CCYyC,MDZzC,CCYgD,eDZhD,CCYgE,SDZhE,CAAA,ECY4E,cDZ5E,CAAA,CAAA;EAA2B;;AAK/B;;EAEoC,OAAA,CAAA,cCmBZ,mBDnBY,CCmBQ,SDnBR,CAAA,CAAA,CAAA,aAAA,ECoBjB,KDpBiB,EAAA,OAAA,ECqBvB,yBDrBuB,CCqBG,SDrBH,ECqBc,KDrBd,CAAA,EAAA,OAAA,CAAA,ECsBtB,OAAA,CAAQ,ODtBc,CAAA,ECuB/B,MDvB+B,CCuBxB,MDvBwB,CAAA,IAAA,ECuBX,cDvBW,GCuBM,sBDvBN,CAAA,CAAA;EAApB;;;EACQ,KAAA,CAAA,CAAA,EC0Fb,MD1Fa,CC0FN,MD1FM,CAAA,IAAA,EC0FO,cD1FP,CAAA,CAAA;EAApB,QAAA,sBAAA"}
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,KElBD,cAAA,GAAiB,OAAA,CAAQ,OFkBO,GAAA;;;;AC7BkB;;EAM5D,WAAA,CAAA,ECWc,oBDXd,GAAA,SAAA;CAAgB;;AAAgB;;AAMhC,KCWU,mBDXV,CAAA,kBCWgD,kBDXhD,CAAA,GAAA;EADiE,QAAA,ECavD,SDbuD;EAAgB,IAAA,ECc3E,aDd2E,EAAA;EAO9E,iBAAA,CAAe,ECQE,4BDRF,GAAA,SAAA;EAAmB,MAAA,CAAA,ECS5B,MDT4B,GAAA,SAAA;CAAkC;;;AAAD;AAMpD,cCSP,eDTO,CAAA,kBCS2B,kBDT3B,CAAA,CAAA;EACgB,iBAAA,QAAA;EAApB,iBAAA,UAAA;EACI,iBAAA,MAAA;EAAhB,QAAA,WAAA,CAAA;EAA2B;;AAK/B;;;;;;;;EAGuB,OAAA,MAAA,CAAA,kBCgBW,kBDhBX,CAAA,CAAA;IAAA,QAAA;IAAA,IAAA;IAAA,iBAAA;IAAA;EAAA,CAAA,ECqBlB,mBDrBkB,CCqBE,SDrBF,CAAA,CAAA,ECqBe,MDrBf,CCqBsB,MDrBtB,CCqB6B,eDrB7B,CCqB6C,SDrB7C,CAAA,ECqByD,cDrBzD,CAAA,CAAA;;;;ACvBvB;AAYA;;;;;;;AAUA;;;EAkBI,OAAA,CAAA,cA4BoB,mBA5BpB,CA4BwC,SA5BxC,CAAA,CAAA,CAAA,aAAA,EA6Be,KA7Bf,EAAA,OAAA,EA8BS,yBA9BT,CA8BmC,SA9BnC,EA8B8C,KA9B9C,CAAA,EAAA,OAAA,CAAA,EA+BU,cA/BV,CAAA,EAgCC,MAhCD,CAgCQ,MAhCR,CAAA,IAAA,EAgCqB,cAhCrB,GAgCsC,sBAhCtC,CAAA,CAAA;EACA;;;EAGqB,KAAA,CAAA,CAAA,EAwHd,MAxHc,CAwHP,MAxHO,CAAA,IAAA,EAwHM,cAxHN,CAAA,CAAA;EAApB,QAAA,sBAAA"}
package/dist/index.mjs CHANGED
@@ -1,5 +1,8 @@
1
1
  import { AmqpClient } from "@amqp-contract/core";
2
2
  import { Future, Result } from "@swan-io/boxed";
3
+ import { deflate, gzip } from "node:zlib";
4
+ import { match } from "ts-pattern";
5
+ import { promisify } from "node:util";
3
6
 
4
7
  //#region src/errors.ts
5
8
  /**
@@ -36,6 +39,24 @@ var MessageValidationError = class extends ClientError {
36
39
  }
37
40
  };
38
41
 
42
+ //#endregion
43
+ //#region src/compression.ts
44
+ const gzipAsync = promisify(gzip);
45
+ const deflateAsync = promisify(deflate);
46
+ /**
47
+ * Compress a buffer using the specified compression algorithm.
48
+ *
49
+ * @param buffer - The buffer to compress
50
+ * @param algorithm - The compression algorithm to use
51
+ * @returns A promise that resolves to the compressed buffer
52
+ * @throws Error if compression fails
53
+ *
54
+ * @internal
55
+ */
56
+ async function compressBuffer(buffer, algorithm) {
57
+ return match(algorithm).with("gzip", () => gzipAsync(buffer)).with("deflate", () => deflateAsync(buffer)).exhaustive();
58
+ }
59
+
39
60
  //#endregion
40
61
  //#region src/client.ts
41
62
  /**
@@ -66,7 +87,17 @@ var TypedAmqpClient = class TypedAmqpClient {
66
87
  }
67
88
  /**
68
89
  * Publish a message using a defined publisher
69
- * Returns Result.Ok(true) on success, or Result.Error with specific error on failure
90
+ *
91
+ * @param publisherName - The name of the publisher to use
92
+ * @param message - The message to publish
93
+ * @param options - Optional publish options including compression, headers, priority, etc.
94
+ *
95
+ * @remarks
96
+ * If `options.compression` is specified, the message will be compressed before publishing
97
+ * and the `contentEncoding` property will be set automatically. Any `contentEncoding`
98
+ * value already in options will be overwritten by the compression algorithm.
99
+ *
100
+ * @returns Result.Ok(void) on success, or Result.Error with specific error on failure
70
101
  */
71
102
  publish(publisherName, message, options) {
72
103
  const publishers = this.contract.publishers;
@@ -81,15 +112,26 @@ var TypedAmqpClient = class TypedAmqpClient {
81
112
  });
82
113
  };
83
114
  const publishMessage = (validatedMessage) => {
84
- return Future.fromPromise(this.amqpClient.channel.publish(publisher.exchange.name, publisher.routingKey ?? "", validatedMessage, options)).mapError((error) => new TechnicalError(`Failed to publish message`, error)).mapOkToResult((published) => {
115
+ const { compression, ...restOptions } = options ?? {};
116
+ const publishOptions = { ...restOptions };
117
+ const preparePayload = () => {
118
+ if (compression) {
119
+ const messageBuffer = Buffer.from(JSON.stringify(validatedMessage));
120
+ publishOptions.contentEncoding = compression;
121
+ return Future.fromPromise(compressBuffer(messageBuffer, compression)).mapError((error) => new TechnicalError(`Failed to compress message`, error)).map((compressedBuffer) => Result.Ok(compressedBuffer));
122
+ }
123
+ return Future.value(Result.Ok(validatedMessage));
124
+ };
125
+ 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) => {
85
126
  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)`));
86
127
  this.logger?.info("Message published successfully", {
87
128
  publisherName: String(publisherName),
88
129
  exchange: publisher.exchange.name,
89
- routingKey: publisher.routingKey
130
+ routingKey: publisher.routingKey,
131
+ compressed: !!compression
90
132
  });
91
133
  return Result.Ok(void 0);
92
- });
134
+ }));
93
135
  };
94
136
  return validateMessage().flatMapOk((validatedMessage) => publishMessage(validatedMessage));
95
137
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["cause?: unknown","publisherName: string","issues: unknown","contract: TContract","amqpClient: AmqpClient","logger?: Logger"],"sources":["../src/errors.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 { AmqpClient, type Logger } from \"@amqp-contract/core\";\nimport type { AmqpConnectionManagerOptions, ConnectionUrl } from \"amqp-connection-manager\";\nimport type { ContractDefinition, InferPublisherNames } 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\";\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\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 ) {}\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 }: CreateClientOptions<TContract>): Future<Result<TypedAmqpClient<TContract>, TechnicalError>> {\n const client = new TypedAmqpClient(\n contract,\n new AmqpClient(contract, { urls, connectionOptions }),\n logger,\n );\n\n return client.waitForConnectionReady().mapOk(() => client);\n }\n\n /**\n * Publish a message using a defined publisher\n * Returns Result.Ok(true) 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?: Options.Publish,\n ): Future<Result<void, TechnicalError | MessageValidationError>> {\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 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 return Future.fromPromise(\n this.amqpClient.channel.publish(\n publisher.exchange.name,\n publisher.routingKey ?? \"\",\n validatedMessage,\n options,\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 });\n\n return Result.Ok(undefined);\n });\n };\n\n // Validate message using schema\n return validateMessage().flatMapOk((validatedMessage) => publishMessage(validatedMessage));\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":";;;;;;;AAGA,IAAe,cAAf,cAAmC,MAAM;CACvC,AAAU,YAAY,SAAiB;AACrC,QAAM,QAAQ;AACd,OAAK,OAAO;EAEZ,MAAM,mBAAmB;AAGzB,MAAI,OAAO,iBAAiB,sBAAsB,WAChD,kBAAiB,kBAAkB,MAAM,KAAK,YAAY;;;;;;;AAShE,IAAa,iBAAb,cAAoC,YAAY;CAC9C,YACE,SACA,AAAyBA,OACzB;AACA,QAAM,QAAQ;EAFW;AAGzB,OAAK,OAAO;;;;;;AAOhB,IAAa,yBAAb,cAA4C,YAAY;CACtD,YACE,AAAgBC,eAChB,AAAgBC,QAChB;AACA,QAAM,4CAA4C,cAAc,GAAG;EAHnD;EACA;AAGhB,OAAK,OAAO;;;;;;;;;ACnBhB,IAAa,kBAAb,MAAa,gBAAsD;CACjE,AAAQ,YACN,AAAiBC,UACjB,AAAiBC,YACjB,AAAiBC,QACjB;EAHiB;EACA;EACA;;;;;;;;;;;;CAanB,OAAO,OAA6C,EAClD,UACA,MACA,mBACA,UAC6F;EAC7F,MAAM,SAAS,IAAI,gBACjB,UACA,IAAI,WAAW,UAAU;GAAE;GAAM;GAAmB,CAAC,EACrD,OACD;AAED,SAAO,OAAO,wBAAwB,CAAC,YAAY,OAAO;;;;;;CAO5D,QACE,eACA,SACA,SAC+D;EAC/D,MAAM,aAAa,KAAK,SAAS;AACjC,MAAI,CAAC,WACH,QAAO,OAAO,MAAM,OAAO,MAAM,IAAI,eAAe,oCAAoC,CAAC,CAAC;EAG5F,MAAM,YAAY,WAAW;AAC7B,MAAI,CAAC,UACH,QAAO,OAAO,MACZ,OAAO,MACL,IAAI,eAAe,cAAc,OAAO,cAAc,CAAC,yBAAyB,CACjF,CACF;EAGH,MAAM,wBAAwB;GAC5B,MAAM,mBAAmB,UAAU,QAAQ,QAAQ,aAAa,SAAS,QAAQ;AACjF,UAAO,OAAO,YACZ,4BAA4B,UAAU,mBAAmB,QAAQ,QAAQ,iBAAiB,CAC3F,CACE,UAAU,UAAU,IAAI,eAAe,qBAAqB,MAAM,CAAC,CACnE,eAAe,eAAe;AAC7B,QAAI,WAAW,OACb,QAAO,OAAO,MACZ,IAAI,uBAAuB,OAAO,cAAc,EAAE,WAAW,OAAO,CACrE;AAGH,WAAO,OAAO,GAAG,WAAW,MAAM;KAClC;;EAGN,MAAM,kBAAkB,qBAAoE;AAC1F,UAAO,OAAO,YACZ,KAAK,WAAW,QAAQ,QACtB,UAAU,SAAS,MACnB,UAAU,cAAc,IACxB,kBACA,QACD,CACF,CACE,UAAU,UAAU,IAAI,eAAe,6BAA6B,MAAM,CAAC,CAC3E,eAAe,cAAc;AAC5B,QAAI,CAAC,UACH,QAAO,OAAO,MACZ,IAAI,eACF,4CAA4C,OAAO,cAAc,CAAC,sEACnE,CACF;AAGH,SAAK,QAAQ,KAAK,kCAAkC;KAClD,eAAe,OAAO,cAAc;KACpC,UAAU,UAAU,SAAS;KAC7B,YAAY,UAAU;KACvB,CAAC;AAEF,WAAO,OAAO,GAAG,OAAU;KAC3B;;AAIN,SAAO,iBAAiB,CAAC,WAAW,qBAAqB,eAAe,iBAAiB,CAAC;;;;;CAM5F,QAA8C;AAC5C,SAAO,OAAO,YAAY,KAAK,WAAW,OAAO,CAAC,CAC/C,UAAU,UAAU,IAAI,eAAe,mCAAmC,MAAM,CAAC,CACjF,YAAY,OAAU;;CAG3B,AAAQ,yBAA+D;AACrE,SAAO,OAAO,YAAY,KAAK,WAAW,QAAQ,gBAAgB,CAAC,CAAC,UACjE,UAAU,IAAI,eAAe,uCAAuC,MAAM,CAC5E"}
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 { AmqpClient, type Logger } 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\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 ) {}\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 }: CreateClientOptions<TContract>): Future<Result<TypedAmqpClient<TContract>, TechnicalError>> {\n const client = new TypedAmqpClient(\n contract,\n new AmqpClient(contract, { urls, connectionOptions }),\n logger,\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 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 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().flatMapOk((validatedMessage) => publishMessage(validatedMessage));\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":";;;;;;;;;;AAGA,IAAe,cAAf,cAAmC,MAAM;CACvC,AAAU,YAAY,SAAiB;AACrC,QAAM,QAAQ;AACd,OAAK,OAAO;EAEZ,MAAM,mBAAmB;AAGzB,MAAI,OAAO,iBAAiB,sBAAsB,WAChD,kBAAiB,kBAAkB,MAAM,KAAK,YAAY;;;;;;;AAShE,IAAa,iBAAb,cAAoC,YAAY;CAC9C,YACE,SACA,AAAyB,OACzB;AACA,QAAM,QAAQ;EAFW;AAGzB,OAAK,OAAO;;;;;;AAOhB,IAAa,yBAAb,cAA4C,YAAY;CACtD,YACE,AAAgB,eAChB,AAAgB,QAChB;AACA,QAAM,4CAA4C,cAAc,GAAG;EAHnD;EACA;AAGhB,OAAK,OAAO;;;;;;ACnChB,MAAM,YAAY,UAAU,KAAK;AACjC,MAAM,eAAe,UAAU,QAAQ;;;;;;;;;;;AAYvC,eAAsB,eACpB,QACA,WACiB;AACjB,QAAO,MAAM,UAAU,CACpB,KAAK,cAAc,UAAU,OAAO,CAAC,CACrC,KAAK,iBAAiB,aAAa,OAAO,CAAC,CAC3C,YAAY;;;;;;;;ACajB,IAAa,kBAAb,MAAa,gBAAsD;CACjE,AAAQ,YACN,AAAiB,UACjB,AAAiB,YACjB,AAAiB,QACjB;EAHiB;EACA;EACA;;;;;;;;;;;;CAanB,OAAO,OAA6C,EAClD,UACA,MACA,mBACA,UAC6F;EAC7F,MAAM,SAAS,IAAI,gBACjB,UACA,IAAI,WAAW,UAAU;GAAE;GAAM;GAAmB,CAAC,EACrD,OACD;AAED,SAAO,OAAO,wBAAwB,CAAC,YAAY,OAAO;;;;;;;;;;;;;;;;CAiB5D,QACE,eACA,SACA,SAC+D;EAC/D,MAAM,aAAa,KAAK,SAAS;AACjC,MAAI,CAAC,WACH,QAAO,OAAO,MAAM,OAAO,MAAM,IAAI,eAAe,oCAAoC,CAAC,CAAC;EAG5F,MAAM,YAAY,WAAW;AAC7B,MAAI,CAAC,UACH,QAAO,OAAO,MACZ,OAAO,MACL,IAAI,eAAe,cAAc,OAAO,cAAc,CAAC,yBAAyB,CACjF,CACF;EAGH,MAAM,wBAAwB;GAC5B,MAAM,mBAAmB,UAAU,QAAQ,QAAQ,aAAa,SAAS,QAAQ;AACjF,UAAO,OAAO,YACZ,4BAA4B,UAAU,mBAAmB,QAAQ,QAAQ,iBAAiB,CAC3F,CACE,UAAU,UAAU,IAAI,eAAe,qBAAqB,MAAM,CAAC,CACnE,eAAe,eAAe;AAC7B,QAAI,WAAW,OACb,QAAO,OAAO,MACZ,IAAI,uBAAuB,OAAO,cAAc,EAAE,WAAW,OAAO,CACrE;AAGH,WAAO,OAAO,GAAG,WAAW,MAAM;KAClC;;EAGN,MAAM,kBAAkB,qBAAoE;GAE1F,MAAM,EAAE,aAAa,GAAG,gBAAgB,WAAW,EAAE;GACrD,MAAM,iBAAkC,EAAE,GAAG,aAAa;GAG1D,MAAM,uBAAyE;AAC7E,QAAI,aAAa;KAEf,MAAM,gBAAgB,OAAO,KAAK,KAAK,UAAU,iBAAiB,CAAC;AACnE,oBAAe,kBAAkB;AAEjC,YAAO,OAAO,YAAY,eAAe,eAAe,YAAY,CAAC,CAClE,UAAU,UAAU,IAAI,eAAe,8BAA8B,MAAM,CAAC,CAC5E,KAAK,qBAAqB,OAAO,GAAG,iBAAiB,CAAC;;AAI3D,WAAO,OAAO,MAAM,OAAO,GAAG,iBAAiB,CAAC;;AAIlD,UAAO,gBAAgB,CAAC,WAAW,YACjC,OAAO,YACL,KAAK,WAAW,QAAQ,QACtB,UAAU,SAAS,MACnB,UAAU,cAAc,IACxB,SACA,eACD,CACF,CACE,UAAU,UAAU,IAAI,eAAe,6BAA6B,MAAM,CAAC,CAC3E,eAAe,cAAc;AAC5B,QAAI,CAAC,UACH,QAAO,OAAO,MACZ,IAAI,eACF,4CAA4C,OAAO,cAAc,CAAC,sEACnE,CACF;AAGH,SAAK,QAAQ,KAAK,kCAAkC;KAClD,eAAe,OAAO,cAAc;KACpC,UAAU,UAAU,SAAS;KAC7B,YAAY,UAAU;KACtB,YAAY,CAAC,CAAC;KACf,CAAC;AAEF,WAAO,OAAO,GAAG,OAAU;KAC3B,CACL;;AAIH,SAAO,iBAAiB,CAAC,WAAW,qBAAqB,eAAe,iBAAiB,CAAC;;;;;CAM5F,QAA8C;AAC5C,SAAO,OAAO,YAAY,KAAK,WAAW,OAAO,CAAC,CAC/C,UAAU,UAAU,IAAI,eAAe,mCAAmC,MAAM,CAAC,CACjF,YAAY,OAAU;;CAG3B,AAAQ,yBAA+D;AACrE,SAAO,OAAO,YAAY,KAAK,WAAW,QAAQ,gBAAgB,CAAC,CAAC,UACjE,UAAU,IAAI,eAAe,uCAAuC,MAAM,CAC5E"}
package/docs/index.md CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  ### MessageValidationError
10
10
 
11
- Defined in: [packages/client/src/errors.ts:35](https://github.com/btravers/amqp-contract/blob/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/errors.ts#L35)
11
+ Defined in: [packages/client/src/errors.ts:35](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/errors.ts#L35)
12
12
 
13
13
  Error thrown when message validation fails
14
14
 
@@ -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/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/errors.ts#L36)
27
+ Defined in: [packages/client/src/errors.ts:36](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/errors.ts#L36)
28
28
 
29
29
  ###### Parameters
30
30
 
@@ -48,12 +48,12 @@ ClientError.constructor
48
48
  | Property | Modifier | Type | Description | Inherited from | Defined in |
49
49
  | ------ | ------ | ------ | ------ | ------ | ------ |
50
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/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/errors.ts#L38) |
51
+ | <a id="issues"></a> `issues` | `readonly` | `unknown` | - | - | [packages/client/src/errors.ts:38](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/errors.ts#L38) |
52
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
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/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/errors.ts#L37) |
54
+ | <a id="publishername"></a> `publisherName` | `readonly` | `string` | - | - | [packages/client/src/errors.ts:37](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/errors.ts#L37) |
55
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.3/node\_modules/@types/node/globals.d.ts:67 |
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 |
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.3/node\_modules/@types/node/globals.d.ts:51
66
+ Defined in: node\_modules/.pnpm/@types+node@25.0.5/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
@@ -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.3/node\_modules/@types/node/globals.d.ts:55
135
+ Defined in: node\_modules/.pnpm/@types+node@25.0.5/node\_modules/@types/node/globals.d.ts:55
136
136
 
137
137
  ###### Parameters
138
138
 
@@ -159,7 +159,7 @@ ClientError.prepareStackTrace
159
159
 
160
160
  ### TechnicalError
161
161
 
162
- Defined in: [packages/client/src/errors.ts:22](https://github.com/btravers/amqp-contract/blob/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/errors.ts#L22)
162
+ Defined in: [packages/client/src/errors.ts:22](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/errors.ts#L22)
163
163
 
164
164
  Error for technical/runtime failures that cannot be prevented by TypeScript
165
165
  This includes validation failures and AMQP channel issues
@@ -176,7 +176,7 @@ This includes validation failures and AMQP channel issues
176
176
  new TechnicalError(message, cause?): TechnicalError;
177
177
  ```
178
178
 
179
- Defined in: [packages/client/src/errors.ts:23](https://github.com/btravers/amqp-contract/blob/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/errors.ts#L23)
179
+ Defined in: [packages/client/src/errors.ts:23](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/errors.ts#L23)
180
180
 
181
181
  ###### Parameters
182
182
 
@@ -199,11 +199,11 @@ ClientError.constructor
199
199
 
200
200
  | Property | Modifier | Type | Description | Inherited from | Defined in |
201
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/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/errors.ts#L25) |
202
+ | <a id="cause-1"></a> `cause?` | `readonly` | `unknown` | - | `ClientError.cause` | [packages/client/src/errors.ts:25](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/errors.ts#L25) |
203
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
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
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.3/node\_modules/@types/node/globals.d.ts:67 |
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
207
 
208
208
  #### Methods
209
209
 
@@ -213,7 +213,7 @@ ClientError.constructor
213
213
  static captureStackTrace(targetObject, constructorOpt?): void;
214
214
  ```
215
215
 
216
- Defined in: node\_modules/.pnpm/@types+node@25.0.3/node\_modules/@types/node/globals.d.ts:51
216
+ Defined in: node\_modules/.pnpm/@types+node@25.0.5/node\_modules/@types/node/globals.d.ts:51
217
217
 
218
218
  Creates a `.stack` property on `targetObject`, which when accessed returns
219
219
  a string representing the location in the code at which
@@ -282,7 +282,7 @@ ClientError.captureStackTrace
282
282
  static prepareStackTrace(err, stackTraces): any;
283
283
  ```
284
284
 
285
- Defined in: node\_modules/.pnpm/@types+node@25.0.3/node\_modules/@types/node/globals.d.ts:55
285
+ Defined in: node\_modules/.pnpm/@types+node@25.0.5/node\_modules/@types/node/globals.d.ts:55
286
286
 
287
287
  ###### Parameters
288
288
 
@@ -309,7 +309,7 @@ ClientError.prepareStackTrace
309
309
 
310
310
  ### TypedAmqpClient
311
311
 
312
- Defined in: [packages/client/src/client.ts:22](https://github.com/btravers/amqp-contract/blob/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/client.ts#L22)
312
+ Defined in: [packages/client/src/client.ts:39](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/client.ts#L39)
313
313
 
314
314
  Type-safe AMQP client for publishing messages
315
315
 
@@ -327,7 +327,7 @@ Type-safe AMQP client for publishing messages
327
327
  close(): Future<Result<void, TechnicalError>>;
328
328
  ```
329
329
 
330
- Defined in: [packages/client/src/client.ts:130](https://github.com/btravers/amqp-contract/blob/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/client.ts#L130)
330
+ Defined in: [packages/client/src/client.ts:181](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/client.ts#L181)
331
331
 
332
332
  Close the channel and connection
333
333
 
@@ -346,10 +346,9 @@ publish<TName>(
346
346
  | MessageValidationError>>;
347
347
  ```
348
348
 
349
- Defined in: [packages/client/src/client.ts:58](https://github.com/btravers/amqp-contract/blob/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/client.ts#L58)
349
+ Defined in: [packages/client/src/client.ts:85](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/client.ts#L85)
350
350
 
351
351
  Publish a message using a defined publisher
352
- Returns Result.Ok(true) on success, or Result.Error with specific error on failure
353
352
 
354
353
  ###### Type Parameters
355
354
 
@@ -359,11 +358,11 @@ Returns Result.Ok(true) on success, or Result.Error with specific error on failu
359
358
 
360
359
  ###### Parameters
361
360
 
362
- | Parameter | Type |
363
- | ------ | ------ |
364
- | `publisherName` | `TName` |
365
- | `message` | [`ClientInferPublisherInput`](#clientinferpublisherinput)\<`TContract`, `TName`\> |
366
- | `options?` | `Publish` |
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. |
367
366
 
368
367
  ###### Returns
369
368
 
@@ -371,13 +370,21 @@ Returns Result.Ok(true) on success, or Result.Error with specific error on failu
371
370
  \| [`TechnicalError`](#technicalerror)
372
371
  \| [`MessageValidationError`](#messagevalidationerror)\>\>
373
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.
380
+
374
381
  ##### create()
375
382
 
376
383
  ```ts
377
384
  static create<TContract>(__namedParameters): Future<Result<TypedAmqpClient<TContract>, TechnicalError>>;
378
385
  ```
379
386
 
380
- Defined in: [packages/client/src/client.ts:39](https://github.com/btravers/amqp-contract/blob/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/client.ts#L39)
387
+ Defined in: [packages/client/src/client.ts:56](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/client.ts#L56)
381
388
 
382
389
  Create a type-safe AMQP client from a contract.
383
390
 
@@ -412,7 +419,7 @@ connection options, following RabbitMQ best practices.
412
419
  type ClientInferPublisherInput<TContract, TName> = PublisherInferInput<InferPublisher<TContract, TName>>;
413
420
  ```
414
421
 
415
- Defined in: [packages/client/src/types.ts:37](https://github.com/btravers/amqp-contract/blob/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/types.ts#L37)
422
+ Defined in: [packages/client/src/types.ts:37](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/types.ts#L37)
416
423
 
417
424
  Infer publisher input type (message payload) for a specific publisher in a contract
418
425
 
@@ -431,7 +438,7 @@ Infer publisher input type (message payload) for a specific publisher in a contr
431
438
  type CreateClientOptions<TContract> = object;
432
439
  ```
433
440
 
434
- Defined in: [packages/client/src/client.ts:12](https://github.com/btravers/amqp-contract/blob/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/client.ts#L12)
441
+ Defined in: [packages/client/src/client.ts:29](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/client.ts#L29)
435
442
 
436
443
  Options for creating a client
437
444
 
@@ -445,7 +452,25 @@ Options for creating a client
445
452
 
446
453
  | Property | Type | Defined in |
447
454
  | ------ | ------ | ------ |
448
- | <a id="connectionoptions"></a> `connectionOptions?` | `AmqpConnectionManagerOptions` | [packages/client/src/client.ts:15](https://github.com/btravers/amqp-contract/blob/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/client.ts#L15) |
449
- | <a id="contract"></a> `contract` | `TContract` | [packages/client/src/client.ts:13](https://github.com/btravers/amqp-contract/blob/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/client.ts#L13) |
450
- | <a id="logger"></a> `logger?` | `Logger` | [packages/client/src/client.ts:16](https://github.com/btravers/amqp-contract/blob/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/client.ts#L16) |
451
- | <a id="urls"></a> `urls` | `ConnectionUrl`[] | [packages/client/src/client.ts:14](https://github.com/btravers/amqp-contract/blob/8711ad20abb1d4e537ec473d43e85fac3ebd4d0b/packages/client/src/client.ts#L14) |
455
+ | <a id="connectionoptions"></a> `connectionOptions?` | `AmqpConnectionManagerOptions` | [packages/client/src/client.ts:32](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/client.ts#L32) |
456
+ | <a id="contract"></a> `contract` | `TContract` | [packages/client/src/client.ts:30](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/client.ts#L30) |
457
+ | <a id="logger"></a> `logger?` | `Logger` | [packages/client/src/client.ts:33](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/client.ts#L33) |
458
+ | <a id="urls"></a> `urls` | `ConnectionUrl`[] | [packages/client/src/client.ts:31](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/client.ts#L31) |
459
+
460
+ ***
461
+
462
+ ### PublishOptions
463
+
464
+ ```ts
465
+ type PublishOptions = Options.Publish & object;
466
+ ```
467
+
468
+ Defined in: [packages/client/src/client.ts:17](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/client.ts#L17)
469
+
470
+ Publish options that extend amqplib's Options.Publish with optional compression support.
471
+
472
+ #### Type Declaration
473
+
474
+ | Name | Type | Description | Defined in |
475
+ | ------ | ------ | ------ | ------ |
476
+ | `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:23](https://github.com/btravers/amqp-contract/blob/7897a0ef6745684800b11ec9bbc26bfab645f2a7/packages/client/src/client.ts#L23) |
package/package.json CHANGED
@@ -1,13 +1,21 @@
1
1
  {
2
2
  "name": "@amqp-contract/client",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Client utilities for publishing messages using amqp-contract",
5
5
  "keywords": [
6
6
  "amqp",
7
7
  "client",
8
8
  "contract",
9
9
  "rabbitmq",
10
- "typescript"
10
+ "typescript",
11
+ "nodejs",
12
+ "messaging",
13
+ "type-safe",
14
+ "schema",
15
+ "validation",
16
+ "message-broker",
17
+ "message-queue",
18
+ "publisher"
11
19
  ],
12
20
  "homepage": "https://github.com/btravers/amqp-contract#readme",
13
21
  "bugs": {
@@ -44,32 +52,32 @@
44
52
  "dependencies": {
45
53
  "@standard-schema/spec": "1.1.0",
46
54
  "@swan-io/boxed": "3.2.1",
47
- "@amqp-contract/contract": "0.6.0",
48
- "@amqp-contract/core": "0.6.0"
55
+ "ts-pattern": "5.9.0",
56
+ "@amqp-contract/contract": "0.8.0",
57
+ "@amqp-contract/core": "0.8.0"
49
58
  },
50
59
  "devDependencies": {
51
60
  "@types/amqplib": "0.10.8",
52
- "@types/node": "25.0.3",
61
+ "@types/node": "25.0.5",
53
62
  "@vitest/coverage-v8": "4.0.16",
54
63
  "amqp-connection-manager": "5.0.0",
55
64
  "amqplib": "0.10.9",
56
- "tsdown": "0.18.3",
65
+ "tsdown": "0.19.0",
57
66
  "typedoc": "0.28.15",
58
67
  "typedoc-plugin-markdown": "4.9.0",
59
68
  "typescript": "5.9.3",
60
69
  "vitest": "4.0.16",
61
- "zod": "4.2.1",
62
- "@amqp-contract/testing": "0.6.0",
63
- "@amqp-contract/tsconfig": "0.0.0",
64
- "@amqp-contract/typedoc": "0.0.1"
70
+ "zod": "4.3.5",
71
+ "@amqp-contract/testing": "0.8.0",
72
+ "@amqp-contract/tsconfig": "0.1.0",
73
+ "@amqp-contract/typedoc": "0.1.0"
65
74
  },
66
75
  "scripts": {
67
76
  "build": "tsdown src/index.ts --format cjs,esm --dts --clean",
68
77
  "build:docs": "typedoc",
69
78
  "dev": "tsdown src/index.ts --format cjs,esm --dts --watch",
70
- "test": "vitest run --project integration",
79
+ "test": "vitest run --project unit",
71
80
  "test:integration": "vitest run --project integration",
72
- "test:watch": "vitest --project integration",
73
81
  "typecheck": "tsc --noEmit"
74
82
  }
75
83
  }