@windrun-huaiin/backend-core 20.0.0 → 20.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -115,7 +115,11 @@ exports.fetchPaymentId = stripeConfig.fetchPaymentId;
115
115
  exports.getStripe = stripeConfig.getStripe;
116
116
  exports.updateSubscription = stripeConfig.updateSubscription;
117
117
  exports.validateStripeWebhook = stripeConfig.validateStripeWebhook;
118
+ exports.getPrefixedQstashQueueName = upstashConfig.getPrefixedQstashQueueName;
119
+ exports.getPrefixedRedisKey = upstashConfig.getPrefixedRedisKey;
120
+ exports.getPrefixedRedisKeys = upstashConfig.getPrefixedRedisKeys;
118
121
  exports.getQstash = upstashConfig.getQstash;
122
+ exports.getQstashNamePrefix = upstashConfig.getQstashNamePrefix;
119
123
  exports.getRedis = upstashConfig.getRedis;
120
124
  exports.withQstash = upstashConfig.withQstash;
121
125
  exports.withRedis = upstashConfig.withRedis;
@@ -171,7 +175,9 @@ exports.smembers = redisStructures.smembers;
171
175
  exports.srem = redisStructures.srem;
172
176
  exports.ttl = redisStructures.ttl;
173
177
  exports.cancelSchedule = qstash.cancelSchedule;
178
+ exports.publishBroadcastMessage = qstash.publishBroadcastMessage;
174
179
  exports.publishDelayedMessage = qstash.publishDelayedMessage;
180
+ exports.publishFIFOQueueMessage = qstash.publishFIFOQueueMessage;
175
181
  exports.publishMessage = qstash.publishMessage;
176
182
  exports.scheduleMessage = qstash.scheduleMessage;
177
183
  exports.verifyQstashSignature = qstash.verifyQstashSignature;
package/dist/index.mjs CHANGED
@@ -26,10 +26,10 @@ export { getMoneyPriceInitUserContext } from './lib/money-price-helper.mjs';
26
26
  export { fingerprintConfig } from './lib/fingerprint-config.mjs';
27
27
  export { creditsConfig, freeAmount, freeExpiredDays, freeRegisterAmount, oneTimeExpiredDays } from './lib/credit-init.mjs';
28
28
  export { ActiveSubscriptionExistsError, cancelSubscription, createCheckoutSession, createCustomerPortalSession, createOrGetCustomer, fetchPaymentId, getStripe, updateSubscription, validateStripeWebhook } from './lib/stripe-config.mjs';
29
- export { getQstash, getRedis, withQstash, withRedis } from './lib/upstash-config.mjs';
29
+ export { getPrefixedQstashQueueName, getPrefixedRedisKey, getPrefixedRedisKeys, getQstash, getQstashNamePrefix, getRedis, withQstash, withRedis } from './lib/upstash-config.mjs';
30
30
  export { acquireLock, releaseLock, withLock } from './lib/upstash/redis-lock.mjs';
31
31
  export { getTargetLikeCount, getUserLikedTargets, isTargetLiked, likeTarget, unlikeTarget } from './lib/upstash/redis-like.mjs';
32
32
  export { addFavorite, getFavoriteCount, getUserFavorites, isFavorited, removeFavorite } from './lib/upstash/redis-favorite.mjs';
33
33
  export { getCounter, getUniqueCounter, incrCounter, incrUniqueCounter } from './lib/upstash/redis-counter.mjs';
34
34
  export { del, deleteHashField, deleteKey, exists, expire, getHashAll, getHashField, getHashJson, getJson, getString, hexists, hkeys, hlen, hmget, hmset, listLength, mget, mgetJson, mset, msetJson, pipeline, popList, pushList, rangeList, sadd, scard, setHashField, setHashJson, setJson, setString, sismember, smembers, srem, ttl } from './lib/upstash/redis-structures.mjs';
35
- export { cancelSchedule, publishDelayedMessage, publishMessage, scheduleMessage, verifyQstashSignature } from './lib/upstash/qstash.mjs';
35
+ export { cancelSchedule, publishBroadcastMessage, publishDelayedMessage, publishFIFOQueueMessage, publishMessage, scheduleMessage, verifyQstashSignature } from './lib/upstash/qstash.mjs';
package/dist/lib/index.js CHANGED
@@ -35,7 +35,11 @@ exports.fetchPaymentId = stripeConfig.fetchPaymentId;
35
35
  exports.getStripe = stripeConfig.getStripe;
36
36
  exports.updateSubscription = stripeConfig.updateSubscription;
37
37
  exports.validateStripeWebhook = stripeConfig.validateStripeWebhook;
38
+ exports.getPrefixedQstashQueueName = upstashConfig.getPrefixedQstashQueueName;
39
+ exports.getPrefixedRedisKey = upstashConfig.getPrefixedRedisKey;
40
+ exports.getPrefixedRedisKeys = upstashConfig.getPrefixedRedisKeys;
38
41
  exports.getQstash = upstashConfig.getQstash;
42
+ exports.getQstashNamePrefix = upstashConfig.getQstashNamePrefix;
39
43
  exports.getRedis = upstashConfig.getRedis;
40
44
  exports.withQstash = upstashConfig.withQstash;
41
45
  exports.withRedis = upstashConfig.withRedis;
@@ -91,7 +95,9 @@ exports.smembers = redisStructures.smembers;
91
95
  exports.srem = redisStructures.srem;
92
96
  exports.ttl = redisStructures.ttl;
93
97
  exports.cancelSchedule = qstash.cancelSchedule;
98
+ exports.publishBroadcastMessage = qstash.publishBroadcastMessage;
94
99
  exports.publishDelayedMessage = qstash.publishDelayedMessage;
100
+ exports.publishFIFOQueueMessage = qstash.publishFIFOQueueMessage;
95
101
  exports.publishMessage = qstash.publishMessage;
96
102
  exports.scheduleMessage = qstash.scheduleMessage;
97
103
  exports.verifyQstashSignature = qstash.verifyQstashSignature;
@@ -3,10 +3,10 @@ export { getMoneyPriceInitUserContext } from './money-price-helper.mjs';
3
3
  export { fingerprintConfig } from './fingerprint-config.mjs';
4
4
  export { creditsConfig, freeAmount, freeExpiredDays, freeRegisterAmount, oneTimeExpiredDays } from './credit-init.mjs';
5
5
  export { ActiveSubscriptionExistsError, cancelSubscription, createCheckoutSession, createCustomerPortalSession, createOrGetCustomer, fetchPaymentId, getStripe, updateSubscription, validateStripeWebhook } from './stripe-config.mjs';
6
- export { getQstash, getRedis, withQstash, withRedis } from './upstash-config.mjs';
6
+ export { getPrefixedQstashQueueName, getPrefixedRedisKey, getPrefixedRedisKeys, getQstash, getQstashNamePrefix, getRedis, withQstash, withRedis } from './upstash-config.mjs';
7
7
  export { acquireLock, releaseLock, withLock } from './upstash/redis-lock.mjs';
8
8
  export { getTargetLikeCount, getUserLikedTargets, isTargetLiked, likeTarget, unlikeTarget } from './upstash/redis-like.mjs';
