@blamejs/core 0.7.1 → 0.7.4
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 +6 -0
- package/README.md +2 -2
- package/index.js +2 -0
- package/lib/api-key.js +1 -10
- package/lib/cache-redis.js +1 -11
- package/lib/cache.js +11 -16
- package/lib/file-upload.js +933 -0
- package/lib/framework-error.js +13 -0
- package/lib/log-stream-syslog.js +1 -1
- package/lib/middleware/api-encrypt.js +415 -52
- package/lib/middleware/db-role-for.js +3 -8
- package/lib/notify.js +3 -5
- package/lib/object-store/azure-blob.js +42 -5
- package/lib/object-store/gcs.js +47 -7
- package/lib/object-store/sigv4.js +55 -7
- package/lib/pubsub-redis.js +1 -11
- package/lib/queue-redis.js +1 -8
- package/lib/redis-client.js +30 -0
- package/lib/request-helpers.js +21 -17
- package/lib/seeders.js +5 -17
- package/lib/static.js +699 -114
- package/lib/validate-opts.js +49 -0
- package/lib/webhook.js +3 -6
- package/package.json +1 -1
- package/sbom.cyclonedx.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,12 @@ upgrading across more than a few patches at a time.
|
|
|
8
8
|
|
|
9
9
|
## v0.7.x
|
|
10
10
|
|
|
11
|
+
- **0.7.4** (2026-05-04) — CI gate alignment, wiki cross-platform fix, redis-client opts forwarding consolidation. Two CI-only gates (`scripts/check-api-snapshot.js` for public-API drift detection; Linux-container wiki e2e for cross-platform example execution) added to the local Release Workflow, plus `api-snapshot.json` baseline refreshed for the first time since v0.6.17 (40+ patches of accumulated drift; `b.objectStoreRetry` removal in v0.7.0 was the BREAKING entry). The wiki file-upload example previously hardcoded `stagingDir: "/var/lib/myapp/uploads"` which mkdir-passed on Windows but failed `EACCES` on Linux/macOS CI runners — replaced with a real runnable example using `path.join(os.tmpdir(), "myapp-uploads-" + Date.now())` and a self-contained `b.fileUpload.create` + `uploads.close()` round-trip; the Usage block likewise instantiates a real `b.router.create()` + uploads pair. `examples/wiki/test/run-example.js` harness gains `path` + `os` Node built-ins as bindings so wiki examples can write idiomatic `path.join(os.tmpdir(), ...)` without falling foul of the harness's `var X = require(...)` line stripper. **`redisClient.pickClientOpts(cfg, prefix?)`** — new helper that returns the standard 9-key opts bag (`url / password / username / tls / ca / servername / connectTimeoutMs / commandTimeoutMs / maxReconnectAttempts`); `cache-redis` / `pubsub-redis` / `queue-redis` / `cache` redis-backend creator all migrated to it, eliminating ~40 lines of duplicate inline forwarding across the four files. The new `inline-redis-client-opts-forwarding` `KNOWN_ANTIPATTERNS` entry catches future re-implementations at n=1. **`testNoDuplicateCodeBlocks`** + **`testNoUnresolvedMarkers`** + **`testNoTierTerminologyInLib`** detector tuning: `MIN_DISTINCT_FILES` lowered 3 → 2 / `MIN_DISTINCT_TOKENS` lowered 6 → 5 (more aggressive duplicate detection); `defer` added to forbidden-marker scan; `Tier 1/2/3` added to forbidden-tier-terminology scan. `lib/log-stream-syslog.js`'s socket error-handler comment reworded from "defer to 'close' for reconnect" to "reconnect handled in the close listener" — same behavior, no marker false-positive. **Tests** — Linux-container wiki e2e green (188 examples ran clean, 0 failures, 0 symbol drift); `node scripts/check-api-snapshot.js` reports `[api-snapshot] no changes`. Smoke 7485 / wiki e2e 178 / Linux container smoke 7485 / Linux container wiki e2e 178 / eslint clean / shellcheck clean.
|
|
12
|
+
|
|
13
|
+
- **0.7.3** (2026-05-04) — `b.middleware.apiEncrypt` per-session keying mode (opt-in). Per-request keying stays the default — every existing test passes unchanged. Operators opt in by passing `keying: "per-session"`; the first request in a session carries the bootstrap envelope `{ _ek, _ct, _ts, _nonce, _sid, _ctr }` and the server stores the session key keyed by `_sid` (UUID v4); subsequent requests in the same session omit `_ek` and `_nonce` entirely, sending only `{ _ct, _ts, _sid, _ctr }`. The monotonic `_ctr` replaces the nonce for replay defense — server rejects any request with `_ctr <= last_seen_ctr` for that session. Responses carry `{ _ct, _sid, _ctr }`; the client helper validates the response counter is strictly increasing so a tampered / replayed response surfaces as `CLIENT_RESPONSE_REPLAY` instead of silently propagating stale data. Sessions expire on `sessionTtlMs` (default 15 minutes) OR after `sessionMaxResponses` (default 1024); both surface as 401 (`session-expired` / `session-rotation-required`) and the client helper's `resetSession()` re-bootstraps. Operator-supplied `sessionStore` is a `{ get, set, delete }`-shaped handle (b.cache shape-compatible) so multi-replica deploys share session state; default is an in-memory map for single-process apps. Wire format trade-off: per-session amortizes ~1.6 KB of KEM material across the session for high-throughput / mobile / metered-network apps; per-request stays strictly safer if the session storage gets compromised. Audit emits `apiEncrypt.session.created` / `.expired` / `.rotated` / `.replay_rejected` with actor context; observability counters track sessions established / replay-rejected / expired / unknown / rotated. The framework HTTP-client helper `b.httpClient.encrypted({ keying: "per-session" })` threads the same posture through service-to-service callers. **Tests** — 13 new layer-0 assertions covering default-keying invariant, opt validation (bad keying value / TTL / store shape), bootstrap-and-reuse round-trip (KEM amortization confirmed by inspecting subsequent envelope shape), unknown-sid 401, counter-replay 400, TTL-expiry 401, max-responses-rotation 401, response counter monotonic check, sessionInfo / resetSession client API, observability emission. Smoke 7445 → 7485 / wiki e2e 178 / Linux container smoke 7485 (147s) / eslint clean / shellcheck clean.
|
|
14
|
+
|
|
15
|
+
- **0.7.2** (2026-05-04) — Symmetric upload + download primitives ship with full v1-defensible feature sets. **`b.fileUpload`** chunked upload primitive: operators wire HTTP routes for per-chunk PUT (`fileUpload.acceptChunk`) and finalize POST (`fileUpload.finalize`); the framework owns the chunk lifecycle (per-chunk SHA3-512, atomic chunk write to `<stagingDir>/<uploadId>/<index>`, reassemble in manifest order, verify total SHA3-512) and hands the assembled buffer to an operator-supplied `onFinalize` callback. Surface includes `init` / `acceptChunk` / `finalize` / `status` / `list` / `cancelUpload` / `purgeIncomplete`. v1 features: per-actor active-upload quota, total staging-bytes quota, MIME magic-byte allowlist (composes `b.fileType`), `onChunk` operator hook, idle-upload timeout, stream reassembly above `maxStreamReassemblyBytes` (sequential async iterator over chunk files instead of `Buffer.concat`), permissions integration, metadata stash with cap, path-safe upload-ID regex, mode 0o700 staging dir, idempotent re-PUT, force-cancel, audit emission with 5-W actor context, observability counters. **`b.staticServe`** download primitive expanded with the symmetric feature set: permissions gate (403), compliance retention gate (451), force-revoke instance method + revoke-store opt (404), MIME magic-byte allowlist (415), RFC 7233 single-range support (multi-range refused with 416), full conditional-request set (`If-None-Match` / `If-Match` / `If-Modified-Since` / `If-Unmodified-Since`), per-actor + global bandwidth quotas via `b.cache` cluster-shared token-buckets (429 + Retry-After), per-actor concurrency cap (429), `onServe` per-request operator hook, `maxIdleMs` stalled-stream timeout, cancellation propagation (client disconnect destroys file stream + releases concurrency slot), audit + observability emission with 5-W actor context. ETag is now SHA3-512-truncated for PQC posture; the SRI integrity helper keeps SHA-384 because the W3C subresource-integrity spec only allows sha256/sha384/sha512. **Object-store backends** (sigv4 / gcs / azure-blob) gain a new `getResponse(key, opts?)` method that forwards `range` / `ifNoneMatch` / `ifMatch` / `ifModifiedSince` / `ifUnmodifiedSince` opts to the backend's protocol-specific headers and returns `{ statusCode, body, etag, lastModified, contentRange, size, contentType }` — operators wiring object-store-backed download routes route conditional + range from the client request straight through. Existing `get(key)` returns just the body for back-compat. **`HTTP_STATUS`** constants extended with `PARTIAL_CONTENT` / `RANGE_NOT_SATISFIABLE` / `PRECONDITION_FAILED` / `UNAVAILABLE_FOR_LEGAL_REASONS`. **New helpers** — `validateOpts.optionalNonEmptyStringArray(value, label, ErrorClass, code?)` and `validateOpts.optionalObjectWithMethod(value, method, label, ErrorClass, code?, description?)` consolidate the recurring "string-array" and "duck-typed handle" inline cascades across api-key / file-upload / seeders / notify / webhook / db-role-for. Both registered in `KNOWN_ANTIPATTERNS` so future re-implementations fail the n=1 gate. **Tests** — 28 new layer-0 fileUpload assertions (init / acceptChunk / finalize / status / list / cancel / quotas / MIME allowlist / onChunk / idle / stream reassembly / permissions) plus 24 new staticServe assertions (range / suffix-range / open-end-range / unsatisfiable-range / multi-range refused / acceptRanges off / If-Match / If-Modified-Since / If-Unmodified-Since / permissions / retention / revoke / MIME allowlist / onServe / audit / stats / invalidateMeta / quotas / concurrency cap). Wiki page `examples/wiki/seeders/prod/pages/file-upload.js` added; routing.js section for `b.staticServe` rewritten to document the v1 surface. README "what ships in the box" Communication + Routing bullets updated. Smoke 7341 → 7445 / wiki e2e 178 / Linux container smoke 7445 (146s) / eslint clean / shellcheck clean.
|
|
16
|
+
|
|
11
17
|
- **0.7.1** (2026-05-04) — `b.websocket` route opts gain `handshakeGuid` to override the RFC 6455 §1.3 magic string used in the `Sec-WebSocket-Accept` derivation. Default stays `258EAFA5-E914-47DA-95CA-C5AB0DC85B11`. Operators with closed-ecosystem clients running their own GUID (typical for migrations from frameworks that customize the handshake to namespace their own client family) drop `handshakeGuid: "<their-uuid>"` into the `router.ws(path, handler, opts)` opts and clients keep working unchanged. Throws at upgrade time if the override is malformed — UUID-shape regex with a 64-char length cap before the regex test, so a typo produces a clear error instead of silently producing a `Sec-WebSocket-Accept` the client can't match. **Tests** — 3 new layer-0 assertions in `test/00-primitives.js` (custom GUID produces different accept key, empty / null falls back to RFC default, malformed handshakeGuid rejected at config time). Smoke 7338 → 7341 / wiki e2e 178 / Linux container smoke 7341 (145s) / eslint clean / shellcheck clean.
|
|
12
18
|
|
|
13
19
|
- **0.7.0** (2026-05-04) — Codebase-patterns hardening sweep + primitive consolidation. The duplicate-block detector in `test/layer-0-primitives/codebase-patterns.test.js` ran at MIN_DISTINCT_FILES=3 and surfaced ~50 inline-shape clusters that had proliferated across lib/ — the kind of soft drift that's invisible at higher thresholds and hides re-introduction of bug classes the framework already swept once. **New primitive families** consolidated those clusters down: opts validation (`validateOpts.requireObject` / `auditShape` / `observabilityShape` / `applyDefaults` / `optional{Boolean,Function,PositiveInt,FiniteNonNegative,PositiveFinite,NonEmptyString}` / `requireNonEmptyString` / `makeAuditEmitter`), async coordination (`safeAsync.safeInvoke` / `makeDropCallback` / `makeScheduledFlush`), and SQL execution (`dbSchema.runInTransaction` / `runSqlOnHandle`). Plus `numericBounds.requireXFiniteIntIfPresent` for opt-time numeric-shape gates that throw via the caller's framework-error class, `log.makeViaOrFallback` for operator-log routing with per-module fallback, `observability.safeEvent` for hot-path drop-silent emission, `safeBuffer.HEX_RE`/`CRLF_RE`/`TRAILING_HSPACE_RE` regex constants + `isHex` / `hasCrlf` / `stripCrlf` / `stripTrailingHspace` helpers, `time.toIso8601NoMs`, `migrationFiles.MIGRATION_FILE_RE` / `isMigrationFileName` (shared filename grammar across migrations / seeders / external-db-migrate), and `lib/object-store/http-request.js` as a shared HTTP request helper across azure-blob / gcs / sigv4 / http-put. Roughly 80 inline call sites across 50+ files refactored to route through the new primitives; ~1500 lines of duplicate inline shapes eliminated. **Catalog gate** — `KNOWN_ANTIPATTERNS` in the codebase-patterns test now has 24 entries firing at n=1, so future code re-introducing any of the registered inline shapes (even one new file) fails the gate immediately. Pre-v0.7.0 the duplicate-block detector required n>=3 to fire; the catalog closes the gap by registering each extracted primitive's inline shape so it can't drift back in. **Cluster allowlist** — `KNOWN_CLUSTERS` allowlist (n>=3 detector) has 25 entries with documented structural reasons (parser error class signatures don't fit the framework's `(code, message)` contract; framework-convention shapes like middleware factories; future consolidation candidates). **Cleanup** — deleted dead re-export shims `lib/object-store/retry.js` (re-exported `lib/retry.js`) and `lib/auth/totp.js` (re-exported `lib/totp.js`); both fit the rule "pre-v1 frameworks have no operators to compatibly upgrade — every legacy fallback is dead code." Renamed `lib/internal-sha1-hibp.js` → `lib/framework-sha1-hibp.js` to match the lib naming convention (the `internal-` prefix wasn't in the convention's five-bucket list; `framework-` is the canonical "restricted-use" bucket alongside `framework-error.js` / `framework-schema.js`). **No operator-facing API breakage** — `b.objectStoreRetry` was removed from the public surface (operators use `b.retry` directly, which has been the canonical primitive since v0.2.24). **Eslint config tightened** — added `eqeqeq` (with the `null` exception for the `== null` null-or-undefined idiom), `no-throw-literal`, `no-promise-executor-return`, `default-case`, `no-loss-of-precision`. The previous config was hiding 11 real errors: 8 sites of `return resolve()` / `return done()` inside `new Promise(executor)` (return value silently discarded) across app / dev / http-client / mail / router / wiki/integration / 00-primitives, plus a missing default-case + 2 intentional template-language `==` / `!=` operators in template.js's binary-op evaluator (now allowed via inline `// eslint-disable-next-line eqeqeq -- template language operator`). Also adds `structuredClone` to the Node-globals list so db.js's deep-clone calls don't trip `no-undef`. **Release-workflow gate added** — Linux container smoke `docker run --rm -v "/$(pwd):/blamejs" -w //blamejs node:24-alpine node test/smoke.js` is now part of the release flow. Catches lingering-handle bugs that pass on Windows / macOS but hang or error on Linux CI. **Tests** — smoke 7338 / Linux container smoke 7338 (148s) / wiki e2e 178 / per-primitive integration 16 files / wiki integration green / eslint clean / shellcheck clean.
|
package/README.md
CHANGED
|
@@ -46,7 +46,7 @@ The framework bundles the surface a typical Node app reaches for. Every primitiv
|
|
|
46
46
|
- **Crypto** — envelope-versioned PQC at rest (ML-KEM-1024 + P-384 hybrid, XChaCha20-Poly1305, SHAKE256), vault sealing, field-level crypto + cryptographic erasure (`b.cryptoField.eraseRow`), signed webhooks (SLH-DSA-SHAKE-256f), ECIES API encryption (`b.crypto`, `b.vault`, `b.webhook`); pure-JS mTLS CA that issues clientAuth / serverAuth / dual-EKU certs with SAN entries and auto-detects the highest-PQC signature algorithm the vendored x509 library accepts (today: ECDSA-P384-SHA384 bridge; self-upgrades to SLH-DSA / ML-DSA when the X.509 ecosystem catches up), PQC TLS gates inbound + outbound (`b.mtlsCa`, `b.pqcGate`, `b.pqcAgent`).
|
|
47
47
|
- **HTTP** — router with schema-validated routes + OpenAPI publication; full middleware stack (CSRF, CORS, rate-limit, security headers, CSP nonce, body parser, compression, SSE, request log, request-time DB role binding via `b.middleware.dbRoleFor`, in-process CIDR fence via `b.middleware.networkAllowlist`) wired by `createApp`; HTTP/1.1 + HTTP/2 outbound client with SSRF gate (cloud-metadata IPs hard-denied unconditionally; private / loopback / link-local overridable per call), scheme + userinfo + per-host (wildcard / per-method) destination allowlist, redirects, multipart, interceptors, progress, encrypted cookie jar (`b.httpClient`, `b.ssrfGuard`, `b.safeUrl`); operator-tunable network configurability — env-driven NTP / NTS (RFC 8915 authenticated time), IPv4-or-IPv6 NTP servers, DNS with IPv6 / DoH / DoT (private-CA trust pinning via `opts.ca`) / cache / lookup timeout, outbound HTTP proxy (`HTTP_PROXY` / `HTTPS_PROXY` / `NO_PROXY`), runtime DPI trust-store CA additions, application-level heartbeats, TCP socket defaults (`b.network`).
|
|
48
48
|
- **Defensive parsers** — `b.safeJson`, `b.safeBuffer`, `b.safeSql`, `b.safeSchema`, `b.parsers` (XML / TOML / YAML / .env), `b.config` (schema-validated env), `b.fileType` magic-byte content classification with deny-on-upload categories (image / document / archive / executable / etc.).
|
|
49
|
-
- **Communication** — WebSockets with channel/room fan-out across cluster replicas (`b.websocket`, `b.websocketChannels`); generic distributed pub/sub with cluster-table / Redis PUB/SUB / custom backends (`b.pubsub`); mail with multipart + attachments + DKIM + calendar invites + bounce intake (`b.mail`, `b.mailBounce`); generic notification dispatcher with operator-supplied transports (`b.notify`).
|
|
49
|
+
- **Communication** — WebSockets with channel/room fan-out across cluster replicas (`b.websocket`, `b.websocketChannels`); generic distributed pub/sub with cluster-table / Redis PUB/SUB / custom backends (`b.pubsub`); mail with multipart + attachments + DKIM + calendar invites + bounce intake (`b.mail`, `b.mailBounce`); generic notification dispatcher with operator-supplied transports (`b.notify`); chunked file uploads with per-chunk SHA3-512 verification + atomic finalize + tombstone cleanup (`b.fileUpload`).
|
|
50
50
|
- **Observability** — tamper-evident audit chain with SLH-DSA-signed checkpoints, metrics, tracing (OTel pass-through when wired), PII redaction, log-stream sinks (local file rotation, generic webhook, OTLP/HTTP-JSON OR OTLP/gRPC to an OTel collector, AWS CloudWatch Logs via SigV4 with optional autoCreate, RFC 5424 syslog over UDP/TCP/TLS), OTLP/HTTP-JSON exporter for traces + metrics (`b.audit`, `b.metrics`, `b.tracing`, `b.redact`, `b.logStream`, `b.otelExport`); operator-callable boot-time security policy assertions (`b.security.assertProduction`) and tamper-evident config-baseline drift detection signed with the audit-signing key (`b.configDrift`).
|
|
51
51
|
- **i18n** — CLDR plural rules, Accept-Language negotiation, Intl formatters, RTL (`b.i18n`).
|
|
52
52
|
- **Format helpers** — RFC 4180 CSV with Excel formula-injection prevention (`b.csv`), RFC 9562 UUID v4 + v7 (`b.uuid`), URL-safe slugs (`b.slug`), TZ-aware datetime (`b.time`), ZIP creation (`b.archive`), HMAC-signed cursor pagination (`b.pagination`), HTML form rendering + validation + CSRF (`b.forms`).
|
|
@@ -61,7 +61,7 @@ Full primitive-by-primitive docs live at [blamejs.com](https://blamejs.com), whi
|
|
|
61
61
|
- **Crypto** — [Crypto & Vault](https://blamejs.com/crypto-vault) · [Network Crypto](https://blamejs.com/network-crypto)
|
|
62
62
|
- **HTTP** — [Routing](https://blamejs.com/routing) · [Middleware](https://blamejs.com/middleware) · [Outbound HTTP](https://blamejs.com/outbound-http) · [Network Configurability](https://blamejs.com/network-config)
|
|
63
63
|
- **Validation** — [Safe Parsers](https://blamejs.com/safe-parsers)
|
|
64
|
-
- **Communication** — [WebSockets](https://blamejs.com/websockets) · [Mail](https://blamejs.com/mail) · [Notifications](https://blamejs.com/notifications)
|
|
64
|
+
- **Communication** — [WebSockets](https://blamejs.com/websockets) · [Mail](https://blamejs.com/mail) · [Notifications](https://blamejs.com/notifications) · [File Upload](https://blamejs.com/file-upload)
|
|
65
65
|
- **Tools** — [Observability](https://blamejs.com/observability) · [Testing](https://blamejs.com/testing) · [i18n & Locale](https://blamejs.com/i18n-locale) · [Format Helpers](https://blamejs.com/format-helpers)
|
|
66
66
|
- **Compliance** — [Compliance Patterns](https://blamejs.com/compliance-patterns)
|
|
67
67
|
- **Production** — [Cluster Mode](https://blamejs.com/cluster) · [Reliability](https://blamejs.com/reliability) · [Backup & Restore](https://blamejs.com/backup-restore) · [Quality Contract](https://blamejs.com/quality-contract)
|
package/index.js
CHANGED
|
@@ -160,6 +160,7 @@ var testing = require("./lib/testing");
|
|
|
160
160
|
var configDrift = require("./lib/config-drift");
|
|
161
161
|
var security = require("./lib/security-assert");
|
|
162
162
|
var fileType = require("./lib/file-type");
|
|
163
|
+
var fileUpload = require("./lib/file-upload");
|
|
163
164
|
var dualControl = require("./lib/dual-control");
|
|
164
165
|
var retention = require("./lib/retention");
|
|
165
166
|
var network = require("./lib/network");
|
|
@@ -274,6 +275,7 @@ module.exports = {
|
|
|
274
275
|
configDrift: configDrift,
|
|
275
276
|
security: security,
|
|
276
277
|
fileType: fileType,
|
|
278
|
+
fileUpload: fileUpload,
|
|
277
279
|
dualControl: dualControl,
|
|
278
280
|
retention: retention,
|
|
279
281
|
network: network,
|
package/lib/api-key.js
CHANGED
|
@@ -163,16 +163,7 @@ function _validateCreateOpts(opts) {
|
|
|
163
163
|
function _validateIssueOpts(opts) {
|
|
164
164
|
validateOpts.requireObject(opts, "apiKey.issue", ApiKeyError);
|
|
165
165
|
validateOpts.requireNonEmptyString(opts.ownerId, "apiKey.issue: ownerId", ApiKeyError, "MISSING_OWNER");
|
|
166
|
-
|
|
167
|
-
if (!Array.isArray(opts.scopes)) {
|
|
168
|
-
throw _err("BAD_SCOPES", "apiKey.issue: scopes must be an array of strings");
|
|
169
|
-
}
|
|
170
|
-
for (var i = 0; i < opts.scopes.length; i++) {
|
|
171
|
-
if (typeof opts.scopes[i] !== "string" || opts.scopes[i].length === 0) {
|
|
172
|
-
throw _err("BAD_SCOPES", "apiKey.issue: scopes[" + i + "] must be a non-empty string");
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
}
|
|
166
|
+
validateOpts.optionalNonEmptyStringArray(opts.scopes, "apiKey.issue: scopes", ApiKeyError, "BAD_SCOPES");
|
|
176
167
|
if (opts.metadata !== undefined && opts.metadata !== null) {
|
|
177
168
|
if (typeof opts.metadata !== "object" || Array.isArray(opts.metadata)) {
|
|
178
169
|
throw _err("BAD_METADATA", "apiKey.issue: metadata must be a plain object or null");
|
package/lib/cache-redis.js
CHANGED
|
@@ -59,17 +59,7 @@ function create(cfg) {
|
|
|
59
59
|
var slidingTtl = cfg.slidingTtl;
|
|
60
60
|
var defaultTtlMs = cfg.defaultTtlMs;
|
|
61
61
|
|
|
62
|
-
var client = redisClient.create(
|
|
63
|
-
url: cfg.url,
|
|
64
|
-
password: cfg.password,
|
|
65
|
-
username: cfg.username,
|
|
66
|
-
tls: cfg.tls,
|
|
67
|
-
ca: cfg.ca,
|
|
68
|
-
servername: cfg.servername,
|
|
69
|
-
connectTimeoutMs: cfg.connectTimeoutMs,
|
|
70
|
-
commandTimeoutMs: cfg.commandTimeoutMs,
|
|
71
|
-
maxReconnectAttempts: cfg.maxReconnectAttempts,
|
|
72
|
-
});
|
|
62
|
+
var client = redisClient.create(redisClient.pickClientOpts(cfg));
|
|
73
63
|
|
|
74
64
|
// Lazy connect — defer until first op so cache.create stays sync-safe.
|
|
75
65
|
var connectPromise = null;
|
package/lib/cache.js
CHANGED
|
@@ -86,6 +86,7 @@
|
|
|
86
86
|
*/
|
|
87
87
|
|
|
88
88
|
var cacheRedis = require("./cache-redis");
|
|
89
|
+
var redisClient = require("./redis-client");
|
|
89
90
|
var clusterStorage = require("./cluster-storage");
|
|
90
91
|
var C = require("./constants");
|
|
91
92
|
var lazyRequire = require("./lazy-require");
|
|
@@ -802,22 +803,16 @@ function create(opts) {
|
|
|
802
803
|
} else if (backendKind === "cluster") {
|
|
803
804
|
backend = _clusterBackend(cfg);
|
|
804
805
|
} else if (backendKind === "redis") {
|
|
805
|
-
backend = _customBackend(cacheRedis.create(
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
maxReconnectAttempts: opts.redisMaxReconnectAttempts,
|
|
816
|
-
slidingTtl: slidingTtl,
|
|
817
|
-
defaultTtlMs: defaultTtlMs,
|
|
818
|
-
clock: clock,
|
|
819
|
-
emitObs: emitObs,
|
|
820
|
-
}), cfg);
|
|
806
|
+
backend = _customBackend(cacheRedis.create(Object.assign(
|
|
807
|
+
redisClient.pickClientOpts(opts, "redis"),
|
|
808
|
+
{
|
|
809
|
+
namespace: namespace,
|
|
810
|
+
slidingTtl: slidingTtl,
|
|
811
|
+
defaultTtlMs: defaultTtlMs,
|
|
812
|
+
clock: clock,
|
|
813
|
+
emitObs: emitObs,
|
|
814
|
+
}
|
|
815
|
+
)), cfg);
|
|
821
816
|
} else {
|
|
822
817
|
backend = _customBackend(opts.backend, cfg);
|
|
823
818
|
}
|