@horizon-republic/nestjs-jetstream 2.12.0 → 2.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +30 -40
- package/dist/index.d.cts +7 -15
- package/dist/index.d.ts +7 -15
- package/dist/index.js +30 -40
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -598,7 +598,7 @@ var extractContext = (ctx, carrier, getter) => import_api.propagation.extract(ct
|
|
|
598
598
|
|
|
599
599
|
// src/otel/tracer.ts
|
|
600
600
|
var import_api2 = require("@opentelemetry/api");
|
|
601
|
-
var PACKAGE_VERSION = true ? "2.12.
|
|
601
|
+
var PACKAGE_VERSION = true ? "2.12.1" : "0.0.0";
|
|
602
602
|
var getTracer = () => import_api2.trace.getTracer(TRACER_NAME, PACKAGE_VERSION);
|
|
603
603
|
|
|
604
604
|
// src/otel/carrier.ts
|
|
@@ -3880,11 +3880,8 @@ var StreamMigration = class {
|
|
|
3880
3880
|
);
|
|
3881
3881
|
}
|
|
3882
3882
|
/**
|
|
3883
|
-
*
|
|
3884
|
-
*
|
|
3885
|
-
* live migration is left alone.
|
|
3886
|
-
*
|
|
3887
|
-
* @returns true when recovery work was performed.
|
|
3883
|
+
* Finish a migration a previous process left unfinished; a backup fresh
|
|
3884
|
+
* enough to belong to a live peer migration is left alone.
|
|
3888
3885
|
*/
|
|
3889
3886
|
async recoverInterrupted(jsm, streamName2, desiredConfig) {
|
|
3890
3887
|
const backupName = `${streamName2}${MIGRATION_BACKUP_SUFFIX}`;
|
|
@@ -3938,11 +3935,9 @@ var StreamMigration = class {
|
|
|
3938
3935
|
await jsm.streams.update(streamName2, { ...streamConfig, sources: [] });
|
|
3939
3936
|
}
|
|
3940
3937
|
/**
|
|
3941
|
-
*
|
|
3942
|
-
*
|
|
3943
|
-
*
|
|
3944
|
-
* `lag: 0, active: -1` before its first sync — `active >= 0` filters that
|
|
3945
|
-
* false positive out (verified against NATS 2.12.6).
|
|
3938
|
+
* Lag-based drain check — live publishes cannot fake completion. A fresh
|
|
3939
|
+
* source reports lag 0 / active -1 before its first sync (NATS 2.12.6),
|
|
3940
|
+
* hence the active guard.
|
|
3946
3941
|
*/
|
|
3947
3942
|
async waitForSourceDrained(jsm, streamName2, sourceName, minimumMessages) {
|
|
3948
3943
|
const deadline = Date.now() + this.sourcingTimeoutMs;
|
|
@@ -3959,12 +3954,8 @@ var StreamMigration = class {
|
|
|
3959
3954
|
);
|
|
3960
3955
|
}
|
|
3961
3956
|
/**
|
|
3962
|
-
* A backup
|
|
3963
|
-
*
|
|
3964
|
-
* Stale leftovers are handled by recoverInterrupted() before migrate() runs,
|
|
3965
|
-
* so a timeout here means something is genuinely stuck.
|
|
3966
|
-
*
|
|
3967
|
-
* @returns true when a peer's backup was observed and cleared.
|
|
3957
|
+
* A backup present at migrate() start is a live peer migration — wait it
|
|
3958
|
+
* out. Stale leftovers were already handled by recoverInterrupted().
|
|
3968
3959
|
*/
|
|
3969
3960
|
async waitOutPeerMigration(jsm, backupName) {
|
|
3970
3961
|
if (await this.tryInfo(jsm, backupName) === null) return false;
|
|
@@ -4015,6 +4006,17 @@ var StreamMigration = class {
|
|
|
4015
4006
|
};
|
|
4016
4007
|
|
|
4017
4008
|
// src/server/infrastructure/stream.provider.ts
|
|
4009
|
+
var subjectCovers = (broad, narrow) => {
|
|
4010
|
+
if (broad === narrow) return false;
|
|
4011
|
+
const broadTokens = broad.split(".");
|
|
4012
|
+
const narrowTokens = narrow.split(".");
|
|
4013
|
+
for (let i = 0; i < broadTokens.length; i += 1) {
|
|
4014
|
+
if (broadTokens[i] === ">") return i < narrowTokens.length;
|
|
4015
|
+
if (i >= narrowTokens.length || narrowTokens[i] === ">") return false;
|
|
4016
|
+
if (broadTokens[i] !== "*" && broadTokens[i] !== narrowTokens[i]) return false;
|
|
4017
|
+
}
|
|
4018
|
+
return broadTokens.length === narrowTokens.length;
|
|
4019
|
+
};
|
|
4018
4020
|
var StreamProvider = class {
|
|
4019
4021
|
constructor(options, connection) {
|
|
4020
4022
|
this.options = options;
|
|
@@ -4069,13 +4071,8 @@ ${formatProvisioningSummary(this.options.name, reservations)}`);
|
|
|
4069
4071
|
}
|
|
4070
4072
|
case "cmd" /* Command */:
|
|
4071
4073
|
return [`${name}.${"cmd" /* Command */}.>`];
|
|
4072
|
-
case "broadcast" /* Broadcast */:
|
|
4073
|
-
|
|
4074
|
-
if (this.isSchedulingEnabled(kind)) {
|
|
4075
|
-
subjects.push("broadcast._sch.>");
|
|
4076
|
-
}
|
|
4077
|
-
return subjects;
|
|
4078
|
-
}
|
|
4074
|
+
case "broadcast" /* Broadcast */:
|
|
4075
|
+
return ["broadcast.>"];
|
|
4079
4076
|
case "ordered" /* Ordered */:
|
|
4080
4077
|
return [`${name}.${"ordered" /* Ordered */}.>`];
|
|
4081
4078
|
}
|
|
@@ -4145,7 +4142,8 @@ ${formatProvisioningSummary(this.options.name, reservations)}`);
|
|
|
4145
4142
|
}
|
|
4146
4143
|
async handleExistingStream(jsm, currentInfo, config, ctx) {
|
|
4147
4144
|
if (this.isSharedStream(config.name)) {
|
|
4148
|
-
|
|
4145
|
+
const merged = [.../* @__PURE__ */ new Set([...config.subjects, ...currentInfo.config.subjects])];
|
|
4146
|
+
config.subjects = merged.filter((s) => !merged.some((other) => subjectCovers(other, s)));
|
|
4149
4147
|
}
|
|
4150
4148
|
const diff = compareStreamConfig(currentInfo.config, config);
|
|
4151
4149
|
if (!diff.hasChanges) {
|
|
@@ -5353,11 +5351,8 @@ var EventRouter = class {
|
|
|
5353
5351
|
return void 0;
|
|
5354
5352
|
}
|
|
5355
5353
|
/**
|
|
5356
|
-
* Last
|
|
5357
|
-
*
|
|
5358
|
-
* never redelivers past `max_deliver` — it stays in the stream for manual
|
|
5359
|
-
* recovery. Used when the DLQ stream isn't configured, or when publishing
|
|
5360
|
-
* to it failed and we still have to surface the message somewhere.
|
|
5354
|
+
* Last resort: invoke onDeadLetter, then term on success. On failure the
|
|
5355
|
+
* message is nak'd — never redelivered past max_deliver, but preserved.
|
|
5361
5356
|
*/
|
|
5362
5357
|
async fallbackToOnDeadLetterCallback(info, msg) {
|
|
5363
5358
|
const onDeadLetter = this.deadLetterConfig?.onDeadLetter;
|
|
@@ -5386,10 +5381,8 @@ var EventRouter = class {
|
|
|
5386
5381
|
}
|
|
5387
5382
|
}
|
|
5388
5383
|
/**
|
|
5389
|
-
* Copy
|
|
5390
|
-
*
|
|
5391
|
-
* the publish rejected when the DLQ stream has no allow_msg_ttl), a copied
|
|
5392
|
-
* Nats-Msg-Id collides with the DLQ dedup window.
|
|
5384
|
+
* Copy headers for the DLQ republish, dropping NATS control headers — a
|
|
5385
|
+
* copied Nats-TTL would expire the DLQ entry, Nats-Msg-Id trips dedup.
|
|
5393
5386
|
*/
|
|
5394
5387
|
buildDlqHeaders(msg) {
|
|
5395
5388
|
const hdrs = (0, import_transport_node4.headers)();
|
|
@@ -5403,12 +5396,9 @@ var EventRouter = class {
|
|
|
5403
5396
|
return hdrs;
|
|
5404
5397
|
}
|
|
5405
5398
|
/**
|
|
5406
|
-
*
|
|
5407
|
-
*
|
|
5408
|
-
*
|
|
5409
|
-
* the only second chance a dead letter gets. There is no artificial delay
|
|
5410
|
-
* between attempts: when the broker is unreachable each publish already
|
|
5411
|
-
* spends its own request timeout, which spaces the attempts naturally.
|
|
5399
|
+
* Past max_deliver the server never redelivers, so these in-process attempts
|
|
5400
|
+
* are the only second chance a dead letter gets. No artificial delay — an
|
|
5401
|
+
* unreachable broker already spaces attempts via its own request timeout.
|
|
5412
5402
|
*/
|
|
5413
5403
|
async publishToDlqWithRetry(connection, subject, data, headers2) {
|
|
5414
5404
|
let lastErr;
|
package/dist/index.d.cts
CHANGED
|
@@ -1532,27 +1532,19 @@ declare class EventRouter {
|
|
|
1532
1532
|
private getConcurrency;
|
|
1533
1533
|
private getAckExtensionConfig;
|
|
1534
1534
|
/**
|
|
1535
|
-
* Last
|
|
1536
|
-
*
|
|
1537
|
-
* never redelivers past `max_deliver` — it stays in the stream for manual
|
|
1538
|
-
* recovery. Used when the DLQ stream isn't configured, or when publishing
|
|
1539
|
-
* to it failed and we still have to surface the message somewhere.
|
|
1535
|
+
* Last resort: invoke onDeadLetter, then term on success. On failure the
|
|
1536
|
+
* message is nak'd — never redelivered past max_deliver, but preserved.
|
|
1540
1537
|
*/
|
|
1541
1538
|
private fallbackToOnDeadLetterCallback;
|
|
1542
1539
|
/**
|
|
1543
|
-
* Copy
|
|
1544
|
-
*
|
|
1545
|
-
* the publish rejected when the DLQ stream has no allow_msg_ttl), a copied
|
|
1546
|
-
* Nats-Msg-Id collides with the DLQ dedup window.
|
|
1540
|
+
* Copy headers for the DLQ republish, dropping NATS control headers — a
|
|
1541
|
+
* copied Nats-TTL would expire the DLQ entry, Nats-Msg-Id trips dedup.
|
|
1547
1542
|
*/
|
|
1548
1543
|
private buildDlqHeaders;
|
|
1549
1544
|
/**
|
|
1550
|
-
*
|
|
1551
|
-
*
|
|
1552
|
-
*
|
|
1553
|
-
* the only second chance a dead letter gets. There is no artificial delay
|
|
1554
|
-
* between attempts: when the broker is unreachable each publish already
|
|
1555
|
-
* spends its own request timeout, which spaces the attempts naturally.
|
|
1545
|
+
* Past max_deliver the server never redelivers, so these in-process attempts
|
|
1546
|
+
* are the only second chance a dead letter gets. No artificial delay — an
|
|
1547
|
+
* unreachable broker already spaces attempts via its own request timeout.
|
|
1556
1548
|
*/
|
|
1557
1549
|
private publishToDlqWithRetry;
|
|
1558
1550
|
/**
|
package/dist/index.d.ts
CHANGED
|
@@ -1532,27 +1532,19 @@ declare class EventRouter {
|
|
|
1532
1532
|
private getConcurrency;
|
|
1533
1533
|
private getAckExtensionConfig;
|
|
1534
1534
|
/**
|
|
1535
|
-
* Last
|
|
1536
|
-
*
|
|
1537
|
-
* never redelivers past `max_deliver` — it stays in the stream for manual
|
|
1538
|
-
* recovery. Used when the DLQ stream isn't configured, or when publishing
|
|
1539
|
-
* to it failed and we still have to surface the message somewhere.
|
|
1535
|
+
* Last resort: invoke onDeadLetter, then term on success. On failure the
|
|
1536
|
+
* message is nak'd — never redelivered past max_deliver, but preserved.
|
|
1540
1537
|
*/
|
|
1541
1538
|
private fallbackToOnDeadLetterCallback;
|
|
1542
1539
|
/**
|
|
1543
|
-
* Copy
|
|
1544
|
-
*
|
|
1545
|
-
* the publish rejected when the DLQ stream has no allow_msg_ttl), a copied
|
|
1546
|
-
* Nats-Msg-Id collides with the DLQ dedup window.
|
|
1540
|
+
* Copy headers for the DLQ republish, dropping NATS control headers — a
|
|
1541
|
+
* copied Nats-TTL would expire the DLQ entry, Nats-Msg-Id trips dedup.
|
|
1547
1542
|
*/
|
|
1548
1543
|
private buildDlqHeaders;
|
|
1549
1544
|
/**
|
|
1550
|
-
*
|
|
1551
|
-
*
|
|
1552
|
-
*
|
|
1553
|
-
* the only second chance a dead letter gets. There is no artificial delay
|
|
1554
|
-
* between attempts: when the broker is unreachable each publish already
|
|
1555
|
-
* spends its own request timeout, which spaces the attempts naturally.
|
|
1545
|
+
* Past max_deliver the server never redelivers, so these in-process attempts
|
|
1546
|
+
* are the only second chance a dead letter gets. No artificial delay — an
|
|
1547
|
+
* unreachable broker already spaces attempts via its own request timeout.
|
|
1556
1548
|
*/
|
|
1557
1549
|
private publishToDlqWithRetry;
|
|
1558
1550
|
/**
|
package/dist/index.js
CHANGED
|
@@ -533,7 +533,7 @@ var extractContext = (ctx, carrier, getter) => propagation.extract(ctx, carrier,
|
|
|
533
533
|
|
|
534
534
|
// src/otel/tracer.ts
|
|
535
535
|
import { trace } from "@opentelemetry/api";
|
|
536
|
-
var PACKAGE_VERSION = true ? "2.12.
|
|
536
|
+
var PACKAGE_VERSION = true ? "2.12.1" : "0.0.0";
|
|
537
537
|
var getTracer = () => trace.getTracer(TRACER_NAME, PACKAGE_VERSION);
|
|
538
538
|
|
|
539
539
|
// src/otel/carrier.ts
|
|
@@ -3842,11 +3842,8 @@ var StreamMigration = class {
|
|
|
3842
3842
|
);
|
|
3843
3843
|
}
|
|
3844
3844
|
/**
|
|
3845
|
-
*
|
|
3846
|
-
*
|
|
3847
|
-
* live migration is left alone.
|
|
3848
|
-
*
|
|
3849
|
-
* @returns true when recovery work was performed.
|
|
3845
|
+
* Finish a migration a previous process left unfinished; a backup fresh
|
|
3846
|
+
* enough to belong to a live peer migration is left alone.
|
|
3850
3847
|
*/
|
|
3851
3848
|
async recoverInterrupted(jsm, streamName2, desiredConfig) {
|
|
3852
3849
|
const backupName = `${streamName2}${MIGRATION_BACKUP_SUFFIX}`;
|
|
@@ -3900,11 +3897,9 @@ var StreamMigration = class {
|
|
|
3900
3897
|
await jsm.streams.update(streamName2, { ...streamConfig, sources: [] });
|
|
3901
3898
|
}
|
|
3902
3899
|
/**
|
|
3903
|
-
*
|
|
3904
|
-
*
|
|
3905
|
-
*
|
|
3906
|
-
* `lag: 0, active: -1` before its first sync — `active >= 0` filters that
|
|
3907
|
-
* false positive out (verified against NATS 2.12.6).
|
|
3900
|
+
* Lag-based drain check — live publishes cannot fake completion. A fresh
|
|
3901
|
+
* source reports lag 0 / active -1 before its first sync (NATS 2.12.6),
|
|
3902
|
+
* hence the active guard.
|
|
3908
3903
|
*/
|
|
3909
3904
|
async waitForSourceDrained(jsm, streamName2, sourceName, minimumMessages) {
|
|
3910
3905
|
const deadline = Date.now() + this.sourcingTimeoutMs;
|
|
@@ -3921,12 +3916,8 @@ var StreamMigration = class {
|
|
|
3921
3916
|
);
|
|
3922
3917
|
}
|
|
3923
3918
|
/**
|
|
3924
|
-
* A backup
|
|
3925
|
-
*
|
|
3926
|
-
* Stale leftovers are handled by recoverInterrupted() before migrate() runs,
|
|
3927
|
-
* so a timeout here means something is genuinely stuck.
|
|
3928
|
-
*
|
|
3929
|
-
* @returns true when a peer's backup was observed and cleared.
|
|
3919
|
+
* A backup present at migrate() start is a live peer migration — wait it
|
|
3920
|
+
* out. Stale leftovers were already handled by recoverInterrupted().
|
|
3930
3921
|
*/
|
|
3931
3922
|
async waitOutPeerMigration(jsm, backupName) {
|
|
3932
3923
|
if (await this.tryInfo(jsm, backupName) === null) return false;
|
|
@@ -3977,6 +3968,17 @@ var StreamMigration = class {
|
|
|
3977
3968
|
};
|
|
3978
3969
|
|
|
3979
3970
|
// src/server/infrastructure/stream.provider.ts
|
|
3971
|
+
var subjectCovers = (broad, narrow) => {
|
|
3972
|
+
if (broad === narrow) return false;
|
|
3973
|
+
const broadTokens = broad.split(".");
|
|
3974
|
+
const narrowTokens = narrow.split(".");
|
|
3975
|
+
for (let i = 0; i < broadTokens.length; i += 1) {
|
|
3976
|
+
if (broadTokens[i] === ">") return i < narrowTokens.length;
|
|
3977
|
+
if (i >= narrowTokens.length || narrowTokens[i] === ">") return false;
|
|
3978
|
+
if (broadTokens[i] !== "*" && broadTokens[i] !== narrowTokens[i]) return false;
|
|
3979
|
+
}
|
|
3980
|
+
return broadTokens.length === narrowTokens.length;
|
|
3981
|
+
};
|
|
3980
3982
|
var StreamProvider = class {
|
|
3981
3983
|
constructor(options, connection) {
|
|
3982
3984
|
this.options = options;
|
|
@@ -4031,13 +4033,8 @@ ${formatProvisioningSummary(this.options.name, reservations)}`);
|
|
|
4031
4033
|
}
|
|
4032
4034
|
case "cmd" /* Command */:
|
|
4033
4035
|
return [`${name}.${"cmd" /* Command */}.>`];
|
|
4034
|
-
case "broadcast" /* Broadcast */:
|
|
4035
|
-
|
|
4036
|
-
if (this.isSchedulingEnabled(kind)) {
|
|
4037
|
-
subjects.push("broadcast._sch.>");
|
|
4038
|
-
}
|
|
4039
|
-
return subjects;
|
|
4040
|
-
}
|
|
4036
|
+
case "broadcast" /* Broadcast */:
|
|
4037
|
+
return ["broadcast.>"];
|
|
4041
4038
|
case "ordered" /* Ordered */:
|
|
4042
4039
|
return [`${name}.${"ordered" /* Ordered */}.>`];
|
|
4043
4040
|
}
|
|
@@ -4107,7 +4104,8 @@ ${formatProvisioningSummary(this.options.name, reservations)}`);
|
|
|
4107
4104
|
}
|
|
4108
4105
|
async handleExistingStream(jsm, currentInfo, config, ctx) {
|
|
4109
4106
|
if (this.isSharedStream(config.name)) {
|
|
4110
|
-
|
|
4107
|
+
const merged = [.../* @__PURE__ */ new Set([...config.subjects, ...currentInfo.config.subjects])];
|
|
4108
|
+
config.subjects = merged.filter((s) => !merged.some((other) => subjectCovers(other, s)));
|
|
4111
4109
|
}
|
|
4112
4110
|
const diff = compareStreamConfig(currentInfo.config, config);
|
|
4113
4111
|
if (!diff.hasChanges) {
|
|
@@ -5324,11 +5322,8 @@ var EventRouter = class {
|
|
|
5324
5322
|
return void 0;
|
|
5325
5323
|
}
|
|
5326
5324
|
/**
|
|
5327
|
-
* Last
|
|
5328
|
-
*
|
|
5329
|
-
* never redelivers past `max_deliver` — it stays in the stream for manual
|
|
5330
|
-
* recovery. Used when the DLQ stream isn't configured, or when publishing
|
|
5331
|
-
* to it failed and we still have to surface the message somewhere.
|
|
5325
|
+
* Last resort: invoke onDeadLetter, then term on success. On failure the
|
|
5326
|
+
* message is nak'd — never redelivered past max_deliver, but preserved.
|
|
5332
5327
|
*/
|
|
5333
5328
|
async fallbackToOnDeadLetterCallback(info, msg) {
|
|
5334
5329
|
const onDeadLetter = this.deadLetterConfig?.onDeadLetter;
|
|
@@ -5357,10 +5352,8 @@ var EventRouter = class {
|
|
|
5357
5352
|
}
|
|
5358
5353
|
}
|
|
5359
5354
|
/**
|
|
5360
|
-
* Copy
|
|
5361
|
-
*
|
|
5362
|
-
* the publish rejected when the DLQ stream has no allow_msg_ttl), a copied
|
|
5363
|
-
* Nats-Msg-Id collides with the DLQ dedup window.
|
|
5355
|
+
* Copy headers for the DLQ republish, dropping NATS control headers — a
|
|
5356
|
+
* copied Nats-TTL would expire the DLQ entry, Nats-Msg-Id trips dedup.
|
|
5364
5357
|
*/
|
|
5365
5358
|
buildDlqHeaders(msg) {
|
|
5366
5359
|
const hdrs = natsHeaders3();
|
|
@@ -5374,12 +5367,9 @@ var EventRouter = class {
|
|
|
5374
5367
|
return hdrs;
|
|
5375
5368
|
}
|
|
5376
5369
|
/**
|
|
5377
|
-
*
|
|
5378
|
-
*
|
|
5379
|
-
*
|
|
5380
|
-
* the only second chance a dead letter gets. There is no artificial delay
|
|
5381
|
-
* between attempts: when the broker is unreachable each publish already
|
|
5382
|
-
* spends its own request timeout, which spaces the attempts naturally.
|
|
5370
|
+
* Past max_deliver the server never redelivers, so these in-process attempts
|
|
5371
|
+
* are the only second chance a dead letter gets. No artificial delay — an
|
|
5372
|
+
* unreachable broker already spaces attempts via its own request timeout.
|
|
5383
5373
|
*/
|
|
5384
5374
|
async publishToDlqWithRetry(connection, subject, data, headers2) {
|
|
5385
5375
|
let lastErr;
|
package/package.json
CHANGED