9
9
  export { addFavorite, getFavoriteCount, getUserFavorites, isFavorited, removeFavorite } from './upstash/redis-favorite.mjs';
10
10
  export { getCounter, getUniqueCounter, incrCounter, incrUniqueCounter } from './upstash/redis-counter.mjs';
11
11
  export { del, deleteHashField, deleteKey, exists, expire, getHashAll, getHashField, getHashJson, getJson, getString, hexists, hkeys, hlen, hmget, hmset, listLength, mget, mgetJson, mset, msetJson, pipeline, popList, pushList, rangeList, sadd, scard, setHashField, setHashJson, setJson, setString, sismember, smembers, srem, ttl } from './upstash/redis-structures.mjs';
12
- export { cancelSchedule, publishDelayedMessage, publishMessage, scheduleMessage, verifyQstashSignature } from './upstash/qstash.mjs';
12
+ export { cancelSchedule, publishBroadcastMessage, publishDelayedMessage, publishFIFOQueueMessage, publishMessage, scheduleMessage, verifyQstashSignature } from './upstash/qstash.mjs';
@@ -7,6 +7,15 @@ export interface PublishMessageOptions<TBody extends PublishBody = PublishBody>
7
7
  url: string;
8
8
  body: TBody;
9
9
  }
10
+ export interface PublishBroadcastMessageOptions<TBody extends PublishBody = PublishBody> {
11
+ urlGroup: string;
12
+ body: TBody;
13
+ }
14
+ export interface PublishFIFOQueueMessageOptions<TBody extends PublishBody = PublishBody> {
15
+ queueName: string;
16
+ url: string;
17
+ body: TBody;
18
+ }
10
19
  /**
11
20
  * Publish a message. Returns message id or null if QStash is unavailable.
12
21
  */
@@ -14,6 +23,22 @@ export declare const publishMessage: <TBody extends PublishBody>(options: Publis
14
23
  messageId: string | null;
15
24
  message: QstashEnvelope<TBody>;
16
25
  } | null>;
26
+ /**
27
+ * Publish a broadcast message to a QStash URL Group.
28
+ * Returns message ids or null if QStash is unavailable.
29
+ */
30
+ export declare const publishBroadcastMessage: <TBody extends PublishBody>(options: PublishBroadcastMessageOptions<TBody>) => Promise<{
31
+ messageIds: string[];
32
+ message: QstashEnvelope<TBody>;
33
+ } | null>;
34
+ /**
35
+ * Publish a single-recipient message into a QStash FIFO queue.
36
+ * Returns message id or null if QStash is unavailable.
37
+ */
38
+ export declare const publishFIFOQueueMessage: <TBody extends PublishBody>(options: PublishFIFOQueueMessageOptions<TBody>) => Promise<{
39
+ messageId: string | null;
40
+ message: QstashEnvelope<TBody>;
41
+ } | null>;
17
42
  /**
18
43
  * Publish a delayed message. Returns message id or null if QStash is unavailable.
19
44
  */
@@ -1 +1 @@
1
- {"version":3,"file":"qstash.d.ts","sourceRoot":"","sources":["../../../src/lib/upstash/qstash.ts"],"names":[],"mappings":"AA8CA,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AAErF,MAAM,WAAW,cAAc,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW;IACrE,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,KAAK,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW;IAC5E,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,KAAK,CAAC;CACb;AAiBD;;GAEG;AACH,eAAO,MAAM,cAAc,GAAU,KAAK,SAAS,WAAW,EAC5D,SAAS,qBAAqB,CAAC,KAAK,CAAC,KACpC,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,CAAA;CAAE,GAAG,IAAI,CAa7E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAAU,KAAK,SAAS,WAAW,EACnE,SAAS,qBAAqB,CAAC,KAAK,CAAC,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,KAC3D,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,CAAA;CAAE,GAAG,IAAI,CAc7E,CAAC;AAEF,MAAM,WAAW,sBAAsB,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW,CAC7E,SAAQ,qBAAqB,CAAC,KAAK,CAAC;IACpC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,GAAU,KAAK,SAAS,WAAW,EAC7D,SAAS,sBAAsB,CAAC,KAAK,CAAC,KACrC,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,CAAA;CAAE,GAAG,IAAI,CAsB9E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,GAAU,YAAY,MAAM,KAAG,OAAO,CAAC,OAAO,CAexE,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAAU,SAAS,mBAAmB,KAAG,OAAO,CAAC,OAAO,CAqBzF,CAAC"}
1
+ {"version":3,"file":"qstash.d.ts","sourceRoot":"","sources":["../../../src/lib/upstash/qstash.ts"],"names":[],"mappings":"AA8CA,MAAM,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,CAAC;AAErF,MAAM,WAAW,cAAc,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW;IACrE,aAAa,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,KAAK,CAAC;CAChB;AAED,MAAM,WAAW,qBAAqB,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW;IAC5E,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,KAAK,CAAC;CACb;AAED,MAAM,WAAW,8BAA8B,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW;IACrF,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,KAAK,CAAC;CACb;AAED,MAAM,WAAW,8BAA8B,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW;IACrF,SAAS,EAAE,MAAM,CAAC;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,KAAK,CAAC;CACb;AAiBD;;GAEG;AACH,eAAO,MAAM,cAAc,GAAU,KAAK,SAAS,WAAW,EAC5D,SAAS,qBAAqB,CAAC,KAAK,CAAC,KACpC,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,CAAA;CAAE,GAAG,IAAI,CAa7E,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,uBAAuB,GAAU,KAAK,SAAS,WAAW,EACrE,SAAS,8BAA8B,CAAC,KAAK,CAAC,KAC7C,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,CAAA;CAAE,GAAG,IAAI,CA0BzE,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,uBAAuB,GAAU,KAAK,SAAS,WAAW,EACrE,SAAS,8BAA8B,CAAC,KAAK,CAAC,KAC7C,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,CAAA;CAAE,GAAG,IAAI,CAqB7E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAAU,KAAK,SAAS,WAAW,EACnE,SAAS,qBAAqB,CAAC,KAAK,CAAC,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,KAC3D,OAAO,CAAC;IAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,CAAA;CAAE,GAAG,IAAI,CAc7E,CAAC;AAEF,MAAM,WAAW,sBAAsB,CAAC,KAAK,SAAS,WAAW,GAAG,WAAW,CAC7E,SAAQ,qBAAqB,CAAC,KAAK,CAAC;IACpC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;GAEG;AACH,eAAO,MAAM,eAAe,GAAU,KAAK,SAAS,WAAW,EAC7D,SAAS,sBAAsB,CAAC,KAAK,CAAC,KACrC,OAAO,CAAC;IAAE,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,OAAO,EAAE,cAAc,CAAC,KAAK,CAAC,CAAA;CAAE,GAAG,IAAI,CAsB9E,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,cAAc,GAAU,YAAY,MAAM,KAAG,OAAO,CAAC,OAAO,CAexE,CAAC;AAEF,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAAU,SAAS,mBAAmB,KAAG,OAAO,CAAC,OAAO,CAqBzF,CAAC"}
@@ -69,6 +69,56 @@ const publishMessage = (options) => tslib.__awaiter(void 0, void 0, void 0, func
69
69
  };
