@celerity-sdk/topic 0.4.0 → 0.5.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/chunk-T4LCI5X5.js +20 -0
- package/dist/chunk-T4LCI5X5.js.map +1 -0
- package/dist/index.cjs +348 -280
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -22
- package/dist/index.js +20 -328
- package/dist/index.js.map +1 -1
- package/dist/redis-topic-client-SPF63T34.js +158 -0
- package/dist/redis-topic-client-SPF63T34.js.map +1 -0
- package/dist/sns-topic-client-643MNMBF.js +161 -0
- package/dist/sns-topic-client-643MNMBF.js.map +1 -0
- package/package.json +4 -4
- package/dist/index.d.cts +0 -215
package/dist/index.cjs
CHANGED
|
@@ -6,6 +6,9 @@ var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
|
6
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
7
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
8
|
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
9
12
|
var __export = (target, all) => {
|
|
10
13
|
for (var name in all)
|
|
11
14
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
@@ -28,136 +31,25 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
28
31
|
));
|
|
29
32
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
33
|
|
|
31
|
-
// src/index.ts
|
|
32
|
-
var index_exports = {};
|
|
33
|
-
__export(index_exports, {
|
|
34
|
-
DEFAULT_TOPIC_TOKEN: () => DEFAULT_TOPIC_TOKEN,
|
|
35
|
-
RedisTopicClient: () => RedisTopicClient,
|
|
36
|
-
SNSTopicClient: () => SNSTopicClient,
|
|
37
|
-
Topic: () => Topic,
|
|
38
|
-
TopicClient: () => TopicClient,
|
|
39
|
-
TopicError: () => TopicError,
|
|
40
|
-
TopicLayer: () => TopicLayer,
|
|
41
|
-
createTopicClient: () => createTopicClient,
|
|
42
|
-
getTopic: () => getTopic,
|
|
43
|
-
topicToken: () => topicToken
|
|
44
|
-
});
|
|
45
|
-
module.exports = __toCommonJS(index_exports);
|
|
46
|
-
|
|
47
|
-
// src/types.ts
|
|
48
|
-
var TopicClient = /* @__PURE__ */ Symbol.for("TopicClient");
|
|
49
|
-
|
|
50
|
-
// src/providers/sns/sns-topic-client.ts
|
|
51
|
-
var import_client_sns2 = require("@aws-sdk/client-sns");
|
|
52
|
-
|
|
53
|
-
// src/providers/sns/sns-topic.ts
|
|
54
|
-
var import_debug = __toESM(require("debug"), 1);
|
|
55
|
-
var import_client_sns = require("@aws-sdk/client-sns");
|
|
56
|
-
|
|
57
34
|
// src/errors.ts
|
|
58
|
-
var TopicError
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
this.name = "TopicError";
|
|
66
|
-
}
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
// src/providers/sns/sns-topic.ts
|
|
70
|
-
var debug = (0, import_debug.default)("celerity:topic:sns");
|
|
71
|
-
var SNS_MAX_BATCH_SIZE = 10;
|
|
72
|
-
var SNSTopic = class {
|
|
73
|
-
static {
|
|
74
|
-
__name(this, "SNSTopic");
|
|
75
|
-
}
|
|
76
|
-
topicArn;
|
|
77
|
-
client;
|
|
78
|
-
tracer;
|
|
79
|
-
constructor(topicArn, client, tracer) {
|
|
80
|
-
this.topicArn = topicArn;
|
|
81
|
-
this.client = client;
|
|
82
|
-
this.tracer = tracer;
|
|
83
|
-
}
|
|
84
|
-
async publish(body, options) {
|
|
85
|
-
debug("publish %s", this.topicArn);
|
|
86
|
-
return this.traced("celerity.topic.publish", {
|
|
87
|
-
"topic.arn": this.topicArn
|
|
88
|
-
}, async () => {
|
|
89
|
-
try {
|
|
90
|
-
const result = await this.client.send(new import_client_sns.PublishCommand({
|
|
91
|
-
TopicArn: this.topicArn,
|
|
92
|
-
Message: JSON.stringify(body),
|
|
93
|
-
MessageGroupId: options?.groupId,
|
|
94
|
-
MessageDeduplicationId: options?.deduplicationId,
|
|
95
|
-
Subject: options?.subject,
|
|
96
|
-
MessageAttributes: options?.attributes ? toSNSAttributes(options.attributes) : void 0
|
|
97
|
-
}));
|
|
98
|
-
return {
|
|
99
|
-
messageId: result.MessageId
|
|
100
|
-
};
|
|
101
|
-
} catch (error) {
|
|
102
|
-
throw new TopicError(`Failed to publish message to topic "${this.topicArn}"`, this.topicArn, {
|
|
103
|
-
cause: error
|
|
104
|
-
});
|
|
35
|
+
var TopicError;
|
|
36
|
+
var init_errors = __esm({
|
|
37
|
+
"src/errors.ts"() {
|
|
38
|
+
"use strict";
|
|
39
|
+
TopicError = class extends Error {
|
|
40
|
+
static {
|
|
41
|
+
__name(this, "TopicError");
|
|
105
42
|
}
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
return this.traced("celerity.topic.publish_batch", {
|
|
111
|
-
"topic.arn": this.topicArn,
|
|
112
|
-
"topic.message_count": entries.length
|
|
113
|
-
}, async () => {
|
|
114
|
-
const successful = [];
|
|
115
|
-
const failed = [];
|
|
116
|
-
for (let i = 0; i < entries.length; i += SNS_MAX_BATCH_SIZE) {
|
|
117
|
-
const chunk = entries.slice(i, i + SNS_MAX_BATCH_SIZE);
|
|
118
|
-
const snsEntries = chunk.map((entry) => ({
|
|
119
|
-
Id: entry.id,
|
|
120
|
-
Message: JSON.stringify(entry.body),
|
|
121
|
-
MessageGroupId: entry.options?.groupId,
|
|
122
|
-
MessageDeduplicationId: entry.options?.deduplicationId,
|
|
123
|
-
Subject: entry.options?.subject,
|
|
124
|
-
MessageAttributes: entry.options?.attributes ? toSNSAttributes(entry.options.attributes) : void 0
|
|
125
|
-
}));
|
|
126
|
-
try {
|
|
127
|
-
const result = await this.client.send(new import_client_sns.PublishBatchCommand({
|
|
128
|
-
TopicArn: this.topicArn,
|
|
129
|
-
PublishBatchRequestEntries: snsEntries
|
|
130
|
-
}));
|
|
131
|
-
for (const s of result.Successful ?? []) {
|
|
132
|
-
successful.push({
|
|
133
|
-
id: s.Id,
|
|
134
|
-
messageId: s.MessageId
|
|
135
|
-
});
|
|
136
|
-
}
|
|
137
|
-
for (const f of result.Failed ?? []) {
|
|
138
|
-
failed.push({
|
|
139
|
-
id: f.Id,
|
|
140
|
-
code: f.Code,
|
|
141
|
-
message: f.Message ?? "Unknown error"
|
|
142
|
-
});
|
|
143
|
-
}
|
|
144
|
-
} catch (error) {
|
|
145
|
-
throw new TopicError(`Failed to publish message batch to topic "${this.topicArn}"`, this.topicArn, {
|
|
146
|
-
cause: error
|
|
147
|
-
});
|
|
148
|
-
}
|
|
43
|
+
topic;
|
|
44
|
+
constructor(message, topic, options) {
|
|
45
|
+
super(message, options), this.topic = topic;
|
|
46
|
+
this.name = "TopicError";
|
|
149
47
|
}
|
|
150
|
-
|
|
151
|
-
successful,
|
|
152
|
-
failed
|
|
153
|
-
};
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
traced(name, attributes, fn) {
|
|
157
|
-
if (!this.tracer) return fn();
|
|
158
|
-
return this.tracer.withSpan(name, (span) => fn(span), attributes);
|
|
48
|
+
};
|
|
159
49
|
}
|
|
160
|
-
};
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
// src/providers/sns/sns-topic.ts
|
|
161
53
|
function toSNSAttributes(attrs) {
|
|
162
54
|
const result = {};
|
|
163
55
|
for (const [key, value] of Object.entries(attrs)) {
|
|
@@ -168,139 +60,171 @@ function toSNSAttributes(attrs) {
|
|
|
168
60
|
}
|
|
169
61
|
return result;
|
|
170
62
|
}
|
|
171
|
-
|
|
63
|
+
var import_debug, import_client_sns, debug, SNS_MAX_BATCH_SIZE, SNSTopic;
|
|
64
|
+
var init_sns_topic = __esm({
|
|
65
|
+
"src/providers/sns/sns-topic.ts"() {
|
|
66
|
+
"use strict";
|
|
67
|
+
import_debug = __toESM(require("debug"), 1);
|
|
68
|
+
import_client_sns = require("@aws-sdk/client-sns");
|
|
69
|
+
init_errors();
|
|
70
|
+
debug = (0, import_debug.default)("celerity:topic:sns");
|
|
71
|
+
SNS_MAX_BATCH_SIZE = 10;
|
|
72
|
+
SNSTopic = class {
|
|
73
|
+
static {
|
|
74
|
+
__name(this, "SNSTopic");
|
|
75
|
+
}
|
|
76
|
+
topicArn;
|
|
77
|
+
client;
|
|
78
|
+
tracer;
|
|
79
|
+
constructor(topicArn, client, tracer) {
|
|
80
|
+
this.topicArn = topicArn;
|
|
81
|
+
this.client = client;
|
|
82
|
+
this.tracer = tracer;
|
|
83
|
+
}
|
|
84
|
+
async publish(body, options) {
|
|
85
|
+
debug("publish %s", this.topicArn);
|
|
86
|
+
return this.traced("celerity.topic.publish", {
|
|
87
|
+
"topic.arn": this.topicArn
|
|
88
|
+
}, async () => {
|
|
89
|
+
try {
|
|
90
|
+
const result = await this.client.send(new import_client_sns.PublishCommand({
|
|
91
|
+
TopicArn: this.topicArn,
|
|
92
|
+
Message: JSON.stringify(body),
|
|
93
|
+
MessageGroupId: options?.groupId,
|
|
94
|
+
MessageDeduplicationId: options?.deduplicationId,
|
|
95
|
+
Subject: options?.subject,
|
|
96
|
+
MessageAttributes: options?.attributes ? toSNSAttributes(options.attributes) : void 0
|
|
97
|
+
}));
|
|
98
|
+
return {
|
|
99
|
+
messageId: result.MessageId
|
|
100
|
+
};
|
|
101
|
+
} catch (error) {
|
|
102
|
+
throw new TopicError(`Failed to publish message to topic "${this.topicArn}"`, this.topicArn, {
|
|
103
|
+
cause: error
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
async publishBatch(entries) {
|
|
109
|
+
debug("publishBatch %s (%d entries)", this.topicArn, entries.length);
|
|
110
|
+
return this.traced("celerity.topic.publish_batch", {
|
|
111
|
+
"topic.arn": this.topicArn,
|
|
112
|
+
"topic.message_count": entries.length
|
|
113
|
+
}, async () => {
|
|
114
|
+
const successful = [];
|
|
115
|
+
const failed = [];
|
|
116
|
+
for (let i = 0; i < entries.length; i += SNS_MAX_BATCH_SIZE) {
|
|
117
|
+
const chunk = entries.slice(i, i + SNS_MAX_BATCH_SIZE);
|
|
118
|
+
const snsEntries = chunk.map((entry) => ({
|
|
119
|
+
Id: entry.id,
|
|
120
|
+
Message: JSON.stringify(entry.body),
|
|
121
|
+
MessageGroupId: entry.options?.groupId,
|
|
122
|
+
MessageDeduplicationId: entry.options?.deduplicationId,
|
|
123
|
+
Subject: entry.options?.subject,
|
|
124
|
+
MessageAttributes: entry.options?.attributes ? toSNSAttributes(entry.options.attributes) : void 0
|
|
125
|
+
}));
|
|
126
|
+
try {
|
|
127
|
+
const result = await this.client.send(new import_client_sns.PublishBatchCommand({
|
|
128
|
+
TopicArn: this.topicArn,
|
|
129
|
+
PublishBatchRequestEntries: snsEntries
|
|
130
|
+
}));
|
|
131
|
+
for (const s of result.Successful ?? []) {
|
|
132
|
+
successful.push({
|
|
133
|
+
id: s.Id,
|
|
134
|
+
messageId: s.MessageId
|
|
135
|
+
});
|
|
136
|
+
}
|
|
137
|
+
for (const f of result.Failed ?? []) {
|
|
138
|
+
failed.push({
|
|
139
|
+
id: f.Id,
|
|
140
|
+
code: f.Code,
|
|
141
|
+
message: f.Message ?? "Unknown error"
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
} catch (error) {
|
|
145
|
+
throw new TopicError(`Failed to publish message batch to topic "${this.topicArn}"`, this.topicArn, {
|
|
146
|
+
cause: error
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
successful,
|
|
152
|
+
failed
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
traced(name, attributes, fn) {
|
|
157
|
+
if (!this.tracer) return fn();
|
|
158
|
+
return this.tracer.withSpan(name, (span) => fn(span), attributes);
|
|
159
|
+
}
|
|
160
|
+
};
|
|
161
|
+
__name(toSNSAttributes, "toSNSAttributes");
|
|
162
|
+
}
|
|
163
|
+
});
|
|
172
164
|
|
|
173
165
|
// src/providers/sns/config.ts
|
|
174
166
|
function captureSNSConfig() {
|
|
175
167
|
return {
|
|
176
168
|
region: process.env.AWS_REGION ?? process.env.AWS_DEFAULT_REGION,
|
|
177
|
-
endpoint: process.env.AWS_ENDPOINT_URL,
|
|
169
|
+
endpoint: process.env.CELERITY_AWS_SNS_ENDPOINT ?? process.env.AWS_ENDPOINT_URL,
|
|
178
170
|
credentials: process.env.AWS_ACCESS_KEY_ID && process.env.AWS_SECRET_ACCESS_KEY ? {
|
|
179
171
|
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
180
172
|
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY
|
|
181
173
|
} : void 0
|
|
182
174
|
};
|
|
183
175
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
static {
|
|
189
|
-
__name(this, "SNSTopicClient");
|
|
190
|
-
}
|
|
191
|
-
tracer;
|
|
192
|
-
client = null;
|
|
193
|
-
config;
|
|
194
|
-
constructor(config, tracer) {
|
|
195
|
-
this.tracer = tracer;
|
|
196
|
-
this.config = config ?? captureSNSConfig();
|
|
197
|
-
}
|
|
198
|
-
topic(name) {
|
|
199
|
-
return new SNSTopic(name, this.getClient(), this.tracer);
|
|
200
|
-
}
|
|
201
|
-
close() {
|
|
202
|
-
this.client?.destroy();
|
|
203
|
-
this.client = null;
|
|
204
|
-
}
|
|
205
|
-
getClient() {
|
|
206
|
-
if (!this.client) {
|
|
207
|
-
this.client = new import_client_sns2.SNSClient({
|
|
208
|
-
region: this.config.region,
|
|
209
|
-
endpoint: this.config.endpoint,
|
|
210
|
-
credentials: this.config.credentials
|
|
211
|
-
});
|
|
212
|
-
}
|
|
213
|
-
return this.client;
|
|
176
|
+
var init_config = __esm({
|
|
177
|
+
"src/providers/sns/config.ts"() {
|
|
178
|
+
"use strict";
|
|
179
|
+
__name(captureSNSConfig, "captureSNSConfig");
|
|
214
180
|
}
|
|
215
|
-
};
|
|
181
|
+
});
|
|
216
182
|
|
|
217
|
-
// src/providers/
|
|
218
|
-
var
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
}
|
|
233
|
-
async publish(body, options) {
|
|
234
|
-
debug2("publish %s", this.channelName);
|
|
235
|
-
return this.traced("celerity.topic.publish", {
|
|
236
|
-
"topic.channel": this.channelName
|
|
237
|
-
}, async () => {
|
|
238
|
-
try {
|
|
239
|
-
const messageId = (0, import_node_crypto.randomUUID)();
|
|
240
|
-
const payload = buildEnvelope(body, messageId, options);
|
|
241
|
-
await this.client.publish(this.channelName, payload);
|
|
242
|
-
return {
|
|
243
|
-
messageId
|
|
244
|
-
};
|
|
245
|
-
} catch (error) {
|
|
246
|
-
throw new TopicError(`Failed to publish message to channel "${this.channelName}"`, this.channelName, {
|
|
247
|
-
cause: error
|
|
248
|
-
});
|
|
183
|
+
// src/providers/sns/sns-topic-client.ts
|
|
184
|
+
var sns_topic_client_exports = {};
|
|
185
|
+
__export(sns_topic_client_exports, {
|
|
186
|
+
SNSTopicClient: () => SNSTopicClient
|
|
187
|
+
});
|
|
188
|
+
var import_client_sns2, SNSTopicClient;
|
|
189
|
+
var init_sns_topic_client = __esm({
|
|
190
|
+
"src/providers/sns/sns-topic-client.ts"() {
|
|
191
|
+
"use strict";
|
|
192
|
+
import_client_sns2 = require("@aws-sdk/client-sns");
|
|
193
|
+
init_sns_topic();
|
|
194
|
+
init_config();
|
|
195
|
+
SNSTopicClient = class {
|
|
196
|
+
static {
|
|
197
|
+
__name(this, "SNSTopicClient");
|
|
249
198
|
}
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
"topic.message_count": entries.length
|
|
257
|
-
}, async () => {
|
|
258
|
-
const successful = [];
|
|
259
|
-
const failed = [];
|
|
260
|
-
const messageIds = [];
|
|
261
|
-
const pipeline = this.client.pipeline();
|
|
262
|
-
for (const entry of entries) {
|
|
263
|
-
const messageId = (0, import_node_crypto.randomUUID)();
|
|
264
|
-
messageIds.push(messageId);
|
|
265
|
-
const payload = buildEnvelope(entry.body, messageId, entry.options);
|
|
266
|
-
pipeline.publish(this.channelName, payload);
|
|
199
|
+
tracer;
|
|
200
|
+
client = null;
|
|
201
|
+
config;
|
|
202
|
+
constructor(config, tracer) {
|
|
203
|
+
this.tracer = tracer;
|
|
204
|
+
this.config = config ?? captureSNSConfig();
|
|
267
205
|
}
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
}
|
|
282
|
-
successful.push({
|
|
283
|
-
id: entries[i].id,
|
|
284
|
-
messageId: messageIds[i]
|
|
285
|
-
});
|
|
286
|
-
}
|
|
206
|
+
topic(name) {
|
|
207
|
+
return new SNSTopic(name, this.getClient(), this.tracer);
|
|
208
|
+
}
|
|
209
|
+
close() {
|
|
210
|
+
this.client?.destroy();
|
|
211
|
+
this.client = null;
|
|
212
|
+
}
|
|
213
|
+
getClient() {
|
|
214
|
+
if (!this.client) {
|
|
215
|
+
this.client = new import_client_sns2.SNSClient({
|
|
216
|
+
region: this.config.region,
|
|
217
|
+
endpoint: this.config.endpoint,
|
|
218
|
+
credentials: this.config.credentials
|
|
219
|
+
});
|
|
287
220
|
}
|
|
288
|
-
|
|
289
|
-
throw new TopicError(`Failed to publish message batch to channel "${this.channelName}"`, this.channelName, {
|
|
290
|
-
cause: error
|
|
291
|
-
});
|
|
221
|
+
return this.client;
|
|
292
222
|
}
|
|
293
|
-
|
|
294
|
-
successful,
|
|
295
|
-
failed
|
|
296
|
-
};
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
traced(name, attributes, fn) {
|
|
300
|
-
if (!this.tracer) return fn();
|
|
301
|
-
return this.tracer.withSpan(name, (span) => fn(span), attributes);
|
|
223
|
+
};
|
|
302
224
|
}
|
|
303
|
-
};
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
// src/providers/redis/redis-topic.ts
|
|
304
228
|
function buildEnvelope(body, messageId, options) {
|
|
305
229
|
const envelope = {
|
|
306
230
|
body: JSON.stringify(body),
|
|
@@ -314,59 +238,202 @@ function buildEnvelope(body, messageId, options) {
|
|
|
314
238
|
}
|
|
315
239
|
return JSON.stringify(envelope);
|
|
316
240
|
}
|
|
317
|
-
|
|
241
|
+
var import_node_crypto, import_debug2, debug2, RedisTopic;
|
|
242
|
+
var init_redis_topic = __esm({
|
|
243
|
+
"src/providers/redis/redis-topic.ts"() {
|
|
244
|
+
"use strict";
|
|
245
|
+
import_node_crypto = require("crypto");
|
|
246
|
+
import_debug2 = __toESM(require("debug"), 1);
|
|
247
|
+
init_errors();
|
|
248
|
+
debug2 = (0, import_debug2.default)("celerity:topic:redis");
|
|
249
|
+
RedisTopic = class {
|
|
250
|
+
static {
|
|
251
|
+
__name(this, "RedisTopic");
|
|
252
|
+
}
|
|
253
|
+
channelName;
|
|
254
|
+
client;
|
|
255
|
+
tracer;
|
|
256
|
+
constructor(channelName, client, tracer) {
|
|
257
|
+
this.channelName = channelName;
|
|
258
|
+
this.client = client;
|
|
259
|
+
this.tracer = tracer;
|
|
260
|
+
}
|
|
261
|
+
async publish(body, options) {
|
|
262
|
+
debug2("publish %s", this.channelName);
|
|
263
|
+
return this.traced("celerity.topic.publish", {
|
|
264
|
+
"topic.channel": this.channelName
|
|
265
|
+
}, async () => {
|
|
266
|
+
try {
|
|
267
|
+
const messageId = (0, import_node_crypto.randomUUID)();
|
|
268
|
+
const payload = buildEnvelope(body, messageId, options);
|
|
269
|
+
await this.client.publish(this.channelName, payload);
|
|
270
|
+
return {
|
|
271
|
+
messageId
|
|
272
|
+
};
|
|
273
|
+
} catch (error) {
|
|
274
|
+
throw new TopicError(`Failed to publish message to channel "${this.channelName}"`, this.channelName, {
|
|
275
|
+
cause: error
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
async publishBatch(entries) {
|
|
281
|
+
debug2("publishBatch %s (%d entries)", this.channelName, entries.length);
|
|
282
|
+
return this.traced("celerity.topic.publish_batch", {
|
|
283
|
+
"topic.channel": this.channelName,
|
|
284
|
+
"topic.message_count": entries.length
|
|
285
|
+
}, async () => {
|
|
286
|
+
const successful = [];
|
|
287
|
+
const failed = [];
|
|
288
|
+
const messageIds = [];
|
|
289
|
+
const pipeline = this.client.pipeline();
|
|
290
|
+
for (const entry of entries) {
|
|
291
|
+
const messageId = (0, import_node_crypto.randomUUID)();
|
|
292
|
+
messageIds.push(messageId);
|
|
293
|
+
const payload = buildEnvelope(entry.body, messageId, entry.options);
|
|
294
|
+
pipeline.publish(this.channelName, payload);
|
|
295
|
+
}
|
|
296
|
+
try {
|
|
297
|
+
const results = await pipeline.exec();
|
|
298
|
+
if (!results) {
|
|
299
|
+
throw new Error("Pipeline returned null");
|
|
300
|
+
}
|
|
301
|
+
for (let i = 0; i < entries.length; i++) {
|
|
302
|
+
const [err] = results[i];
|
|
303
|
+
if (err) {
|
|
304
|
+
failed.push({
|
|
305
|
+
id: entries[i].id,
|
|
306
|
+
code: err.name ?? "PipelineError",
|
|
307
|
+
message: err.message
|
|
308
|
+
});
|
|
309
|
+
} else {
|
|
310
|
+
successful.push({
|
|
311
|
+
id: entries[i].id,
|
|
312
|
+
messageId: messageIds[i]
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
} catch (error) {
|
|
317
|
+
throw new TopicError(`Failed to publish message batch to channel "${this.channelName}"`, this.channelName, {
|
|
318
|
+
cause: error
|
|
319
|
+
});
|
|
320
|
+
}
|
|
321
|
+
return {
|
|
322
|
+
successful,
|
|
323
|
+
failed
|
|
324
|
+
};
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
traced(name, attributes, fn) {
|
|
328
|
+
if (!this.tracer) return fn();
|
|
329
|
+
return this.tracer.withSpan(name, (span) => fn(span), attributes);
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
__name(buildEnvelope, "buildEnvelope");
|
|
333
|
+
}
|
|
334
|
+
});
|
|
318
335
|
|
|
319
336
|
// src/providers/redis/config.ts
|
|
320
|
-
var DEFAULT_REDIS_URL = "redis://localhost:6379";
|
|
321
337
|
function captureRedisConfig() {
|
|
322
338
|
return {
|
|
323
|
-
url: process.env.
|
|
339
|
+
url: process.env.CELERITY_REDIS_ENDPOINT ?? DEFAULT_REDIS_URL
|
|
324
340
|
};
|
|
325
341
|
}
|
|
326
|
-
|
|
342
|
+
var DEFAULT_REDIS_URL;
|
|
343
|
+
var init_config2 = __esm({
|
|
344
|
+
"src/providers/redis/config.ts"() {
|
|
345
|
+
"use strict";
|
|
346
|
+
DEFAULT_REDIS_URL = "redis://localhost:6379";
|
|
347
|
+
__name(captureRedisConfig, "captureRedisConfig");
|
|
348
|
+
}
|
|
349
|
+
});
|
|
327
350
|
|
|
328
351
|
// src/providers/redis/redis-topic-client.ts
|
|
329
|
-
var
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
352
|
+
var redis_topic_client_exports = {};
|
|
353
|
+
__export(redis_topic_client_exports, {
|
|
354
|
+
RedisTopicClient: () => RedisTopicClient
|
|
355
|
+
});
|
|
356
|
+
var RedisTopicClient;
|
|
357
|
+
var init_redis_topic_client = __esm({
|
|
358
|
+
"src/providers/redis/redis-topic-client.ts"() {
|
|
359
|
+
"use strict";
|
|
360
|
+
init_redis_topic();
|
|
361
|
+
init_config2();
|
|
362
|
+
RedisTopicClient = class {
|
|
363
|
+
static {
|
|
364
|
+
__name(this, "RedisTopicClient");
|
|
365
|
+
}
|
|
366
|
+
tracer;
|
|
367
|
+
client = null;
|
|
368
|
+
ioredisModule = null;
|
|
369
|
+
config;
|
|
370
|
+
constructor(config, tracer) {
|
|
371
|
+
this.tracer = tracer;
|
|
372
|
+
this.config = config ?? captureRedisConfig();
|
|
373
|
+
}
|
|
374
|
+
topic(name) {
|
|
375
|
+
const channel = `celerity:topic:channel:${name}`;
|
|
376
|
+
return new RedisTopic(channel, this.getClient(), this.tracer);
|
|
377
|
+
}
|
|
378
|
+
async close() {
|
|
379
|
+
if (this.client) {
|
|
380
|
+
await this.client.quit();
|
|
381
|
+
this.client = null;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
async ensureIoRedis() {
|
|
385
|
+
if (!this.ioredisModule) {
|
|
386
|
+
const pkg = "ioredis";
|
|
387
|
+
this.ioredisModule = await import(pkg);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
getClient() {
|
|
391
|
+
if (!this.client) {
|
|
392
|
+
const ioredis = this.ioredisModule;
|
|
393
|
+
const Redis = ioredis.default ?? ioredis;
|
|
394
|
+
this.client = new Redis(this.config.url);
|
|
395
|
+
}
|
|
396
|
+
return this.client;
|
|
397
|
+
}
|
|
398
|
+
};
|
|
355
399
|
}
|
|
356
|
-
};
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
// src/index.ts
|
|
403
|
+
var index_exports = {};
|
|
404
|
+
__export(index_exports, {
|
|
405
|
+
DEFAULT_TOPIC_TOKEN: () => DEFAULT_TOPIC_TOKEN,
|
|
406
|
+
Topic: () => Topic,
|
|
407
|
+
TopicClient: () => TopicClient,
|
|
408
|
+
TopicError: () => TopicError,
|
|
409
|
+
TopicLayer: () => TopicLayer,
|
|
410
|
+
createTopicClient: () => createTopicClient,
|
|
411
|
+
getTopic: () => getTopic,
|
|
412
|
+
topicToken: () => topicToken
|
|
413
|
+
});
|
|
414
|
+
module.exports = __toCommonJS(index_exports);
|
|
415
|
+
|
|
416
|
+
// src/types.ts
|
|
417
|
+
var TopicClient = /* @__PURE__ */ Symbol.for("TopicClient");
|
|
357
418
|
|
|
358
419
|
// src/factory.ts
|
|
359
420
|
var import_config3 = require("@celerity-sdk/config");
|
|
360
|
-
function createTopicClient(options) {
|
|
421
|
+
async function createTopicClient(options) {
|
|
361
422
|
const resolved = (0, import_config3.resolveConfig)("topic");
|
|
362
423
|
const provider = options?.provider ?? resolved.provider;
|
|
363
424
|
switch (provider) {
|
|
364
|
-
case "aws":
|
|
365
|
-
|
|
425
|
+
case "aws": {
|
|
426
|
+
const { SNSTopicClient: SNSTopicClient2 } = await Promise.resolve().then(() => (init_sns_topic_client(), sns_topic_client_exports));
|
|
427
|
+
return new SNSTopicClient2(options?.aws, options?.tracer);
|
|
428
|
+
}
|
|
366
429
|
// Local environments always use Redis pub/sub regardless of deploy target.
|
|
367
430
|
// The Celerity CLI manages the Redis instance and local-events sidecar.
|
|
368
|
-
case "local":
|
|
369
|
-
|
|
431
|
+
case "local": {
|
|
432
|
+
const { RedisTopicClient: RedisTopicClient2 } = await Promise.resolve().then(() => (init_redis_topic_client(), redis_topic_client_exports));
|
|
433
|
+
const client = new RedisTopicClient2(options?.local, options?.tracer);
|
|
434
|
+
await client.ensureIoRedis();
|
|
435
|
+
return client;
|
|
436
|
+
}
|
|
370
437
|
// case "gcp":
|
|
371
438
|
// v1: Google Cloud Pub/Sub
|
|
372
439
|
// case "azure":
|
|
@@ -424,7 +491,7 @@ var TopicLayer = class {
|
|
|
424
491
|
async handle(context, next) {
|
|
425
492
|
if (!this.initialized) {
|
|
426
493
|
const tracer = context.container.has(import_common2.TRACER_TOKEN) ? await context.container.resolve(import_common2.TRACER_TOKEN) : void 0;
|
|
427
|
-
const client = createTopicClient({
|
|
494
|
+
const client = await createTopicClient({
|
|
428
495
|
tracer
|
|
429
496
|
});
|
|
430
497
|
debug3("registering TopicClient");
|
|
@@ -459,11 +526,12 @@ var TopicLayer = class {
|
|
|
459
526
|
return next();
|
|
460
527
|
}
|
|
461
528
|
};
|
|
529
|
+
|
|
530
|
+
// src/index.ts
|
|
531
|
+
init_errors();
|
|
462
532
|
// Annotate the CommonJS export names for ESM import in node:
|
|
463
533
|
0 && (module.exports = {
|
|
464
534
|
DEFAULT_TOPIC_TOKEN,
|
|
465
|
-
RedisTopicClient,
|
|
466
|
-
SNSTopicClient,
|
|
467
535
|
Topic,
|
|
468
536
|
TopicClient,
|
|
469
537
|
TopicError,
|