@amqp-contract/core 0.2.0 → 0.3.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 +16 -2
- package/dist/index.cjs +69 -27
- package/dist/index.d.cts +16 -12
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +16 -12
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +42 -27
- package/dist/index.mjs.map +1 -1
- package/package.json +4 -6
package/README.md
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
# @amqp-contract/core
|
|
2
2
|
|
|
3
|
-
Core utilities for AMQP setup and management in amqp-contract
|
|
3
|
+
**Core utilities for AMQP setup and management in amqp-contract.**
|
|
4
|
+
|
|
5
|
+
[](https://github.com/btravers/amqp-contract/actions/workflows/ci.yml)
|
|
6
|
+
[](https://www.npmjs.com/package/@amqp-contract/core)
|
|
7
|
+
[](https://www.npmjs.com/package/@amqp-contract/core)
|
|
8
|
+
[](https://www.typescriptlang.org/)
|
|
9
|
+
[](https://opensource.org/licenses/MIT)
|
|
10
|
+
|
|
11
|
+
This package provides centralized functionality for establishing AMQP topology (exchanges, queues, and bindings) from contract definitions.
|
|
12
|
+
|
|
13
|
+
📖 **[Full documentation →](https://btravers.github.io/amqp-contract)**
|
|
4
14
|
|
|
5
15
|
## Installation
|
|
6
16
|
|
|
@@ -85,6 +95,10 @@ A Promise that resolves when all resources are created.
|
|
|
85
95
|
- [@amqp-contract/client](../client) - Type-safe AMQP client
|
|
86
96
|
- [@amqp-contract/worker](../worker) - Type-safe AMQP worker
|
|
87
97
|
|
|
98
|
+
## Documentation
|
|
99
|
+
|
|
100
|
+
📖 **[Read the full documentation →](https://btravers.github.io/amqp-contract)**
|
|
101
|
+
|
|
88
102
|
## License
|
|
89
103
|
|
|
90
|
-
MIT
|
|
104
|
+
MIT
|
package/dist/index.cjs
CHANGED
|
@@ -1,30 +1,72 @@
|
|
|
1
|
+
//#region rolldown:runtime
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
10
|
+
for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
11
|
+
key = keys[i];
|
|
12
|
+
if (!__hasOwnProp.call(to, key) && key !== except) {
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: ((k) => from[k]).bind(null, key),
|
|
15
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
return to;
|
|
21
|
+
};
|
|
22
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", {
|
|
23
|
+
value: mod,
|
|
24
|
+
enumerable: true
|
|
25
|
+
}) : target, mod));
|
|
1
26
|
|
|
2
|
-
//#
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
//#endregion
|
|
28
|
+
let amqp_connection_manager = require("amqp-connection-manager");
|
|
29
|
+
amqp_connection_manager = __toESM(amqp_connection_manager);
|
|
30
|
+
|
|
31
|
+
//#region src/index.ts
|
|
32
|
+
var AmqpClient = class {
|
|
33
|
+
connection;
|
|
34
|
+
channel;
|
|
35
|
+
constructor(contract, options) {
|
|
36
|
+
this.contract = contract;
|
|
37
|
+
this.options = options;
|
|
38
|
+
this.connection = amqp_connection_manager.default.connect(this.options.urls, this.options.connectionOptions);
|
|
39
|
+
this.channel = this.connection.createChannel({
|
|
40
|
+
json: true,
|
|
41
|
+
setup: (channel) => this.setup(channel)
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
async close() {
|
|
45
|
+
await this.channel.close();
|
|
46
|
+
await this.connection.close();
|
|
47
|
+
}
|
|
48
|
+
async setup(channel) {
|
|
49
|
+
const exchangeErrors = (await Promise.allSettled(Object.values(this.contract.exchanges ?? {}).map((exchange) => channel.assertExchange(exchange.name, exchange.type, {
|
|
50
|
+
durable: exchange.durable,
|
|
51
|
+
autoDelete: exchange.autoDelete,
|
|
52
|
+
internal: exchange.internal,
|
|
53
|
+
arguments: exchange.arguments
|
|
54
|
+
})))).filter((result) => result.status === "rejected");
|
|
55
|
+
if (exchangeErrors.length > 0) throw new AggregateError(exchangeErrors.map(({ reason }) => reason), "Failed to setup exchanges");
|
|
56
|
+
const queueErrors = (await Promise.allSettled(Object.values(this.contract.queues ?? {}).map((queue) => channel.assertQueue(queue.name, {
|
|
57
|
+
durable: queue.durable,
|
|
58
|
+
exclusive: queue.exclusive,
|
|
59
|
+
autoDelete: queue.autoDelete,
|
|
60
|
+
arguments: queue.arguments
|
|
61
|
+
})))).filter((result) => result.status === "rejected");
|
|
62
|
+
if (queueErrors.length > 0) throw new AggregateError(queueErrors.map(({ reason }) => reason), "Failed to setup queues");
|
|
63
|
+
const bindingErrors = (await Promise.allSettled(Object.values(this.contract.bindings ?? {}).map((binding) => {
|
|
64
|
+
if (binding.type === "queue") return channel.bindQueue(binding.queue.name, binding.exchange.name, binding.routingKey ?? "", binding.arguments);
|
|
65
|
+
return channel.bindExchange(binding.destination.name, binding.source.name, binding.routingKey ?? "", binding.arguments);
|
|
66
|
+
}))).filter((result) => result.status === "rejected");
|
|
67
|
+
if (bindingErrors.length > 0) throw new AggregateError(bindingErrors.map(({ reason }) => reason), "Failed to setup bindings");
|
|
68
|
+
}
|
|
69
|
+
};
|
|
28
70
|
|
|
29
71
|
//#endregion
|
|
30
|
-
exports.
|
|
72
|
+
exports.AmqpClient = AmqpClient;
|
package/dist/index.d.cts
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
import { Channel } from "amqplib";
|
|
2
1
|
import { ContractDefinition } from "@amqp-contract/contract";
|
|
2
|
+
import { AmqpConnectionManagerOptions, ChannelWrapper, ConnectionUrl } from "amqp-connection-manager";
|
|
3
3
|
|
|
4
|
-
//#region src/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
//#region src/index.d.ts
|
|
5
|
+
type AmqpClientOptions = {
|
|
6
|
+
urls: ConnectionUrl[];
|
|
7
|
+
connectionOptions?: AmqpConnectionManagerOptions | undefined;
|
|
8
|
+
};
|
|
9
|
+
declare class AmqpClient {
|
|
10
|
+
private readonly contract;
|
|
11
|
+
private readonly options;
|
|
12
|
+
private readonly connection;
|
|
13
|
+
readonly channel: ChannelWrapper;
|
|
14
|
+
constructor(contract: ContractDefinition, options: AmqpClientOptions);
|
|
15
|
+
close(): Promise<void>;
|
|
16
|
+
private setup;
|
|
17
|
+
}
|
|
14
18
|
//#endregion
|
|
15
|
-
export {
|
|
19
|
+
export { AmqpClient, AmqpClientOptions };
|
|
16
20
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;KASY,iBAAA;QACJ;EADI,iBAAA,CAAA,EAEU,4BAAA,GAAA,SAAA;AAGtB,CAAA;AAE2B,cAFd,UAAA,CAEc;EAGI,iBAAA,QAAA;EACD,iBAAA,OAAA;EASb,iBAAA,UAAA;EAAO,SAAA,OAAA,EAbG,cAaH;wBAVO,6BACD;WASb"}
|
package/dist/index.d.mts
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { AmqpConnectionManagerOptions, ChannelWrapper, ConnectionUrl } from "amqp-connection-manager";
|
|
2
2
|
import { ContractDefinition } from "@amqp-contract/contract";
|
|
3
3
|
|
|
4
|
-
//#region src/
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
//#region src/index.d.ts
|
|
5
|
+
type AmqpClientOptions = {
|
|
6
|
+
urls: ConnectionUrl[];
|
|
7
|
+
connectionOptions?: AmqpConnectionManagerOptions | undefined;
|
|
8
|
+
};
|
|
9
|
+
declare class AmqpClient {
|
|
10
|
+
private readonly contract;
|
|
11
|
+
private readonly options;
|
|
12
|
+
private readonly connection;
|
|
13
|
+
readonly channel: ChannelWrapper;
|
|
14
|
+
constructor(contract: ContractDefinition, options: AmqpClientOptions);
|
|
15
|
+
close(): Promise<void>;
|
|
16
|
+
private setup;
|
|
17
|
+
}
|
|
14
18
|
//#endregion
|
|
15
|
-
export {
|
|
19
|
+
export { AmqpClient, AmqpClientOptions };
|
|
16
20
|
//# sourceMappingURL=index.d.mts.map
|
package/dist/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"sourcesContent":[],"mappings":";;;;KASY,iBAAA;QACJ;EADI,iBAAA,CAAA,EAEU,4BAAA,GAAA,SAAA;AAGtB,CAAA;AAE2B,cAFd,UAAA,CAEc;EAGI,iBAAA,QAAA;EACD,iBAAA,OAAA;EASb,iBAAA,UAAA;EAAO,SAAA,OAAA,EAbG,cAaH;wBAVO,6BACD;WASb"}
|
package/dist/index.mjs
CHANGED
|
@@ -1,30 +1,45 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
}
|
|
1
|
+
import amqp from "amqp-connection-manager";
|
|
2
|
+
|
|
3
|
+
//#region src/index.ts
|
|
4
|
+
var AmqpClient = class {
|
|
5
|
+
connection;
|
|
6
|
+
channel;
|
|
7
|
+
constructor(contract, options) {
|
|
8
|
+
this.contract = contract;
|
|
9
|
+
this.options = options;
|
|
10
|
+
this.connection = amqp.connect(this.options.urls, this.options.connectionOptions);
|
|
11
|
+
this.channel = this.connection.createChannel({
|
|
12
|
+
json: true,
|
|
13
|
+
setup: (channel) => this.setup(channel)
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
async close() {
|
|
17
|
+
await this.channel.close();
|
|
18
|
+
await this.connection.close();
|
|
19
|
+
}
|
|
20
|
+
async setup(channel) {
|
|
21
|
+
const exchangeErrors = (await Promise.allSettled(Object.values(this.contract.exchanges ?? {}).map((exchange) => channel.assertExchange(exchange.name, exchange.type, {
|
|
22
|
+
durable: exchange.durable,
|
|
23
|
+
autoDelete: exchange.autoDelete,
|
|
24
|
+
internal: exchange.internal,
|
|
25
|
+
arguments: exchange.arguments
|
|
26
|
+
})))).filter((result) => result.status === "rejected");
|
|
27
|
+
if (exchangeErrors.length > 0) throw new AggregateError(exchangeErrors.map(({ reason }) => reason), "Failed to setup exchanges");
|
|
28
|
+
const queueErrors = (await Promise.allSettled(Object.values(this.contract.queues ?? {}).map((queue) => channel.assertQueue(queue.name, {
|
|
29
|
+
durable: queue.durable,
|
|
30
|
+
exclusive: queue.exclusive,
|
|
31
|
+
autoDelete: queue.autoDelete,
|
|
32
|
+
arguments: queue.arguments
|
|
33
|
+
})))).filter((result) => result.status === "rejected");
|
|
34
|
+
if (queueErrors.length > 0) throw new AggregateError(queueErrors.map(({ reason }) => reason), "Failed to setup queues");
|
|
35
|
+
const bindingErrors = (await Promise.allSettled(Object.values(this.contract.bindings ?? {}).map((binding) => {
|
|
36
|
+
if (binding.type === "queue") return channel.bindQueue(binding.queue.name, binding.exchange.name, binding.routingKey ?? "", binding.arguments);
|
|
37
|
+
return channel.bindExchange(binding.destination.name, binding.source.name, binding.routingKey ?? "", binding.arguments);
|
|
38
|
+
}))).filter((result) => result.status === "rejected");
|
|
39
|
+
if (bindingErrors.length > 0) throw new AggregateError(bindingErrors.map(({ reason }) => reason), "Failed to setup bindings");
|
|
40
|
+
}
|
|
41
|
+
};
|
|
27
42
|
|
|
28
43
|
//#endregion
|
|
29
|
-
export {
|
|
44
|
+
export { AmqpClient };
|
|
30
45
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../src/
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["contract: ContractDefinition","options: AmqpClientOptions"],"sources":["../src/index.ts"],"sourcesContent":["import type { Channel } from \"amqplib\";\nimport type { ContractDefinition } from \"@amqp-contract/contract\";\nimport amqp, {\n AmqpConnectionManager,\n AmqpConnectionManagerOptions,\n ChannelWrapper,\n ConnectionUrl,\n} from \"amqp-connection-manager\";\n\nexport type AmqpClientOptions = {\n urls: ConnectionUrl[];\n connectionOptions?: AmqpConnectionManagerOptions | undefined;\n};\n\nexport class AmqpClient {\n private readonly connection: AmqpConnectionManager;\n public readonly channel: ChannelWrapper;\n\n constructor(\n private readonly contract: ContractDefinition,\n private readonly options: AmqpClientOptions,\n ) {\n this.connection = amqp.connect(this.options.urls, this.options.connectionOptions);\n this.channel = this.connection.createChannel({\n json: true,\n setup: (channel: Channel) => this.setup(channel),\n });\n }\n\n async close(): Promise<void> {\n await this.channel.close();\n await this.connection.close();\n }\n\n private async setup(channel: Channel): Promise<void> {\n // Setup exchanges\n const exchangeResults = await Promise.allSettled(\n Object.values(this.contract.exchanges ?? {}).map((exchange) =>\n channel.assertExchange(exchange.name, exchange.type, {\n durable: exchange.durable,\n autoDelete: exchange.autoDelete,\n internal: exchange.internal,\n arguments: exchange.arguments,\n }),\n ),\n );\n const exchangeErrors = exchangeResults.filter(\n (result): result is PromiseRejectedResult => result.status === \"rejected\",\n );\n if (exchangeErrors.length > 0) {\n throw new AggregateError(\n exchangeErrors.map(({ reason }) => reason),\n \"Failed to setup exchanges\",\n );\n }\n\n // Setup queues\n const queueResults = await Promise.allSettled(\n Object.values(this.contract.queues ?? {}).map((queue) =>\n channel.assertQueue(queue.name, {\n durable: queue.durable,\n exclusive: queue.exclusive,\n autoDelete: queue.autoDelete,\n arguments: queue.arguments,\n }),\n ),\n );\n const queueErrors = queueResults.filter(\n (result): result is PromiseRejectedResult => result.status === \"rejected\",\n );\n if (queueErrors.length > 0) {\n throw new AggregateError(\n queueErrors.map(({ reason }) => reason),\n \"Failed to setup queues\",\n );\n }\n\n // Setup bindings\n const bindingResults = await Promise.allSettled(\n Object.values(this.contract.bindings ?? {}).map((binding) => {\n if (binding.type === \"queue\") {\n return channel.bindQueue(\n binding.queue.name,\n binding.exchange.name,\n binding.routingKey ?? \"\",\n binding.arguments,\n );\n }\n\n return channel.bindExchange(\n binding.destination.name,\n binding.source.name,\n binding.routingKey ?? \"\",\n binding.arguments,\n );\n }),\n );\n const bindingErrors = bindingResults.filter(\n (result): result is PromiseRejectedResult => result.status === \"rejected\",\n );\n if (bindingErrors.length > 0) {\n throw new AggregateError(\n bindingErrors.map(({ reason }) => reason),\n \"Failed to setup bindings\",\n );\n }\n }\n}\n"],"mappings":";;;AAcA,IAAa,aAAb,MAAwB;CACtB,AAAiB;CACjB,AAAgB;CAEhB,YACE,AAAiBA,UACjB,AAAiBC,SACjB;EAFiB;EACA;AAEjB,OAAK,aAAa,KAAK,QAAQ,KAAK,QAAQ,MAAM,KAAK,QAAQ,kBAAkB;AACjF,OAAK,UAAU,KAAK,WAAW,cAAc;GAC3C,MAAM;GACN,QAAQ,YAAqB,KAAK,MAAM,QAAQ;GACjD,CAAC;;CAGJ,MAAM,QAAuB;AAC3B,QAAM,KAAK,QAAQ,OAAO;AAC1B,QAAM,KAAK,WAAW,OAAO;;CAG/B,MAAc,MAAM,SAAiC;EAYnD,MAAM,kBAVkB,MAAM,QAAQ,WACpC,OAAO,OAAO,KAAK,SAAS,aAAa,EAAE,CAAC,CAAC,KAAK,aAChD,QAAQ,eAAe,SAAS,MAAM,SAAS,MAAM;GACnD,SAAS,SAAS;GAClB,YAAY,SAAS;GACrB,UAAU,SAAS;GACnB,WAAW,SAAS;GACrB,CAAC,CACH,CACF,EACsC,QACpC,WAA4C,OAAO,WAAW,WAChE;AACD,MAAI,eAAe,SAAS,EAC1B,OAAM,IAAI,eACR,eAAe,KAAK,EAAE,aAAa,OAAO,EAC1C,4BACD;EAcH,MAAM,eAVe,MAAM,QAAQ,WACjC,OAAO,OAAO,KAAK,SAAS,UAAU,EAAE,CAAC,CAAC,KAAK,UAC7C,QAAQ,YAAY,MAAM,MAAM;GAC9B,SAAS,MAAM;GACf,WAAW,MAAM;GACjB,YAAY,MAAM;GAClB,WAAW,MAAM;GAClB,CAAC,CACH,CACF,EACgC,QAC9B,WAA4C,OAAO,WAAW,WAChE;AACD,MAAI,YAAY,SAAS,EACvB,OAAM,IAAI,eACR,YAAY,KAAK,EAAE,aAAa,OAAO,EACvC,yBACD;EAuBH,MAAM,iBAnBiB,MAAM,QAAQ,WACnC,OAAO,OAAO,KAAK,SAAS,YAAY,EAAE,CAAC,CAAC,KAAK,YAAY;AAC3D,OAAI,QAAQ,SAAS,QACnB,QAAO,QAAQ,UACb,QAAQ,MAAM,MACd,QAAQ,SAAS,MACjB,QAAQ,cAAc,IACtB,QAAQ,UACT;AAGH,UAAO,QAAQ,aACb,QAAQ,YAAY,MACpB,QAAQ,OAAO,MACf,QAAQ,cAAc,IACtB,QAAQ,UACT;IACD,CACH,EACoC,QAClC,WAA4C,OAAO,WAAW,WAChE;AACD,MAAI,cAAc,SAAS,EACzB,OAAM,IAAI,eACR,cAAc,KAAK,EAAE,aAAa,OAAO,EACzC,2BACD"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@amqp-contract/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "Core utilities for AMQP setup and management in amqp-contract",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"amqp",
|
|
@@ -41,20 +41,18 @@
|
|
|
41
41
|
"dist"
|
|
42
42
|
],
|
|
43
43
|
"dependencies": {
|
|
44
|
-
"
|
|
44
|
+
"amqp-connection-manager": "5.0.0",
|
|
45
|
+
"amqplib": "0.10.9",
|
|
46
|
+
"@amqp-contract/contract": "0.3.0"
|
|
45
47
|
},
|
|
46
48
|
"devDependencies": {
|
|
47
49
|
"@types/amqplib": "0.10.8",
|
|
48
50
|
"@vitest/coverage-v8": "4.0.16",
|
|
49
|
-
"amqplib": "0.10.9",
|
|
50
51
|
"tsdown": "0.18.2",
|
|
51
52
|
"typescript": "5.9.3",
|
|
52
53
|
"vitest": "4.0.16",
|
|
53
54
|
"@amqp-contract/tsconfig": "0.0.0"
|
|
54
55
|
},
|
|
55
|
-
"peerDependencies": {
|
|
56
|
-
"amqplib": ">=0.10.0"
|
|
57
|
-
},
|
|
58
56
|
"scripts": {
|
|
59
57
|
"build": "tsdown src/index.ts --format cjs,esm --dts --clean",
|
|
60
58
|
"dev": "tsdown src/index.ts --format cjs,esm --dts --watch",
|