70
70
  }));
71
71
  });
72
+ /**
73
+ * Publish a broadcast message to a QStash URL Group.
74
+ * Returns message ids or null if QStash is unavailable.
75
+ */
76
+ const publishBroadcastMessage = (options) => tslib.__awaiter(void 0, void 0, void 0, function* () {
77
+ const message = createEnvelope(options.body);
78
+ return upstashConfig.withQstash((client) => tslib.__awaiter(void 0, void 0, void 0, function* () {
79
+ const result = yield client.publishJSON({
80
+ urlGroup: options.urlGroup,
81
+ body: message,
82
+ });
83
+ const messageIds = Array.isArray(result)
84
+ ? result
85
+ .map((item) => typeof item === 'string' ? item : typeof (item === null || item === void 0 ? void 0 : item.messageId) === 'string' ? item.messageId : null)
86
+ .filter((messageId) => typeof messageId === 'string')
87
+ : typeof result === 'string'
88
+ ? [result]
89
+ : typeof (result === null || result === void 0 ? void 0 : result.messageId) === 'string'
90
+ ? [result.messageId]
91
+ : [];
92
+ return {
93
+ messageIds,
94
+ message,
95
+ };
96
+ }));
97
+ });
98
+ /**
99
+ * Publish a single-recipient message into a QStash FIFO queue.
100
+ * Returns message id or null if QStash is unavailable.
101
+ */
102
+ const publishFIFOQueueMessage = (options) => tslib.__awaiter(void 0, void 0, void 0, function* () {
103
+ const message = createEnvelope(options.body);
104
+ const queueName = upstashConfig.getPrefixedQstashQueueName(options.queueName);
105
+ return upstashConfig.withQstash((client) => tslib.__awaiter(void 0, void 0, void 0, function* () {
106
+ var _a, _b;
107
+ const anyClient = client;
108
+ const queueClient = (_a = anyClient.queue) === null || _a === void 0 ? void 0 : _a.call(anyClient, { queueName });
109
+ if (!(queueClient === null || queueClient === void 0 ? void 0 : queueClient.enqueueJSON)) {
110
+ throw new Error('QStash queue enqueueJSON API is unavailable');
111
+ }
112
+ const result = yield queueClient.enqueueJSON({
113
+ url: options.url,
114
+ body: message,
115
+ });
116
+ return {
117
+ messageId: typeof result === 'string' ? result : (_b = result === null || result === void 0 ? void 0 : result.messageId) !== null && _b !== void 0 ? _b : null,
118
+ message,
119
+ };
120
+ }));
121
+ });
72
122
  /**
73
123
  * Publish a delayed message. Returns message id or null if QStash is unavailable.
74
124
  */
@@ -154,7 +204,9 @@ const verifyQstashSignature = (options) => tslib.__awaiter(void 0, void 0, void
154
204
  });
155
205
 
156
206
  exports.cancelSchedule = cancelSchedule;
207
+ exports.publishBroadcastMessage = publishBroadcastMessage;
157
208
  exports.publishDelayedMessage = publishDelayedMessage;
209
+ exports.publishFIFOQueueMessage = publishFIFOQueueMessage;
158
210
  exports.publishMessage = publishMessage;
159
211
  exports.scheduleMessage = scheduleMessage;
160
212
  exports.verifyQstashSignature = verifyQstashSignature;
@@ -1,6 +1,6 @@
1
1
  import { __awaiter } from 'tslib';
2
2
  import { Receiver } from '@upstash/qstash';
3
- import { withQstash } from '../upstash-config.mjs';
3
+ import { withQstash, getPrefixedQstashQueueName } from '../upstash-config.mjs';
4
4
 
5
5
  let cachedReceiver = null;
6
6
  let receiverWarnedMissingEnv = false;
@@ -67,6 +67,56 @@ const publishMessage = (options) => __awaiter(void 0, void 0, void 0, function*
67
67
  };
68
68
  }));
69
69
  });
70
+ /**
71
+ * Publish a broadcast message to a QStash URL Group.
72
+ * Returns message ids or null if QStash is unavailable.
73
+ */
74
+ const publishBroadcastMessage = (options) => __awaiter(void 0, void 0, void 0, function* () {
75
+ const message = createEnvelope(options.body);
76
+ return withQstash((client) => __awaiter(void 0, void 0, void 0, function* () {
77
+ const result = yield client.publishJSON({
78
+ urlGroup: options.urlGroup,
79
+ body: message,
80
+ });
81
+ const messageIds = Array.isArray(result)
82
+ ? result
83
+ .map((item) => typeof item === 'string' ? item : typeof (item === null || item === void 0 ? void 0 : item.messageId) === 'string' ? item.messageId : null)
84
+ .filter((messageId) => typeof messageId === 'string')
85
+ : typeof result === 'string'
86
+ ? [result]
87
+ : typeof (result === null || result === void 0 ? void 0 : result.messageId) === 'string'
88
+ ? [result.messageId]
89
+ : [];
90
+ return {
91
+ messageIds,
92
+ message,
93
+ };
94
+ }));
95
+ });
96
+ /**
97
+ * Publish a single-recipient message into a QStash FIFO queue.
98
+ * Returns message id or null if QStash is unavailable.
99
+ */
100
+ const publishFIFOQueueMessage = (options) => __awaiter(void 0, void 0, void 0, function* () {
101
+ const message = createEnvelope(options.body);
102
+ const queueName = getPrefixedQstashQueueName(options.queueName);
103
+ return withQstash((client) => __awaiter(void 0, void 0, void 0, function* () {
104
+ var _a, _b;
105
+ const anyClient = client;
106
+ const queueClient = (_a = anyClient.queue) === null || _a === void 0 ? void 0 : _a.call(anyClient, { queueName });
107
+ if (!(queueClient === null || queueClient === void 0 ? void 0 : queueClient.enqueueJSON)) {
108
+ throw new Error('QStash queue enqueueJSON API is unavailable');
109
+ }
110
+ const result = yield queueClient.enqueueJSON({
111
+ url: options.url,
112
+ body: message,
113
+ });
114
+ return {
115
+ messageId: typeof result === 'string' ? result : (_b = result === null || result === void 0 ? void 0 : result.messageId) !== null && _b !== void 0 ? _b : null,
116
+ message,
117
+ };
118
+ }));
119
+ });
70
120
  /**
71
121
  * Publish a delayed message. Returns message id or null if QStash is unavailable.
72
122
  */
@@ -151,4 +201,4 @@ const verifyQstashSignature = (options) => __awaiter(void 0, void 0, void 0, fun
151
201
  return true;
152
202
  });
153
203
 
154
- export { cancelSchedule, publishDelayedMessage, publishMessage, scheduleMessage, verifyQstashSignature };
204
+ export { cancelSchedule, publishBroadcastMessage, publishDelayedMessage, publishFIFOQueueMessage, publishMessage, scheduleMessage, verifyQstashSignature };
@@ -30,7 +30,7 @@ export declare const setJson: <T>(key: string, value: T, ttlSec?: number) => Pro
30
30
  */
