@blamejs/core 0.7.4 → 0.7.18
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/CHANGELOG.md +423 -395
- package/README.md +150 -149
- package/bin/blamejs.js +0 -0
- package/index.js +308 -284
- package/lib/api-key.js +660 -663
- package/lib/api-snapshot.js +338 -338
- package/lib/app-shutdown.js +385 -385
- package/lib/app.js +365 -365
- package/lib/archive.js +250 -250
- package/lib/atomic-file.js +544 -544
- package/lib/audit-chain.js +177 -177
- package/lib/audit-sign.js +344 -344
- package/lib/audit-tools.js +677 -677
- package/lib/audit.js +766 -766
- package/lib/auth/jwt.js +311 -311
- package/lib/auth/lockout.js +436 -436
- package/lib/auth/oauth.js +721 -721
- package/lib/auth/passkey.js +181 -181
- package/lib/auth/password.js +594 -594
- package/lib/backup/bundle.js +217 -217
- package/lib/backup/crypto.js +176 -176
- package/lib/backup/index.js +515 -515
- package/lib/backup/manifest.js +282 -282
- package/lib/break-glass.js +1338 -1338
- package/lib/bundler.js +441 -441
- package/lib/cache-redis.js +256 -256
- package/lib/cache.js +1206 -1206
- package/lib/canonical-json.js +115 -115
- package/lib/chain-writer.js +234 -234
- package/lib/cli-helpers.js +206 -206
- package/lib/cli.js +2334 -2334
- package/lib/cluster-provider-db.js +317 -317
- package/lib/cluster-storage.js +226 -226
- package/lib/cluster.js +703 -703
- package/lib/codepoint-class.js +196 -0
- package/lib/config-drift.js +301 -301
- package/lib/consent.js +222 -222
- package/lib/constants.js +191 -191
- package/lib/cookies.js +315 -315
- package/lib/credential-hash.js +322 -322
- package/lib/crypto.js +266 -266
- package/lib/csv.js +275 -286
- package/lib/db-declare-row-policy.js +267 -267
- package/lib/db-declare-view.js +420 -421
- package/lib/db-query.js +406 -406
- package/lib/db-schema.js +319 -319
- package/lib/db.js +1288 -1288
- package/lib/deprecate.js +222 -222
- package/lib/dev.js +335 -335
- package/lib/dual-control.js +473 -473
- package/lib/error-page.js +420 -420
- package/lib/external-db-migrate.js +441 -441
- package/lib/external-db.js +1061 -1061
- package/lib/file-type.js +273 -273
- package/lib/file-upload.js +213 -10
- package/lib/forms.js +422 -422
- package/lib/framework-error.js +293 -215
- package/lib/framework-schema.js +717 -717
- package/lib/gate-contract.js +971 -0
- package/lib/guard-all.js +405 -0
- package/lib/guard-archive.js +739 -0
- package/lib/guard-csv.js +816 -0
- package/lib/guard-email.js +744 -0
- package/lib/guard-filename.js +724 -0
- package/lib/guard-html.js +976 -0
- package/lib/guard-json.js +729 -0
- package/lib/guard-markdown.js +586 -0
- package/lib/guard-svg.js +976 -0
- package/lib/guard-xml.js +405 -0
- package/lib/guard-yaml.js +529 -0
- package/lib/handlers.js +350 -350
- package/lib/http-client-cookie-jar.js +508 -508
- package/lib/http-client.js +1195 -1195
- package/lib/i18n.js +878 -878
- package/lib/jobs.js +185 -185
- package/lib/log-stream-cloudwatch.js +369 -369
- package/lib/log-stream-local.js +146 -146
- package/lib/log-stream-otlp-grpc.js +410 -410
- package/lib/log-stream-otlp.js +286 -286
- package/lib/log-stream-syslog.js +302 -302
- package/lib/log-stream-webhook.js +199 -199
- package/lib/log-stream.js +330 -330
- package/lib/log.js +500 -500
- package/lib/mail-bounce.js +528 -528
- package/lib/mail-dkim.js +369 -362
- package/lib/mail.js +981 -962
- package/lib/metrics.js +683 -683
- package/lib/middleware/api-encrypt.js +936 -936
- package/lib/middleware/attach-user.js +157 -157
- package/lib/middleware/body-parser.js +1170 -1091
- package/lib/middleware/bot-guard.js +178 -178
- package/lib/middleware/compression.js +452 -452
- package/lib/middleware/cors.js +314 -314
- package/lib/middleware/csp-nonce.js +348 -348
- package/lib/middleware/csrf-protect.js +316 -316
- package/lib/middleware/db-role-for.js +264 -264
- package/lib/middleware/health.js +392 -392
- package/lib/middleware/index.js +79 -79
- package/lib/middleware/rate-limit.js +358 -358
- package/lib/middleware/request-id.js +61 -61
- package/lib/middleware/request-log.js +168 -168
- package/lib/middleware/require-auth.js +104 -104
- package/lib/middleware/security-headers.js +116 -116
- package/lib/middleware/sse.js +166 -166
- package/lib/migrations.js +383 -383
- package/lib/mtls-ca.js +518 -518
- package/lib/mtls-engine-default.js +481 -481
- package/lib/network-dns.js +632 -632
- package/lib/network-heartbeat.js +290 -290
- package/lib/network-nts.js +574 -574
- package/lib/network-proxy.js +265 -265
- package/lib/network-tls.js +328 -328
- package/lib/network.js +233 -233
- package/lib/notify.js +612 -612
- package/lib/ntp-check.js +229 -229
- package/lib/numeric-bounds.js +111 -91
- package/lib/object-store/azure-blob-bucket-ops.js +349 -349
- package/lib/object-store/azure-blob.js +488 -488
- package/lib/object-store/gcs-bucket-ops.js +351 -351
- package/lib/object-store/gcs.js +519 -519
- package/lib/object-store/http-put.js +153 -153
- package/lib/object-store/index.js +197 -197
- package/lib/object-store/sigv4-bucket-ops.js +1092 -1092
- package/lib/object-store/sigv4.js +903 -903
- package/lib/observability.js +151 -151
- package/lib/otel-export.js +269 -269
- package/lib/pagination.js +464 -464
- package/lib/parsers/index.js +80 -80
- package/lib/parsers/safe-env.js +642 -642
- package/lib/parsers/safe-ini.js +292 -292
- package/lib/parsers/safe-toml.js +784 -784
- package/lib/parsers/safe-xml.js +390 -390
- package/lib/parsers/safe-yaml.js +1015 -1015
- package/lib/permissions.js +708 -708
- package/lib/pqc-agent.js +87 -87
- package/lib/pqc-gate.js +279 -279
- package/lib/protobuf-encoder.js +190 -190
- package/lib/protocol-dispatcher.js +161 -161
- package/lib/pubsub-redis.js +167 -167
- package/lib/pubsub.js +429 -429
- package/lib/queue-local.js +476 -476
- package/lib/queue-redis.js +745 -745
- package/lib/queue-sqs.js +319 -319
- package/lib/queue.js +695 -695
- package/lib/redis-client.js +519 -519
- package/lib/request-helpers.js +340 -340
- package/lib/restore-bundle.js +237 -237
- package/lib/restore-rollback.js +259 -259
- package/lib/restore.js +409 -409
- package/lib/retry.js +376 -376
- package/lib/router.js +748 -748
- package/lib/safe-async.js +735 -735
- package/lib/safe-buffer.js +237 -237
- package/lib/safe-json.js +541 -541
- package/lib/safe-schema.js +1266 -1266
- package/lib/safe-url.js +159 -159
- package/lib/scheduler.js +706 -706
- package/lib/security-assert.js +373 -373
- package/lib/seeders.js +618 -618
- package/lib/session.js +478 -478
- package/lib/slug.js +269 -269
- package/lib/ssrf-guard.js +401 -401
- package/lib/static.js +184 -4
- package/lib/storage.js +471 -471
- package/lib/subject.js +281 -281
- package/lib/template.js +791 -791
- package/lib/testing.js +798 -798
- package/lib/time.js +310 -310
- package/lib/totp.js +302 -302
- package/lib/tracing.js +494 -494
- package/lib/uuid.js +132 -132
- package/lib/validate-opts.js +340 -319
- package/lib/vault/index.js +308 -308
- package/lib/vault/rotate.js +784 -784
- package/lib/vault/wrap.js +296 -296
- package/lib/vendor/noble-ciphers.cjs +9 -9
- package/lib/webhook.js +595 -595
- package/lib/websocket.js +1048 -1048
- package/package.json +77 -77
- package/sbom.cyclonedx.json +7 -7
package/lib/pubsub-redis.js
CHANGED
|
@@ -1,167 +1,167 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* pubsub-redis — Redis PUB/SUB backend for `lib/pubsub.js`.
|
|
4
|
-
*
|
|
5
|
-
* Two connections per pubsub instance:
|
|
6
|
-
*
|
|
7
|
-
* subscriberConn — placed in subscribe mode via SUBSCRIBE /
|
|
8
|
-
* PSUBSCRIBE. The `lib/redis-client.js` push hook
|
|
9
|
-
* (`setOnPushMessage`) demultiplexes server-pushed
|
|
10
|
-
* "message" / "pmessage" frames from
|
|
11
|
-
* SUBSCRIBE/UNSUBSCRIBE acks. Subscribe-mode
|
|
12
|
-
* connections can't issue arbitrary commands;
|
|
13
|
-
* splitting publisher off is mandatory.
|
|
14
|
-
* publisherConn — issues PUBLISH commands against the same Redis
|
|
15
|
-
* instance. Uses normal command pipelining.
|
|
16
|
-
*
|
|
17
|
-
* The framework's `lib/redis-client.js` is single-connection-per-create
|
|
18
|
-
* — both connections use the same options (URL / password / TLS / CA).
|
|
19
|
-
*
|
|
20
|
-
* Channels are passed through to Redis with the topicPrefix already
|
|
21
|
-
* applied by `lib/pubsub.js`; this backend doesn't add any naming
|
|
22
|
-
* conventions of its own.
|
|
23
|
-
*/
|
|
24
|
-
var C = require("./constants");
|
|
25
|
-
var fwCrypto = require("./crypto");
|
|
26
|
-
var lazyRequire = require("./lazy-require");
|
|
27
|
-
var redisClient = require("./redis-client");
|
|
28
|
-
var safeJson = require("./safe-json");
|
|
29
|
-
|
|
30
|
-
var logger = lazyRequire(function () { return require("./log").boot("pubsub-redis"); });
|
|
31
|
-
|
|
32
|
-
function create(opts) {
|
|
33
|
-
if (typeof opts.redisUrl !== "string" || opts.redisUrl.length === 0) {
|
|
34
|
-
throw new Error("pubsub-redis: redisUrl is required");
|
|
35
|
-
}
|
|
36
|
-
// Per-instance nonce stamped on every outgoing payload so the
|
|
37
|
-
// SUBSCRIBE socket can recognize its own publishes and skip
|
|
38
|
-
// dispatching them (the framework's pubsub.publish() already did
|
|
39
|
-
// the local dispatch synchronously before awaiting the remote
|
|
40
|
-
// write — without this filter every same-instance publish would
|
|
41
|
-
// double-fire local handlers).
|
|
42
|
-
var instanceNonce = fwCrypto.generateToken(C.BYTES.bytes(8));
|
|
43
|
-
|
|
44
|
-
var clientOpts = redisClient.pickClientOpts(opts, "redis");
|
|
45
|
-
|
|
46
|
-
var subscriberConn = null;
|
|
47
|
-
var publisherConn = null;
|
|
48
|
-
var connectPromise = null;
|
|
49
|
-
var stopped = false;
|
|
50
|
-
var savedOnRemoteMessage = null;
|
|
51
|
-
|
|
52
|
-
// Inbound demultiplex — the redis-client routes "message" /
|
|
53
|
-
// "pmessage" frames here. Strip the {_psnode, p} envelope; if the
|
|
54
|
-
// nonce matches this instance, the message is our own publish
|
|
55
|
-
// looping back through Redis — skip dispatch (pubsub.js already
|
|
56
|
-
// dispatched locally in publish()). Otherwise forward to the
|
|
57
|
-
// dispatcher with the unwrapped payload string.
|
|
58
|
-
function _onPush(ev) {
|
|
59
|
-
if (!savedOnRemoteMessage) return;
|
|
60
|
-
var rawPayload = ev.payload;
|
|
61
|
-
var payloadStr = Buffer.isBuffer(rawPayload)
|
|
62
|
-
? rawPayload.toString("utf8") : String(rawPayload);
|
|
63
|
-
var inner = payloadStr;
|
|
64
|
-
// Redis pubsub frames are bounded by Redis's own bulk-string limit;
|
|
65
|
-
// cap the envelope parse at 16 MiB to keep this hot path fast and
|
|
66
|
-
// defeat a hostile publisher inflating one frame to 512 MB.
|
|
67
|
-
try {
|
|
68
|
-
var envelope = safeJson.parse(payloadStr, { maxBytes: C.BYTES.mib(16) });
|
|
69
|
-
if (envelope && typeof envelope === "object" &&
|
|
70
|
-
typeof envelope._psnode === "string") {
|
|
71
|
-
if (envelope._psnode === instanceNonce) return; // own publish
|
|
72
|
-
inner = JSON.stringify(envelope.p);
|
|
73
|
-
}
|
|
74
|
-
} catch (e) {
|
|
75
|
-
// Not an envelope — forward as-is for operators publishing raw
|
|
76
|
-
// strings via redis CLI etc. (Parse failure is the expected path
|
|
77
|
-
// for raw-string publishers; not log-worthy.)
|
|
78
|
-
void e;
|
|
79
|
-
}
|
|
80
|
-
try {
|
|
81
|
-
savedOnRemoteMessage(ev.channel, inner, {
|
|
82
|
-
pattern: ev.pattern || null,
|
|
83
|
-
});
|
|
84
|
-
} catch (e) {
|
|
85
|
-
try { logger().warn("pubsub-redis push dispatch failed: " +
|
|
86
|
-
((e && e.message) || String(e))); }
|
|
87
|
-
catch (_e) { /* */ }
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
async function _ensureConnected() {
|
|
92
|
-
if (stopped) throw new Error("pubsub-redis: backend stopped");
|
|
93
|
-
if (subscriberConn && publisherConn) return;
|
|
94
|
-
if (connectPromise) return connectPromise;
|
|
95
|
-
connectPromise = (async function () {
|
|
96
|
-
subscriberConn = redisClient.create(Object.assign({}, clientOpts, {
|
|
97
|
-
onPushMessage: _onPush,
|
|
98
|
-
}));
|
|
99
|
-
publisherConn = redisClient.create(clientOpts);
|
|
100
|
-
await Promise.all([subscriberConn.connect(), publisherConn.connect()]);
|
|
101
|
-
})();
|
|
102
|
-
try { await connectPromise; }
|
|
103
|
-
finally { connectPromise = null; }
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
async function publishRemote(scopedChannel, payload) {
|
|
107
|
-
await _ensureConnected();
|
|
108
|
-
var serialized = JSON.stringify({ _psnode: instanceNonce, p: payload });
|
|
109
|
-
var n = await publisherConn.command("PUBLISH", scopedChannel, serialized);
|
|
110
|
-
return { remote: Number(n) || 0 };
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
async function subscribeRemote(scopedChannel, isPattern) {
|
|
114
|
-
await _ensureConnected();
|
|
115
|
-
var cmd = isPattern ? "PSUBSCRIBE" : "SUBSCRIBE";
|
|
116
|
-
await subscriberConn.command(cmd, scopedChannel);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
async function unsubscribeRemote(scopedChannel, isPattern) {
|
|
120
|
-
if (!subscriberConn || !subscriberConn.isOpen()) return;
|
|
121
|
-
var cmd = isPattern ? "PUNSUBSCRIBE" : "UNSUBSCRIBE";
|
|
122
|
-
try { await subscriberConn.command(cmd, scopedChannel); }
|
|
123
|
-
catch (_e) { /* unsubscribe failure is informational */ }
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function start(onRemoteMessage) {
|
|
127
|
-
savedOnRemoteMessage = onRemoteMessage;
|
|
128
|
-
// Lazy connect — first subscribe / publish opens the sockets. This
|
|
129
|
-
// keeps `b.pubsub.create()` synchronous-safe on a misconfigured
|
|
130
|
-
// redis URL: the validation throw lands on the first publish/subscribe
|
|
131
|
-
// call, where the operator can catch it.
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
async function stop() {
|
|
135
|
-
stopped = true;
|
|
136
|
-
savedOnRemoteMessage = null;
|
|
137
|
-
if (subscriberConn) {
|
|
138
|
-
try { await subscriberConn.close(); }
|
|
139
|
-
catch (e) {
|
|
140
|
-
try { logger().debug("subscriber-close-failed: " +
|
|
141
|
-
((e && e.message) || String(e))); }
|
|
142
|
-
catch (_e) { /* logger best-effort */ }
|
|
143
|
-
}
|
|
144
|
-
subscriberConn = null;
|
|
145
|
-
}
|
|
146
|
-
if (publisherConn) {
|
|
147
|
-
try { await publisherConn.close(); }
|
|
148
|
-
catch (e) {
|
|
149
|
-
try { logger().debug("publisher-close-failed: " +
|
|
150
|
-
((e && e.message) || String(e))); }
|
|
151
|
-
catch (_e) { /* logger best-effort */ }
|
|
152
|
-
}
|
|
153
|
-
publisherConn = null;
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return {
|
|
158
|
-
name: "redis",
|
|
159
|
-
publishRemote: publishRemote,
|
|
160
|
-
subscribeRemote: subscribeRemote,
|
|
161
|
-
unsubscribeRemote: unsubscribeRemote,
|
|
162
|
-
start: start,
|
|
163
|
-
stop: stop,
|
|
164
|
-
};
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
module.exports = { create: create };
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* pubsub-redis — Redis PUB/SUB backend for `lib/pubsub.js`.
|
|
4
|
+
*
|
|
5
|
+
* Two connections per pubsub instance:
|
|
6
|
+
*
|
|
7
|
+
* subscriberConn — placed in subscribe mode via SUBSCRIBE /
|
|
8
|
+
* PSUBSCRIBE. The `lib/redis-client.js` push hook
|
|
9
|
+
* (`setOnPushMessage`) demultiplexes server-pushed
|
|
10
|
+
* "message" / "pmessage" frames from
|
|
11
|
+
* SUBSCRIBE/UNSUBSCRIBE acks. Subscribe-mode
|
|
12
|
+
* connections can't issue arbitrary commands;
|
|
13
|
+
* splitting publisher off is mandatory.
|
|
14
|
+
* publisherConn — issues PUBLISH commands against the same Redis
|
|
15
|
+
* instance. Uses normal command pipelining.
|
|
16
|
+
*
|
|
17
|
+
* The framework's `lib/redis-client.js` is single-connection-per-create
|
|
18
|
+
* — both connections use the same options (URL / password / TLS / CA).
|
|
19
|
+
*
|
|
20
|
+
* Channels are passed through to Redis with the topicPrefix already
|
|
21
|
+
* applied by `lib/pubsub.js`; this backend doesn't add any naming
|
|
22
|
+
* conventions of its own.
|
|
23
|
+
*/
|
|
24
|
+
var C = require("./constants");
|
|
25
|
+
var fwCrypto = require("./crypto");
|
|
26
|
+
var lazyRequire = require("./lazy-require");
|
|
27
|
+
var redisClient = require("./redis-client");
|
|
28
|
+
var safeJson = require("./safe-json");
|
|
29
|
+
|
|
30
|
+
var logger = lazyRequire(function () { return require("./log").boot("pubsub-redis"); });
|
|
31
|
+
|
|
32
|
+
function create(opts) {
|
|
33
|
+
if (typeof opts.redisUrl !== "string" || opts.redisUrl.length === 0) {
|
|
34
|
+
throw new Error("pubsub-redis: redisUrl is required");
|
|
35
|
+
}
|
|
36
|
+
// Per-instance nonce stamped on every outgoing payload so the
|
|
37
|
+
// SUBSCRIBE socket can recognize its own publishes and skip
|
|
38
|
+
// dispatching them (the framework's pubsub.publish() already did
|
|
39
|
+
// the local dispatch synchronously before awaiting the remote
|
|
40
|
+
// write — without this filter every same-instance publish would
|
|
41
|
+
// double-fire local handlers).
|
|
42
|
+
var instanceNonce = fwCrypto.generateToken(C.BYTES.bytes(8));
|
|
43
|
+
|
|
44
|
+
var clientOpts = redisClient.pickClientOpts(opts, "redis");
|
|
45
|
+
|
|
46
|
+
var subscriberConn = null;
|
|
47
|
+
var publisherConn = null;
|
|
48
|
+
var connectPromise = null;
|
|
49
|
+
var stopped = false;
|
|
50
|
+
var savedOnRemoteMessage = null;
|
|
51
|
+
|
|
52
|
+
// Inbound demultiplex — the redis-client routes "message" /
|
|
53
|
+
// "pmessage" frames here. Strip the {_psnode, p} envelope; if the
|
|
54
|
+
// nonce matches this instance, the message is our own publish
|
|
55
|
+
// looping back through Redis — skip dispatch (pubsub.js already
|
|
56
|
+
// dispatched locally in publish()). Otherwise forward to the
|
|
57
|
+
// dispatcher with the unwrapped payload string.
|
|
58
|
+
function _onPush(ev) {
|
|
59
|
+
if (!savedOnRemoteMessage) return;
|
|
60
|
+
var rawPayload = ev.payload;
|
|
61
|
+
var payloadStr = Buffer.isBuffer(rawPayload)
|
|
62
|
+
? rawPayload.toString("utf8") : String(rawPayload);
|
|
63
|
+
var inner = payloadStr;
|
|
64
|
+
// Redis pubsub frames are bounded by Redis's own bulk-string limit;
|
|
65
|
+
// cap the envelope parse at 16 MiB to keep this hot path fast and
|
|
66
|
+
// defeat a hostile publisher inflating one frame to 512 MB.
|
|
67
|
+
try {
|
|
68
|
+
var envelope = safeJson.parse(payloadStr, { maxBytes: C.BYTES.mib(16) });
|
|
69
|
+
if (envelope && typeof envelope === "object" &&
|
|
70
|
+
typeof envelope._psnode === "string") {
|
|
71
|
+
if (envelope._psnode === instanceNonce) return; // own publish
|
|
72
|
+
inner = JSON.stringify(envelope.p);
|
|
73
|
+
}
|
|
74
|
+
} catch (e) {
|
|
75
|
+
// Not an envelope — forward as-is for operators publishing raw
|
|
76
|
+
// strings via redis CLI etc. (Parse failure is the expected path
|
|
77
|
+
// for raw-string publishers; not log-worthy.)
|
|
78
|
+
void e;
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
savedOnRemoteMessage(ev.channel, inner, {
|
|
82
|
+
pattern: ev.pattern || null,
|
|
83
|
+
});
|
|
84
|
+
} catch (e) {
|
|
85
|
+
try { logger().warn("pubsub-redis push dispatch failed: " +
|
|
86
|
+
((e && e.message) || String(e))); }
|
|
87
|
+
catch (_e) { /* */ }
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async function _ensureConnected() {
|
|
92
|
+
if (stopped) throw new Error("pubsub-redis: backend stopped");
|
|
93
|
+
if (subscriberConn && publisherConn) return;
|
|
94
|
+
if (connectPromise) return connectPromise;
|
|
95
|
+
connectPromise = (async function () {
|
|
96
|
+
subscriberConn = redisClient.create(Object.assign({}, clientOpts, {
|
|
97
|
+
onPushMessage: _onPush,
|
|
98
|
+
}));
|
|
99
|
+
publisherConn = redisClient.create(clientOpts);
|
|
100
|
+
await Promise.all([subscriberConn.connect(), publisherConn.connect()]);
|
|
101
|
+
})();
|
|
102
|
+
try { await connectPromise; }
|
|
103
|
+
finally { connectPromise = null; }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
async function publishRemote(scopedChannel, payload) {
|
|
107
|
+
await _ensureConnected();
|
|
108
|
+
var serialized = JSON.stringify({ _psnode: instanceNonce, p: payload });
|
|
109
|
+
var n = await publisherConn.command("PUBLISH", scopedChannel, serialized);
|
|
110
|
+
return { remote: Number(n) || 0 };
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
async function subscribeRemote(scopedChannel, isPattern) {
|
|
114
|
+
await _ensureConnected();
|
|
115
|
+
var cmd = isPattern ? "PSUBSCRIBE" : "SUBSCRIBE";
|
|
116
|
+
await subscriberConn.command(cmd, scopedChannel);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
async function unsubscribeRemote(scopedChannel, isPattern) {
|
|
120
|
+
if (!subscriberConn || !subscriberConn.isOpen()) return;
|
|
121
|
+
var cmd = isPattern ? "PUNSUBSCRIBE" : "UNSUBSCRIBE";
|
|
122
|
+
try { await subscriberConn.command(cmd, scopedChannel); }
|
|
123
|
+
catch (_e) { /* unsubscribe failure is informational */ }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
function start(onRemoteMessage) {
|
|
127
|
+
savedOnRemoteMessage = onRemoteMessage;
|
|
128
|
+
// Lazy connect — first subscribe / publish opens the sockets. This
|
|
129
|
+
// keeps `b.pubsub.create()` synchronous-safe on a misconfigured
|
|
130
|
+
// redis URL: the validation throw lands on the first publish/subscribe
|
|
131
|
+
// call, where the operator can catch it.
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
async function stop() {
|
|
135
|
+
stopped = true;
|
|
136
|
+
savedOnRemoteMessage = null;
|
|
137
|
+
if (subscriberConn) {
|
|
138
|
+
try { await subscriberConn.close(); }
|
|
139
|
+
catch (e) {
|
|
140
|
+
try { logger().debug("subscriber-close-failed: " +
|
|
141
|
+
((e && e.message) || String(e))); }
|
|
142
|
+
catch (_e) { /* logger best-effort */ }
|
|
143
|
+
}
|
|
144
|
+
subscriberConn = null;
|
|
145
|
+
}
|
|
146
|
+
if (publisherConn) {
|
|
147
|
+
try { await publisherConn.close(); }
|
|
148
|
+
catch (e) {
|
|
149
|
+
try { logger().debug("publisher-close-failed: " +
|
|
150
|
+
((e && e.message) || String(e))); }
|
|
151
|
+
catch (_e) { /* logger best-effort */ }
|
|
152
|
+
}
|
|
153
|
+
publisherConn = null;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return {
|
|
158
|
+
name: "redis",
|
|
159
|
+
publishRemote: publishRemote,
|
|
160
|
+
subscribeRemote: subscribeRemote,
|
|
161
|
+
unsubscribeRemote: unsubscribeRemote,
|
|
162
|
+
start: start,
|
|
163
|
+
stop: stop,
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
module.exports = { create: create };
|