31
31
  export declare const getJson: <T>(key: string) => Promise<T | null>;
32
32
  /**
33
- * MGET JSON values stored as strings. Missing or invalid values are returned as null.
33
+ * MGET JSON values. Missing or invalid string values are returned as null.
34
34
  */
35
35
  export declare const mgetJson: <T>(keys: string[]) => Promise<(T | null)[] | null>;
36
36
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"redis-structures.d.ts","sourceRoot":"","sources":["../../../src/lib/upstash/redis-structures.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"redis-structures.d.ts","sourceRoot":"","sources":["../../../src/lib/upstash/redis-structures.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,23 @@
3
3
  var tslib = require('tslib');
4
4
  var upstashConfig = require('../upstash-config.js');
5
5
 
6
+ const parseJsonPayload = (payload) => {
7
+ if (payload == null) {
8
+ return null;
9
+ }
10
+ if (typeof payload === 'string') {
11
+ if (!payload) {
12
+ return null;
13
+ }
14
+ try {
15
+ return JSON.parse(payload);
16
+ }
17
+ catch (_a) {
18
+ return null;
19
+ }
20
+ }
21
+ return payload;
22
+ };
6
23
  /**
7
24
  * Set a plain string value with optional TTL (seconds).
8
25
  */
@@ -66,19 +83,11 @@ const setJson = (key, value, ttlSec) => tslib.__awaiter(void 0, void 0, void 0,
66
83
  const getJson = (key) => tslib.__awaiter(void 0, void 0, void 0, function* () {
67
84
  return upstashConfig.withRedis((redis) => tslib.__awaiter(void 0, void 0, void 0, function* () {
68
85
  const payload = yield redis.get(key);
69
- if (!payload) {
70
- return null;
71
- }
72
- try {
73
- return JSON.parse(payload);
74
- }
75
- catch (_a) {
76
- return null;
77
- }
86
+ return parseJsonPayload(payload);
78
87
  }));
79
88
  });
80
89
  /**
81
- * MGET JSON values stored as strings. Missing or invalid values are returned as null.
90
+ * MGET JSON values. Missing or invalid string values are returned as null.
82
91
  */
83
92
  const mgetJson = (keys) => tslib.__awaiter(void 0, void 0, void 0, function* () {
84
93
  return upstashConfig.withRedis((redis) => tslib.__awaiter(void 0, void 0, void 0, function* () {
@@ -86,17 +95,7 @@ const mgetJson = (keys) => tslib.__awaiter(void 0, void 0, void 0, function* ()
86
95
  return [];
87
96
  }
88
97
  const payloads = yield redis.mget(...keys);
89
- return payloads.map((payload) => {
90
- if (!payload) {
91
- return null;
92
- }
93
- try {
94
- return JSON.parse(payload);
95
- }
96
- catch (_a) {
97
- return null;
98
- }
99
- });
98
+ return payloads.map((payload) => parseJsonPayload(payload));
100
99
  }));
101
100
  });
102
101
  /**
@@ -1,6 +1,23 @@
1
1
  import { __awaiter } from 'tslib';
2
2
  import { withRedis } from '../upstash-config.mjs';
3
3
 
4
+ const parseJsonPayload = (payload) => {
5
+ if (payload == null) {
6
+ return null;
7
+ }
8
+ if (typeof payload === 'string') {
9
+ if (!payload) {
10
+ return null;
11
+ }
12
+ try {
13
+ return JSON.parse(payload);
14
+ }
15
+ catch (_a) {
16
+ return null;
17
+ }
18
+ }
19
+ return payload;
20
+ };
4
21
  /**
5
22
  * Set a plain string value with optional TTL (seconds).
6
23
  */
@@ -64,19 +81,11 @@ const setJson = (key, value, ttlSec) => __awaiter(void 0, void 0, void 0, functi
64
81
  const getJson = (key) => __awaiter(void 0, void 0, void 0, function* () {
65
82
  return withRedis((redis) => __awaiter(void 0, void 0, void 0, function* () {
66
83
  const payload = yield redis.get(key);
67
- if (!payload) {
68
- return null;
69
- }
70
- try {
71
- return JSON.parse(payload);
72
- }
73
- catch (_a) {
74
- return null;
75
- }
84
+ return parseJsonPayload(payload);
76
85
  }));
77
86
  });
78
87
  /**
79
- * MGET JSON values stored as strings. Missing or invalid values are returned as null.
88
+ * MGET JSON values. Missing or invalid string values are returned as null.
80
89
  */
81
90
  const mgetJson = (keys) => __awaiter(void 0, void 0, void 0, function* () {
82
91
  return withRedis((redis) => __awaiter(void 0, void 0, void 0, function* () {
@@ -84,17 +93,7 @@ const mgetJson = (keys) => __awaiter(void 0, void 0, void 0, function* () {
84
93
  return [];
85
94
  }
86
95
  const payloads = yield redis.mget(...keys);
87
- return payloads.map((payload) => {
88
- if (!payload) {
89
- return null;
90
- }
91
- try {
92
- return JSON.parse(payload);
93
- }
94
- catch (_a) {
95
- return null;
96
- }
97
- });
96
+ return payloads.map((payload) => parseJsonPayload(payload));
98
97
  }));
99
98
  });
100
99
  /**
@@ -1,5 +1,9 @@
1
1
  import { Redis } from '@upstash/redis';
2
2
  import { Client as QstashClient } from '@upstash/qstash';
3
+ export declare const getPrefixedRedisKey: (key: string) => string;
4
+ export declare const getPrefixedRedisKeys: (keys: string[]) => string[];
5
+ export declare const getQstashNamePrefix: () => string;
6
+ export declare const getPrefixedQstashQueueName: (name: string) => string;
3
7
  /**
4
8
  * Get the Upstash Redis client. Returns null when required env vars are missing/invalid.
5
9
  *
@@ -1 +1 @@
1
- {"version":3,"file":"upstash-config.d.ts","sourceRoot":"","sources":["../../src/lib/upstash-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAwOzD;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,QAAO,KAAK,GAAG,IAEnC,CAAC;AAwDF;;;;;GAKG;AACH,eAAO,MAAM,SAAS,QAAO,YAAY,GAAG,IAE3C,CAAC;AAyCF,eAAO,MAAM,SAAS,GAAU,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,KAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAMzF,CAAC;AAEF,eAAO,MAAM,UAAU,GAAU,CAAC,EAChC,IAAI,CAAC,MAAM,EAAE,YAAY,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,KAC3C,OAAO,CAAC,CAAC,GAAG,IAAI,CAMlB,CAAC"}
1
+ {"version":3,"file":"upstash-config.d.ts","sourceRoot":"","sources":["../../src/lib/upstash-config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AACvC,OAAO,EAAE,MAAM,IAAI,YAAY,EAAE,MAAM,iBAAiB,CAAC;AA2DzD,eAAO,MAAM,mBAAmB,GAAI,KAAK,MAAM,KAAG,MAAyD,CAAC;AAE5G,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,EAAE,KAAG,MAAM,EAAmC,CAAC;AAEhG,eAAO,MAAM,mBAAmB,QAAO,MAEtC,CAAC;AAEF,eAAO,MAAM,0BAA0B,GAAI,MAAM,MAAM,KAAG,MAMzD,CAAC;AAiMF;;;;;GAKG;AACH,eAAO,MAAM,QAAQ,QAAO,KAAK,GAAG,IAEnC,CAAC;AAwDF;;;;;GAKG;AACH,eAAO,MAAM,SAAS,QAAO,YAAY,GAAG,IAE3C,CAAC;AA+CF,eAAO,MAAM,SAAS,GAAU,CAAC,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,KAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAMzF,CAAC;AAEF,eAAO,MAAM,UAAU,GAAU,CAAC,EAChC,IAAI,CAAC,MAAM,EAAE,YAAY,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,KAC3C,OAAO,CAAC,CAAC,GAAG,IAAI,CAMlB,CAAC"}
@@ -45,7 +45,19 @@ const getRedisKeyPrefix = () => {
45
45
  const envSuffix = process.env.NODE_ENV === 'production' ? 'live' : 'test';
46
46
  return `${getRequiredRedisAppName()}_${envSuffix}`;
47
47
  };
48
- const prefixRedisKey = (prefix, key) => `${prefix}:${key}`;
48
+ const buildPrefixedRedisKey = (prefix, key) => `${prefix}:${key}`;
49
+ const getPrefixedRedisKey = (key) => buildPrefixedRedisKey(getRedisKeyPrefix(), key);
50
+ const getPrefixedRedisKeys = (keys) => keys.map(getPrefixedRedisKey);
51
+ const getQstashNamePrefix = () => {
52
+ return getRedisKeyPrefix();
53
+ };
54
+ const getPrefixedQstashQueueName = (name) => {
55
+ if (!isNonEmpty(name)) {
56
+ throw new Error('[Upstash QStash] queue name must not be empty');
57
+ }
58
+ return `${getQstashNamePrefix()}_queue_${name}`;
59
+ };
60
+ const prefixRedisKey = (prefix, key) => buildPrefixedRedisKey(prefix, key);
49
61
  const prefixRedisKeys = (prefix, keys) => keys.map((key) => prefixRedisKey(prefix, key));
50
62
  const prefixFirstStringArg = (args, prefix) => {
51
63
  if (typeof args[0] !== 'string') {
@@ -55,8 +67,16 @@ const prefixFirstStringArg = (args, prefix) => {
55
67
  nextArgs[0] = prefixRedisKey(prefix, args[0]);
56
68
  return nextArgs;
57
69
  };
58
- const prefixAllStringArgs = (args, prefix) => {
59
- return args.map((arg) => (typeof arg === 'string' ? prefixRedisKey(prefix, arg) : arg));
70
+ const prefixVariadicKeyArgs = (args, prefix) => {
71
+ return args.flatMap((arg) => {
72
+ if (typeof arg === 'string') {
73
+ return [prefixRedisKey(prefix, arg)];
74
+ }
75
+ if (Array.isArray(arg) && arg.every((key) => typeof key === 'string')) {
76
+ return prefixRedisKeys(prefix, arg);
77
+ }
78
+ return [arg];
79
+ });
60
80
  };
61
81
  const keyArrayCommands = new Set(['mget', 'del']);
62
82
  const allStringKeyCommands = new Set(['exists']);
@@ -77,11 +97,11 @@ const createPrefixedPipeline = (target, prefix) => {
77
97
  return createPrefixedPipeline(nested, prefix);
78
98
  }
79
99
  if (typeof prop === 'string' && keyArrayCommands.has(prop)) {
80
- const nextArgs = prefixAllStringArgs(args, prefix);
100
+ const nextArgs = prefixVariadicKeyArgs(args, prefix);
81
101
  return value.apply(obj, nextArgs);
82
102
  }
83
103
  if (typeof prop === 'string' && allStringKeyCommands.has(prop)) {
84
- const nextArgs = prefixAllStringArgs(args, prefix);
104
+ const nextArgs = prefixVariadicKeyArgs(args, prefix);
85
105
  return value.apply(obj, nextArgs);
86
106
  }
87
107
  if (prop === 'mset') {
@@ -111,7 +131,10 @@ const parseMinutes = (value, fallback) => {
111
131
  };
112
132
  const getRedisHealthIntervalMinutes = () => parseMinutes(process.env.UPSTASH_REDIS_HEALTHCHECK_INTERVAL_MINUTES, 10);
113
133
  const getQstashHealthIntervalMinutes = () => parseMinutes(process.env.UPSTASH_QSTASH_HEALTHCHECK_INTERVAL_MINUTES, 10);
114
- const getQstashHealthcheckUrl = () => { var _a; return (_a = process.env.UPSTASH_QSTASH_HEALTHCHECK_URL) !== null && _a !== void 0 ? _a : 'https://qstash.upstash.io/v2/topics'; };
134
+ const getQstashHealthcheckUrl = () => {
135
+ const url = process.env.UPSTASH_QSTASH_HEALTHCHECK_URL;
136
+ return isNonEmpty(url) ? url : null;
137
+ };
115
138
  const scheduleRedisHealthCheck = () => {
116
139
  if (redisHealthTimer || !cachedRedis) {
117
140
  return;
@@ -148,7 +171,11 @@ const scheduleRedisHealthCheck = () => {
148
171
  }), delayMs);
149
172
  };
150
173
  const checkQstashHealth = (token) => tslib.__awaiter(void 0, void 0, void 0, function* () {
151
- const response = yield fetch(getQstashHealthcheckUrl(), {
174
+ const healthcheckUrl = getQstashHealthcheckUrl();
175
+ if (!healthcheckUrl) {
176
+ return;
177
+ }
178
+ const response = yield fetch(healthcheckUrl, {
152
179
  method: 'GET',
153
180
  headers: {
154
181
  Authorization: `Bearer ${token}`,
@@ -160,7 +187,7 @@ const checkQstashHealth = (token) => tslib.__awaiter(void 0, void 0, void 0, fun
160
187
  }
161
188
  });
162
189
  const scheduleQstashHealthCheck = (token) => {
163
- if (qstashHealthTimer || !cachedQstash) {
190
+ if (qstashHealthTimer || !cachedQstash || !getQstashHealthcheckUrl()) {
164
191
  return;
165
192
  }
166
193
  const delayMs = getQstashHealthIntervalMinutes() * 60000;
@@ -173,7 +200,6 @@ const scheduleQstashHealthCheck = (token) => {
173
200
  yield checkQstashHealth(token);
174
201
  }
175
202
  catch (error) {
176
- cachedQstash = null;
177
203
  if (!qstashWarnedHealthCheck) {
178
204
  qstashWarnedHealthCheck = true;
179
205
  const message = error instanceof Error ? error.message : String(error);
@@ -279,8 +305,14 @@ const ensureQstash = () => tslib.__awaiter(void 0, void 0, void 0, function* ()
279
305
  }
280
306
  try {
281
307
  const client = new qstash.Client({ token: QSTASH_TOKEN });
282
- yield checkQstashHealth(QSTASH_TOKEN);
283
308
  cachedQstash = client;
309
+ checkQstashHealth(QSTASH_TOKEN).catch((error) => {
310
+ if (!qstashWarnedHealthCheck) {
311
+ qstashWarnedHealthCheck = true;
312
+ const message = error instanceof Error ? error.message : String(error);
313
+ console.warn(`[Upstash Config] QStash health check failed: ${message}`);
314
+ }
315
+ });
284
316
  scheduleQstashHealthCheck(QSTASH_TOKEN);
285
317
  return cachedQstash;
286
318
  }
@@ -313,7 +345,11 @@ const withQstash = (fn) => tslib.__awaiter(void 0, void 0, void 0, function* ()
313
345
  return fn(qstash);
314
346
  });
315
347
 
348
+ exports.getPrefixedQstashQueueName = getPrefixedQstashQueueName;
349
+ exports.getPrefixedRedisKey = getPrefixedRedisKey;
350
+ exports.getPrefixedRedisKeys = getPrefixedRedisKeys;
316
351
  exports.getQstash = getQstash;
352
+ exports.getQstashNamePrefix = getQstashNamePrefix;
317
353
  exports.getRedis = getRedis;
318
354
  exports.withQstash = withQstash;
319
355
  exports.withRedis = withRedis;
@@ -43,7 +43,19 @@ const getRedisKeyPrefix = () => {
43
43
  const envSuffix = process.env.NODE_ENV === 'production' ? 'live' : 'test';
44
44
  return `${getRequiredRedisAppName()}_${envSuffix}`;
45
45
  };
46
- const prefixRedisKey = (prefix, key) => `${prefix}:${key}`;
46
+ const buildPrefixedRedisKey = (prefix, key) => `${prefix}:${key}`;
47
+ const getPrefixedRedisKey = (key) => buildPrefixedRedisKey(getRedisKeyPrefix(), key);
48
+ const getPrefixedRedisKeys = (keys) => keys.map(getPrefixedRedisKey);
49
+ const getQstashNamePrefix = () => {
50
+ return getRedisKeyPrefix();
51
+ };
52
+ const getPrefixedQstashQueueName = (name) => {
53
+ if (!isNonEmpty(name)) {
54
+ throw new Error('[Upstash QStash] queue name must not be empty');
55
+ }
56
+ return `${getQstashNamePrefix()}_queue_${name}`;
57
+ };
58
+ const prefixRedisKey = (prefix, key) => buildPrefixedRedisKey(prefix, key);
47
59
  const prefixRedisKeys = (prefix, keys) => keys.map((key) => prefixRedisKey(prefix, key));
48
60
  const prefixFirstStringArg = (args, prefix) => {
49
61
  if (typeof args[0] !== 'string') {
@@ -53,8 +65,16 @@ const prefixFirstStringArg = (args, prefix) => {
53
65
  nextArgs[0] = prefixRedisKey(prefix, args[0]);
54
66
  return nextArgs;
55
67
  };
56
- const prefixAllStringArgs = (args, prefix) => {
57
- return args.map((arg) => (typeof arg === 'string' ? prefixRedisKey(prefix, arg) : arg));
68
+ const prefixVariadicKeyArgs = (args, prefix) => {
69
+ return args.flatMap((arg) => {
70
+ if (typeof arg === 'string') {
71
+ return [prefixRedisKey(prefix, arg)];
72
+ }
73
+ if (Array.isArray(arg) && arg.every((key) => typeof key === 'string')) {
74
+ return prefixRedisKeys(prefix, arg);
75
+ }
76
+ return [arg];
77
+ });
58
78
  };
59
79
  const keyArrayCommands = new Set(['mget', 'del']);
60
80
  const allStringKeyCommands = new Set(['exists']);
@@ -75,11 +95,11 @@ const createPrefixedPipeline = (target, prefix) => {
75
95
  return createPrefixedPipeline(nested, prefix);
76
96
  }
77
97
  if (typeof prop === 'string' && keyArrayCommands.has(prop)) {
78
- const nextArgs = prefixAllStringArgs(args, prefix);
98
+ const nextArgs = prefixVariadicKeyArgs(args, prefix);
79
99
  return value.apply(obj, nextArgs);
80
100
  }
81
101
  if (typeof prop === 'string' && allStringKeyCommands.has(prop)) {
82
- const nextArgs = prefixAllStringArgs(args, prefix);
102
+ const nextArgs = prefixVariadicKeyArgs(args, prefix);
83
103
  return value.apply(obj, nextArgs);
84
104
  }
85
105
  if (prop === 'mset') {
@@ -109,7 +129,10 @@ const parseMinutes = (value, fallback) => {
109
129
  };
110
130
  const getRedisHealthIntervalMinutes = () => parseMinutes(process.env.UPSTASH_REDIS_HEALTHCHECK_INTERVAL_MINUTES, 10);
111
131
  const getQstashHealthIntervalMinutes = () => parseMinutes(process.env.UPSTASH_QSTASH_HEALTHCHECK_INTERVAL_MINUTES, 10);
112
- const getQstashHealthcheckUrl = () => { var _a; return (_a = process.env.UPSTASH_QSTASH_HEALTHCHECK_URL) !== null && _a !== void 0 ? _a : 'https://qstash.upstash.io/v2/topics'; };
132
+ const getQstashHealthcheckUrl = () => {
133
+ const url = process.env.UPSTASH_QSTASH_HEALTHCHECK_URL;
134
+ return isNonEmpty(url) ? url : null;
135
+ };
113
136
  const scheduleRedisHealthCheck = () => {
114
137
  if (redisHealthTimer || !cachedRedis) {
115
138
  return;
@@ -146,7 +169,11 @@ const scheduleRedisHealthCheck = () => {
146
169
  }), delayMs);
147
170
  };
148
171
  const checkQstashHealth = (token) => __awaiter(void 0, void 0, void 0, function* () {
149
- const response = yield fetch(getQstashHealthcheckUrl(), {
172
+ const healthcheckUrl = getQstashHealthcheckUrl();
173
+ if (!healthcheckUrl) {
174
+ return;
175
+ }
176
+ const response = yield fetch(healthcheckUrl, {
150
177
  method: 'GET',
151
178
  headers: {
152
179
  Authorization: `Bearer ${token}`,
@@ -158,7 +185,7 @@ const checkQstashHealth = (token) => __awaiter(void 0, void 0, void 0, function*
158
185
  }
159
186
  });
160
187
  const scheduleQstashHealthCheck = (token) => {
161
- if (qstashHealthTimer || !cachedQstash) {
188
+ if (qstashHealthTimer || !cachedQstash || !getQstashHealthcheckUrl()) {
162
189
  return;
163
190
  }
164
191
  const delayMs = getQstashHealthIntervalMinutes() * 60000;
@@ -171,7 +198,6 @@ const scheduleQstashHealthCheck = (token) => {
171
198
  yield checkQstashHealth(token);
172
199
  }
173
200
  catch (error) {
174
- cachedQstash = null;
175
201
  if (!qstashWarnedHealthCheck) {
176
202
  qstashWarnedHealthCheck = true;
177
203
  const message = error instanceof Error ? error.message : String(error);
@@ -277,8 +303,14 @@ const ensureQstash = () => __awaiter(void 0, void 0, void 0, function* () {
277
303
  }
278
304
  try {
279
305
  const client = new Client({ token: QSTASH_TOKEN });
280
- yield checkQstashHealth(QSTASH_TOKEN);
281
306
  cachedQstash = client;
307
+ checkQstashHealth(QSTASH_TOKEN).catch((error) => {
308
+ if (!qstashWarnedHealthCheck) {
309
+ qstashWarnedHealthCheck = true;
310
+ const message = error instanceof Error ? error.message : String(error);
311
+ console.warn(`[Upstash Config] QStash health check failed: ${message}`);
312
+ }
313
+ });
282
314
  scheduleQstashHealthCheck(QSTASH_TOKEN);
283
315
  return cachedQstash;
284
316
  }
@@ -311,4 +343,4 @@ const withQstash = (fn) => __awaiter(void 0, void 0, void 0, function* () {
311
343
  return fn(qstash);
312
344
  });
313
345
 
314
- export { getQstash, getRedis, withQstash, withRedis };
346
+ export { getPrefixedQstashQueueName, getPrefixedRedisKey, getPrefixedRedisKeys, getQstash, getQstashNamePrefix, getRedis, withQstash, withRedis };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@windrun-huaiin/backend-core",
3
- "version": "20.0.0",
3
+ "version": "20.1.0",
4
4
  "description": "Shared backend primitives: Prisma schema/client, database services, routing helpers",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,5 +1,5 @@
1
1
  import { Receiver } from '@upstash/qstash';
2
- import { withQstash } from '../upstash-config';
2
+ import { getPrefixedQstashQueueName, withQstash } from '../upstash-config';
3
3
 
4
4
  let cachedReceiver: Receiver | null = null;
5
5
  let receiverWarnedMissingEnv = false;
@@ -56,6 +56,17 @@ export interface PublishMessageOptions<TBody extends PublishBody = PublishBody>
56
56
  body: TBody;
57
57
  }
58
58
 
59
+ export interface PublishBroadcastMessageOptions<TBody extends PublishBody = PublishBody> {
60
+ urlGroup: string;
61
+ body: TBody;
62
+ }
63
+
64
+ export interface PublishFIFOQueueMessageOptions<TBody extends PublishBody = PublishBody> {
65
+ queueName: string;
66
+ url: string;
67
+ body: TBody;
68
+ }
69
+
59
70
  const generateSourceMessageId = (): string => {
60
71
  try {
61
72
  return crypto.randomUUID();
@@ -91,6 +102,69 @@ export const publishMessage = async <TBody extends PublishBody>(
91
102
  });
92
103
  };
93
104
 
105
+ /**
106
+ * Publish a broadcast message to a QStash URL Group.
107
+ * Returns message ids or null if QStash is unavailable.
108
+ */
109
+ export const publishBroadcastMessage = async <TBody extends PublishBody>(
110
+ options: PublishBroadcastMessageOptions<TBody>
111
+ ): Promise<{ messageIds: string[]; message: QstashEnvelope<TBody> } | null> => {
112
+ const message = createEnvelope(options.body);
113
+
114
+ return withQstash(async (client) => {
115
+ const result = await (client as any).publishJSON({
116
+ urlGroup: options.urlGroup,
117
+ body: message,
118
+ });
119
+
120
+ const messageIds = Array.isArray(result)
121
+ ? result
122
+ .map((item) =>
123
+ typeof item === 'string' ? item : typeof item?.messageId === 'string' ? item.messageId : null
124
+ )
125
+ .filter((messageId): messageId is string => typeof messageId === 'string')
126
+ : typeof result === 'string'
127
+ ? [result]
128
+ : typeof result?.messageId === 'string'
129
+ ? [result.messageId]
130
+ : [];
131
+
132
+ return {
133
+ messageIds,
134
+ message,
135
+ };
136
+ });
137
+ };
138
+
139
+ /**
140
+ * Publish a single-recipient message into a QStash FIFO queue.
141
+ * Returns message id or null if QStash is unavailable.
142
+ */
143
+ export const publishFIFOQueueMessage = async <TBody extends PublishBody>(
144
+ options: PublishFIFOQueueMessageOptions<TBody>
145
+ ): Promise<{ messageId: string | null; message: QstashEnvelope<TBody> } | null> => {
146
+ const message = createEnvelope(options.body);
147
+ const queueName = getPrefixedQstashQueueName(options.queueName);
148
+
149
+ return withQstash(async (client) => {
150
+ const anyClient = client as any;
151
+ const queueClient = anyClient.queue?.({ queueName });
152
+ if (!queueClient?.enqueueJSON) {
153
+ throw new Error('QStash queue enqueueJSON API is unavailable');
154
+ }
155
+
156
+ const result = await queueClient.enqueueJSON({
157
+ url: options.url,
158
+ body: message,
159
+ });
160
+
161
+ return {
162
+ messageId: typeof result === 'string' ? result : result?.messageId ?? null,
163
+ message,
164
+ };
165
+ });
166
+ };
167
+
94
168
  /**
95
169
  * Publish a delayed message. Returns message id or null if QStash is unavailable.
96
170
  */
@@ -9,6 +9,26 @@ export type RedisPipelineBuilder<TResult> = (pipeline: ReturnType<Redis['pipelin
9
9
  exec: () => Promise<TResult>;
10
10
  };
11
11
 
12
+ const parseJsonPayload = <T>(payload: unknown): T | null => {
13
+ if (payload == null) {
14
+ return null;
15
+ }
16
+
17
+ if (typeof payload === 'string') {
18
+ if (!payload) {
19
+ return null;
20
+ }
21
+
22
+ try {
23
+ return JSON.parse(payload) as T;
24
+ } catch {
25
+ return null;
26
+ }
27
+ }
28
+
29
+ return payload as T;
30
+ };
31
+
12
32
  /**
13
33
  * Set a plain string value with optional TTL (seconds).
14
34
  */
@@ -88,21 +108,13 @@ export const setJson = async <T>(
88
108
  */
89
109
  export const getJson = async <T>(key: string): Promise<T | null> => {
90
110
  return withRedis(async (redis) => {
91
- const payload = await redis.get<string>(key);
92
- if (!payload) {
93
- return null;
94
- }
95
-
96
- try {
97
- return JSON.parse(payload) as T;
98
- } catch {
99
- return null;
100
- }
111
+ const payload = await redis.get<unknown>(key);
112
+ return parseJsonPayload<T>(payload);
101
113
  });
102
114
  };
103
115
 
104
116
  /**
105
- * MGET JSON values stored as strings. Missing or invalid values are returned as null.
117
+ * MGET JSON values. Missing or invalid string values are returned as null.
106
118
  */
107
119
  export const mgetJson = async <T>(keys: string[]): Promise<(T | null)[] | null> => {
108
120
  return withRedis(async (redis) => {
@@ -110,18 +122,8 @@ export const mgetJson = async <T>(keys: string[]): Promise<(T | null)[] | null>
110
122
  return [];
111
123
  }
112
124
 
113
- const payloads = await redis.mget<(string | null)[]>(...keys);
114
- return payloads.map((payload) => {
115
- if (!payload) {
116
- return null;
117
- }
118
-
119
- try {
120
- return JSON.parse(payload) as T;
121
- } catch {
122
- return null;
123
- }
124
- });
125
+ const payloads = await redis.mget<unknown[]>(...keys);
126
+ return payloads.map((payload) => parseJsonPayload<T>(payload));
125
127
  });
126
128
  };
127
129
 
@@ -56,7 +56,25 @@ const getRedisKeyPrefix = (): string => {
56
56
  return `${getRequiredRedisAppName()}_${envSuffix}`;
57
57
  };
58
58
 
59
- const prefixRedisKey = (prefix: string, key: string): string => `${prefix}:${key}`;
59
+ const buildPrefixedRedisKey = (prefix: string, key: string): string => `${prefix}:${key}`;
60
+
61
+ export const getPrefixedRedisKey = (key: string): string => buildPrefixedRedisKey(getRedisKeyPrefix(), key);
62
+
63
+ export const getPrefixedRedisKeys = (keys: string[]): string[] => keys.map(getPrefixedRedisKey);
64
+
65
+ export const getQstashNamePrefix = (): string => {
66
+ return getRedisKeyPrefix();
67
+ };
68
+
69
+ export const getPrefixedQstashQueueName = (name: string): string => {
70
+ if (!isNonEmpty(name)) {
71
+ throw new Error('[Upstash QStash] queue name must not be empty');
72
+ }
73
+
74
+ return `${getQstashNamePrefix()}_queue_${name}`;
75
+ };
76
+
77
+ const prefixRedisKey = (prefix: string, key: string): string => buildPrefixedRedisKey(prefix, key);
60
78
 
61
79
  const prefixRedisKeys = (prefix: string, keys: string[]): string[] =>
62
80
  keys.map((key) => prefixRedisKey(prefix, key));
@@ -71,8 +89,18 @@ const prefixFirstStringArg = (args: unknown[], prefix: string): unknown[] => {
71
89
  return nextArgs;
72
90
  };
73
91
 
74
- const prefixAllStringArgs = (args: unknown[], prefix: string): unknown[] => {
75
- return args.map((arg) => (typeof arg === 'string' ? prefixRedisKey(prefix, arg) : arg));
92
+ const prefixVariadicKeyArgs = (args: unknown[], prefix: string): unknown[] => {
93
+ return args.flatMap((arg) => {
94
+ if (typeof arg === 'string') {
95
+ return [prefixRedisKey(prefix, arg)];
96
+ }
97
+
98
+ if (Array.isArray(arg) && arg.every((key) => typeof key === 'string')) {
99
+ return prefixRedisKeys(prefix, arg);
100
+ }
101
+
102
+ return [arg];
103
+ });
76
104
  };
77
105
 
78
106
  const keyArrayCommands = new Set(['mget', 'del']);
@@ -103,12 +131,12 @@ const createPrefixedPipeline = <T extends object>(target: T, prefix: string): T
103
131
  }
104
132
 
105
133
  if (typeof prop === 'string' && keyArrayCommands.has(prop)) {
106
- const nextArgs = prefixAllStringArgs(args, prefix);
134
+ const nextArgs = prefixVariadicKeyArgs(args, prefix);
107
135
  return (value as (...innerArgs: unknown[]) => unknown).apply(obj, nextArgs);
108
136
  }
109
137
 
110
138
  if (typeof prop === 'string' && allStringKeyCommands.has(prop)) {
111
- const nextArgs = prefixAllStringArgs(args, prefix);
139
+ const nextArgs = prefixVariadicKeyArgs(args, prefix);
112
140
  return (value as (...innerArgs: unknown[]) => unknown).apply(obj, nextArgs);
113
141
  }
114
142
 
@@ -149,8 +177,10 @@ const getRedisHealthIntervalMinutes = (): number =>
149
177
  const getQstashHealthIntervalMinutes = (): number =>
150
178
  parseMinutes(process.env.UPSTASH_QSTASH_HEALTHCHECK_INTERVAL_MINUTES, 10);
151
179
 
152
- const getQstashHealthcheckUrl = (): string =>
153
- process.env.UPSTASH_QSTASH_HEALTHCHECK_URL ?? 'https://qstash.upstash.io/v2/topics';
180
+ const getQstashHealthcheckUrl = (): string | null => {
181
+ const url = process.env.UPSTASH_QSTASH_HEALTHCHECK_URL;
182
+ return isNonEmpty(url) ? url : null;
183
+ };
154
184
 
155
185
  const scheduleRedisHealthCheck = (): void => {
156
186
  if (redisHealthTimer || !cachedRedis) {
@@ -186,7 +216,12 @@ const scheduleRedisHealthCheck = (): void => {
186
216
  };
187
217
 
188
218
  const checkQstashHealth = async (token: string): Promise<void> => {
189
- const response = await fetch(getQstashHealthcheckUrl(), {
219
+ const healthcheckUrl = getQstashHealthcheckUrl();
220
+ if (!healthcheckUrl) {
221
+ return;
222
+ }
223
+
224
+ const response = await fetch(healthcheckUrl, {
190
225
  method: 'GET',
191
226
  headers: {
192
227
  Authorization: `Bearer ${token}`,
@@ -199,7 +234,7 @@ const checkQstashHealth = async (token: string): Promise<void> => {
199
234
  };
200
235
 
201
236
  const scheduleQstashHealthCheck = (token: string): void => {
202
- if (qstashHealthTimer || !cachedQstash) {
237
+ if (qstashHealthTimer || !cachedQstash || !getQstashHealthcheckUrl()) {
203
238
  return;
204
239
  }
205
240
  const delayMs = getQstashHealthIntervalMinutes() * 60_000;
@@ -211,7 +246,6 @@ const scheduleQstashHealthCheck = (token: string): void => {
211
246
  try {
212
247
  await checkQstashHealth(token);
213
248
  } catch (error) {
214
- cachedQstash = null;
215
249
  if (!qstashWarnedHealthCheck) {
216
250
  qstashWarnedHealthCheck = true;
217
251
  const message = error instanceof Error ? error.message : String(error);
@@ -325,8 +359,14 @@ const ensureQstash = async (): Promise<QstashClient | null> => {
325
359
 
326
360
  try {
327
361
  const client = new QstashClient({ token: QSTASH_TOKEN });
328
- await checkQstashHealth(QSTASH_TOKEN);
329
362
  cachedQstash = client;
363
+ checkQstashHealth(QSTASH_TOKEN).catch((error) => {
364
+ if (!qstashWarnedHealthCheck) {
365
+ qstashWarnedHealthCheck = true;
366
+ const message = error instanceof Error ? error.message : String(error);
367
+ console.warn(`[Upstash Config] QStash health check failed: ${message}`);
368
+ }
369
+ });
330
370
  scheduleQstashHealthCheck(QSTASH_TOKEN);
331
371
  return cachedQstash;
332
372
  } catch (error) {