@blamejs/core 0.8.43 → 0.8.49
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 +92 -0
- package/README.md +10 -10
- package/index.js +52 -0
- package/lib/a2a.js +159 -34
- package/lib/acme.js +762 -0
- package/lib/ai-pref.js +166 -43
- package/lib/api-key.js +108 -47
- package/lib/api-snapshot.js +157 -40
- package/lib/app-shutdown.js +113 -77
- package/lib/archive.js +337 -40
- package/lib/arg-parser.js +697 -0
- package/lib/asyncapi.js +99 -55
- package/lib/atomic-file.js +465 -104
- package/lib/audit-chain.js +123 -34
- package/lib/audit-daily-review.js +389 -0
- package/lib/audit-sign.js +302 -56
- package/lib/audit-tools.js +412 -63
- package/lib/audit.js +656 -35
- package/lib/auth/jwt-external.js +17 -0
- package/lib/auth/oauth.js +7 -0
- package/lib/auth-bot-challenge.js +505 -0
- package/lib/auth-header.js +92 -25
- package/lib/backup/bundle.js +26 -0
- package/lib/backup/index.js +512 -89
- package/lib/backup/manifest.js +168 -7
- package/lib/break-glass.js +415 -39
- package/lib/budr.js +103 -30
- package/lib/bundler.js +86 -66
- package/lib/cache.js +192 -72
- package/lib/chain-writer.js +65 -40
- package/lib/circuit-breaker.js +56 -33
- package/lib/cli-helpers.js +106 -75
- package/lib/cli.js +6 -30
- package/lib/cloud-events.js +99 -32
- package/lib/cluster-storage.js +162 -37
- package/lib/cluster.js +340 -49
- package/lib/codepoint-class.js +66 -0
- package/lib/compliance.js +424 -24
- package/lib/config-drift.js +111 -46
- package/lib/config.js +94 -40
- package/lib/consent.js +165 -18
- package/lib/constants.js +1 -0
- package/lib/content-credentials.js +153 -48
- package/lib/cookies.js +154 -62
- package/lib/credential-hash.js +133 -61
- package/lib/crypto-field.js +702 -18
- package/lib/crypto-hpke.js +256 -0
- package/lib/crypto.js +744 -22
- package/lib/csv.js +178 -35
- package/lib/daemon.js +456 -0
- package/lib/dark-patterns.js +186 -55
- package/lib/db-query.js +79 -2
- package/lib/db.js +1431 -60
- package/lib/ddl-change-control.js +523 -0
- package/lib/deprecate.js +195 -40
- package/lib/dev.js +82 -39
- package/lib/dora.js +67 -48
- package/lib/dr-runbook.js +368 -0
- package/lib/dsr.js +142 -11
- package/lib/dual-control.js +91 -56
- package/lib/events.js +120 -41
- package/lib/external-db-migrate.js +192 -2
- package/lib/external-db.js +795 -50
- package/lib/fapi2.js +122 -1
- package/lib/fda-21cfr11.js +395 -0
- package/lib/fdx.js +132 -2
- package/lib/file-type.js +87 -0
- package/lib/file-upload.js +93 -0
- package/lib/flag.js +82 -20
- package/lib/forms.js +132 -29
- package/lib/framework-error.js +169 -0
- package/lib/framework-schema.js +163 -35
- package/lib/gate-contract.js +849 -175
- package/lib/graphql-federation.js +68 -7
- package/lib/guard-all.js +172 -55
- package/lib/guard-archive.js +286 -124
- package/lib/guard-auth.js +194 -21
- package/lib/guard-cidr.js +190 -28
- package/lib/guard-csv.js +397 -51
- package/lib/guard-domain.js +213 -91
- package/lib/guard-email.js +236 -29
- package/lib/guard-filename.js +307 -75
- package/lib/guard-graphql.js +263 -30
- package/lib/guard-html.js +310 -116
- package/lib/guard-image.js +243 -30
- package/lib/guard-json.js +260 -54
- package/lib/guard-jsonpath.js +235 -23
- package/lib/guard-jwt.js +284 -30
- package/lib/guard-markdown.js +204 -22
- package/lib/guard-mime.js +190 -26
- package/lib/guard-oauth.js +277 -28
- package/lib/guard-pdf.js +251 -27
- package/lib/guard-regex.js +226 -18
- package/lib/guard-shell.js +229 -26
- package/lib/guard-svg.js +177 -10
- package/lib/guard-template.js +232 -21
- package/lib/guard-time.js +195 -29
- package/lib/guard-uuid.js +189 -30
- package/lib/guard-xml.js +259 -36
- package/lib/guard-yaml.js +241 -44
- package/lib/honeytoken.js +63 -27
- package/lib/html-balance.js +83 -0
- package/lib/http-client.js +486 -59
- package/lib/http-message-signature.js +582 -0
- package/lib/i18n.js +102 -49
- package/lib/iab-mspa.js +112 -32
- package/lib/iab-tcf.js +107 -2
- package/lib/inbox.js +90 -52
- package/lib/keychain.js +865 -0
- package/lib/legal-hold.js +374 -0
- package/lib/local-db-thin.js +320 -0
- package/lib/log-stream.js +281 -51
- package/lib/log.js +184 -86
- package/lib/mail-bounce.js +107 -62
- package/lib/mail.js +295 -58
- package/lib/mcp.js +108 -27
- package/lib/metrics.js +98 -89
- package/lib/middleware/age-gate.js +36 -0
- package/lib/middleware/ai-act-disclosure.js +37 -0
- package/lib/middleware/api-encrypt.js +45 -0
- package/lib/middleware/assetlinks.js +40 -0
- package/lib/middleware/asyncapi-serve.js +35 -0
- package/lib/middleware/attach-user.js +40 -0
- package/lib/middleware/bearer-auth.js +40 -0
- package/lib/middleware/body-parser.js +230 -0
- package/lib/middleware/bot-disclose.js +34 -0
- package/lib/middleware/bot-guard.js +39 -0
- package/lib/middleware/compression.js +37 -0
- package/lib/middleware/cookies.js +32 -0
- package/lib/middleware/cors.js +40 -0
- package/lib/middleware/csp-nonce.js +40 -0
- package/lib/middleware/csp-report.js +34 -0
- package/lib/middleware/csrf-protect.js +43 -0
- package/lib/middleware/daily-byte-quota.js +53 -85
- package/lib/middleware/db-role-for.js +40 -0
- package/lib/middleware/dpop.js +40 -0
- package/lib/middleware/error-handler.js +37 -14
- package/lib/middleware/fetch-metadata.js +39 -0
- package/lib/middleware/flag-context.js +34 -0
- package/lib/middleware/gpc.js +33 -0
- package/lib/middleware/headers.js +35 -0
- package/lib/middleware/health.js +46 -0
- package/lib/middleware/host-allowlist.js +30 -0
- package/lib/middleware/network-allowlist.js +38 -0
- package/lib/middleware/openapi-serve.js +34 -0
- package/lib/middleware/rate-limit.js +160 -18
- package/lib/middleware/request-id.js +36 -18
- package/lib/middleware/request-log.js +37 -0
- package/lib/middleware/require-aal.js +29 -0
- package/lib/middleware/require-auth.js +32 -0
- package/lib/middleware/require-bound-key.js +41 -0
- package/lib/middleware/require-content-type.js +32 -0
- package/lib/middleware/require-methods.js +27 -0
- package/lib/middleware/require-mtls.js +33 -0
- package/lib/middleware/require-step-up.js +37 -0
- package/lib/middleware/security-headers.js +44 -0
- package/lib/middleware/security-txt.js +38 -0
- package/lib/middleware/span-http-server.js +37 -0
- package/lib/middleware/sse.js +36 -0
- package/lib/middleware/trace-log-correlation.js +33 -0
- package/lib/middleware/trace-propagate.js +32 -0
- package/lib/middleware/tus-upload.js +90 -0
- package/lib/middleware/web-app-manifest.js +53 -0
- package/lib/mtls-ca.js +100 -70
- package/lib/network-byte-quota.js +308 -0
- package/lib/network-heartbeat.js +135 -0
- package/lib/network-tls.js +534 -4
- package/lib/network.js +103 -0
- package/lib/notify.js +114 -43
- package/lib/ntp-check.js +192 -51
- package/lib/observability.js +145 -47
- package/lib/openapi.js +90 -44
- package/lib/outbox.js +99 -1
- package/lib/pagination.js +168 -86
- package/lib/parsers/index.js +16 -5
- package/lib/permissions.js +93 -40
- package/lib/pqc-agent.js +84 -8
- package/lib/pqc-software.js +94 -60
- package/lib/process-spawn.js +95 -21
- package/lib/pubsub.js +96 -66
- package/lib/queue.js +375 -54
- package/lib/redact.js +793 -21
- package/lib/render.js +139 -47
- package/lib/request-helpers.js +485 -121
- package/lib/restore-bundle.js +142 -39
- package/lib/restore-rollback.js +136 -45
- package/lib/retention.js +178 -50
- package/lib/retry.js +116 -33
- package/lib/router.js +475 -23
- package/lib/safe-async.js +543 -94
- package/lib/safe-buffer.js +337 -41
- package/lib/safe-json.js +467 -62
- package/lib/safe-jsonpath.js +285 -0
- package/lib/safe-schema.js +631 -87
- package/lib/safe-sql.js +221 -59
- package/lib/safe-url.js +278 -46
- package/lib/sandbox-worker.js +135 -0
- package/lib/sandbox.js +358 -0
- package/lib/scheduler.js +135 -70
- package/lib/self-update.js +647 -0
- package/lib/session-device-binding.js +431 -0
- package/lib/session.js +259 -49
- package/lib/slug.js +138 -26
- package/lib/ssrf-guard.js +316 -56
- package/lib/storage.js +433 -70
- package/lib/subject.js +405 -23
- package/lib/template.js +148 -8
- package/lib/tenant-quota.js +545 -0
- package/lib/testing.js +440 -53
- package/lib/time.js +291 -23
- package/lib/tls-exporter.js +239 -0
- package/lib/tracing.js +90 -74
- package/lib/uuid.js +97 -22
- package/lib/vault/index.js +284 -22
- package/lib/vault/seal-pem-file.js +66 -0
- package/lib/watcher.js +368 -0
- package/lib/webhook.js +196 -63
- package/lib/websocket.js +393 -68
- package/lib/wiki-concepts.js +338 -0
- package/lib/worker-pool.js +464 -0
- package/package.json +3 -3
- package/sbom.cyclonedx.json +7 -7
package/lib/log-stream.js
CHANGED
|
@@ -1,56 +1,52 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* local
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
30
|
-
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* logStream.onIncoming(handler) (handler returns Promise)
|
|
51
|
-
* logStream.deliverIncoming(payload, opts?)
|
|
52
|
-
* logStream.shutdown()
|
|
53
|
-
* logStream.listSinks() → [{ name, protocol, stats }]
|
|
3
|
+
* @module b.logStream
|
|
4
|
+
* @nav Observability
|
|
5
|
+
* @title Log Stream
|
|
6
|
+
*
|
|
7
|
+
* @intro
|
|
8
|
+
* Pluggable structured-log dispatcher — fire-and-forget JSON records
|
|
9
|
+
* from request hot paths to one or many sinks (local file with
|
|
10
|
+
* rotation, generic webhook, OTLP HTTP/JSON, OTLP gRPC, AWS
|
|
11
|
+
* CloudWatch Logs, RFC 5424 syslog over UDP/TCP/TLS). Each sink
|
|
12
|
+
* keeps its own connection / fd / batch buffer, so a slow remote
|
|
13
|
+
* collector backpressures only its own queue — never the request
|
|
14
|
+
* thread that called `emit()`.
|
|
15
|
+
*
|
|
16
|
+
* Every record passes through `b.redact` BEFORE any sink sees it.
|
|
17
|
+
* PHI / PCI / JWTs / PEM blocks / AWS access keys / vault-sealed
|
|
18
|
+
* strings / credit-card-shaped digits / SSN-shaped values are
|
|
19
|
+
* stripped on the framework side, not delegated to the operator's
|
|
20
|
+
* sink config — a misnamed field cannot leak sensitive data into
|
|
21
|
+
* operational logs.
|
|
22
|
+
*
|
|
23
|
+
* Sink failures are drop-silent on the hot path: a captured Promise
|
|
24
|
+
* reroutes the error into `audit.system.log.sink_failure` so a
|
|
25
|
+
* downed collector never crashes the request that emitted the log
|
|
26
|
+
* line. Pending emits are tracked and drained on `shutdown()` so
|
|
27
|
+
* records queued just before close still reach disk / the wire.
|
|
28
|
+
*
|
|
29
|
+
* Bidirectional command channel: `onIncoming(handler)` registers a
|
|
30
|
+
* handler for inbound events; the operator wires their preferred
|
|
31
|
+
* transport (HTTP route, webhook receiver, SSE subscription,
|
|
32
|
+
* message-queue consumer) to call `deliverIncoming(payload)`, which
|
|
33
|
+
* redacts, audits, and dispatches to every registered handler. The
|
|
34
|
+
* framework provides the dispatch; the operator provides the wire.
|
|
35
|
+
*
|
|
36
|
+
* Built-in protocols:
|
|
37
|
+
* local — append-only file with size + age rotation
|
|
38
|
+
* webhook — generic HTTP POST (Splunk HEC, Datadog, Loki,
|
|
39
|
+
* Sumo Logic, custom JSON collectors)
|
|
40
|
+
* otlp — OpenTelemetry Protocol over HTTP/JSON
|
|
41
|
+
* otlp-grpc — same Logs Data Model over gRPC (higher throughput;
|
|
42
|
+
* hand-encoded protobuf, no parser dependency)
|
|
43
|
+
* cloudwatch — PutLogEvents over HTTPS with SigV4; honours the
|
|
44
|
+
* 10K-event / 1 MiB / 256 KiB-per-event AWS caps
|
|
45
|
+
* syslog — RFC 5424 octet-counting framing over UDP / TCP /
|
|
46
|
+
* TLS (default ports 514 / 6514)
|
|
47
|
+
*
|
|
48
|
+
* @card
|
|
49
|
+
* Pluggable structured-log dispatcher — fire-and-forget JSON records from request hot paths to one or many sinks (local file with rotation, generic webhook, OTLP HTTP/JSON, OTLP gRPC, AWS CloudWatch Logs, RFC 5424 syslog over UDP/TCP/TLS).
|
|
54
50
|
*/
|
|
55
51
|
var localProto = require("./log-stream-local");
|
|
56
52
|
var webhookProto = require("./log-stream-webhook");
|
|
@@ -100,6 +96,39 @@ var _inflight = new Set();
|
|
|
100
96
|
var minLevel = "info";
|
|
101
97
|
var incomingHandlers = [];
|
|
102
98
|
|
|
99
|
+
/**
|
|
100
|
+
* @primitive b.logStream.init
|
|
101
|
+
* @signature b.logStream.init(opts)
|
|
102
|
+
* @since 0.0.13
|
|
103
|
+
* @related b.logStream.bootFromEnv, b.logStream.shutdown, b.logStream.listSinks
|
|
104
|
+
*
|
|
105
|
+
* Configure the dispatcher. Call once at boot; subsequent calls are
|
|
106
|
+
* no-ops while the dispatcher is initialized (call `shutdown()` first
|
|
107
|
+
* to reconfigure). Every named sink resolves a built-in protocol
|
|
108
|
+
* (`local` / `webhook` / `otlp` / `otlp-grpc` / `cloudwatch` /
|
|
109
|
+
* `syslog`) and constructs a per-sink instance from its own typed
|
|
110
|
+
* config block.
|
|
111
|
+
*
|
|
112
|
+
* Records below `minLevel` (or a sink's per-sink `minLevel` override)
|
|
113
|
+
* are dropped before redaction — debug / info chatter on a
|
|
114
|
+
* production deployment costs nothing past the dispatcher.
|
|
115
|
+
*
|
|
116
|
+
* @opts
|
|
117
|
+
* sinks: { [name]: { protocol, minLevel?, ...protocolOpts } },
|
|
118
|
+
* minLevel: "debug" | "info" | "warn" | "error", // default "info"
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* b.logStream.init({
|
|
122
|
+
* minLevel: "info",
|
|
123
|
+
* sinks: {
|
|
124
|
+
* file: { protocol: "local", path: "/var/log/app.log" },
|
|
125
|
+
* remote: { protocol: "otlp",
|
|
126
|
+
* url: "https://collector.internal:4318/v1/logs",
|
|
127
|
+
* serviceName: "checkout",
|
|
128
|
+
* minLevel: "warn" },
|
|
129
|
+
* },
|
|
130
|
+
* });
|
|
131
|
+
*/
|
|
103
132
|
function init(opts) {
|
|
104
133
|
if (initialized) return;
|
|
105
134
|
if (!opts || !opts.sinks) throw new Error("logStream.init({ sinks }) is required");
|
|
@@ -125,6 +154,31 @@ function _shouldEmit(level, sinkLevelFilter) {
|
|
|
125
154
|
return LEVEL_PRIORITY[level] >= threshold;
|
|
126
155
|
}
|
|
127
156
|
|
|
157
|
+
/**
|
|
158
|
+
* @primitive b.logStream.emit
|
|
159
|
+
* @signature b.logStream.emit(level, message, meta?)
|
|
160
|
+
* @since 0.0.13
|
|
161
|
+
* @related b.logStream.info, b.logStream.warn, b.logStream.error, b.logStream.debug, b.redact.redact
|
|
162
|
+
*
|
|
163
|
+
* Synchronous, fire-and-forget emit to every registered sink whose
|
|
164
|
+
* level filter accepts `level`. The record is `{ ts, level, message,
|
|
165
|
+
* meta }`; `meta` is run through `b.redact.redact` BEFORE distribution
|
|
166
|
+
* so PHI / credentials / vault-sealed values never reach a sink even
|
|
167
|
+
* on a misnamed field. Sink errors are captured, audited
|
|
168
|
+
* (`system.log.sink_failure`), and discarded — a downed collector
|
|
169
|
+
* cannot crash the caller. Throws only on an unknown level (config
|
|
170
|
+
* typo at the call site).
|
|
171
|
+
*
|
|
172
|
+
* @example
|
|
173
|
+
* // Structured event with sensitive metadata — `apiKey` and
|
|
174
|
+
* // `cardNumber` are redacted by pattern before any sink sees them.
|
|
175
|
+
* b.logStream.emit("warn", "checkout retry", {
|
|
176
|
+
* orderId: "ord_01HXYZ",
|
|
177
|
+
* attempt: 3,
|
|
178
|
+
* apiKey: "sk_live_4242424242424242",
|
|
179
|
+
* cardNumber: "4111 1111 1111 1111",
|
|
180
|
+
* });
|
|
181
|
+
*/
|
|
128
182
|
function emit(level, message, meta) {
|
|
129
183
|
if (!initialized) return;
|
|
130
184
|
if (LEVELS.indexOf(level) === -1) {
|
|
@@ -164,13 +218,93 @@ function emit(level, message, meta) {
|
|
|
164
218
|
});
|
|
165
219
|
}
|
|
166
220
|
|
|
221
|
+
/**
|
|
222
|
+
* @primitive b.logStream.debug
|
|
223
|
+
* @signature b.logStream.debug(message, meta?)
|
|
224
|
+
* @since 0.0.13
|
|
225
|
+
* @related b.logStream.emit, b.logStream.info, b.logStream.warn, b.logStream.error
|
|
226
|
+
*
|
|
227
|
+
* Convenience wrapper for `emit("debug", ...)`. Records drop below
|
|
228
|
+
* `minLevel` (default `"info"`) without serialization cost, so leaving
|
|
229
|
+
* `debug()` calls in production code is cheap.
|
|
230
|
+
*
|
|
231
|
+
* @example
|
|
232
|
+
* b.logStream.debug("cache lookup", { key: "user:42", hit: false });
|
|
233
|
+
*/
|
|
167
234
|
function debug(message, meta) { emit("debug", message, meta); }
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* @primitive b.logStream.info
|
|
238
|
+
* @signature b.logStream.info(message, meta?)
|
|
239
|
+
* @since 0.0.13
|
|
240
|
+
* @related b.logStream.emit, b.logStream.debug, b.logStream.warn, b.logStream.error
|
|
241
|
+
*
|
|
242
|
+
* Convenience wrapper for `emit("info", ...)`. Use for routine
|
|
243
|
+
* lifecycle events worth keeping in the operational log under default
|
|
244
|
+
* filtering.
|
|
245
|
+
*
|
|
246
|
+
* @example
|
|
247
|
+
* b.logStream.info("worker ready", { pid: process.pid, queue: "checkout" });
|
|
248
|
+
*/
|
|
168
249
|
function info(message, meta) { emit("info", message, meta); }
|
|
250
|
+
|
|
251
|
+
/**
|
|
252
|
+
* @primitive b.logStream.warn
|
|
253
|
+
* @signature b.logStream.warn(message, meta?)
|
|
254
|
+
* @since 0.0.13
|
|
255
|
+
* @related b.logStream.emit, b.logStream.debug, b.logStream.info, b.logStream.error
|
|
256
|
+
*
|
|
257
|
+
* Convenience wrapper for `emit("warn", ...)`. Use for recoverable
|
|
258
|
+
* anomalies the operator should notice but that don't fail the
|
|
259
|
+
* request — retry exhaustion below the cap, degraded-mode entry,
|
|
260
|
+
* cache misses on a hot key.
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* b.logStream.warn("retry succeeded after backoff", {
|
|
264
|
+
* route: "POST /checkout", attempts: 4, totalMs: 1820,
|
|
265
|
+
* });
|
|
266
|
+
*/
|
|
169
267
|
function warn(message, meta) { emit("warn", message, meta); }
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* @primitive b.logStream.error
|
|
271
|
+
* @signature b.logStream.error(message, meta?)
|
|
272
|
+
* @since 0.0.13
|
|
273
|
+
* @related b.logStream.emit, b.logStream.debug, b.logStream.info, b.logStream.warn
|
|
274
|
+
*
|
|
275
|
+
* Convenience wrapper for `emit("error", ...)`. Use for the failed-
|
|
276
|
+
* request / unhandled-exception class. `b.audit` remains the
|
|
277
|
+
* authoritative tamper-evident record for privileged actions; the
|
|
278
|
+
* log stream is operational telemetry.
|
|
279
|
+
*
|
|
280
|
+
* @example
|
|
281
|
+
* b.logStream.error("dispatcher failure", {
|
|
282
|
+
* route: "POST /checkout", err: "ECONNRESET", upstream: "payments",
|
|
283
|
+
* });
|
|
284
|
+
*/
|
|
170
285
|
function error(message, meta) { emit("error", message, meta); }
|
|
171
286
|
|
|
172
287
|
// ---- Bidirectional incoming command channel ----
|
|
173
288
|
|
|
289
|
+
/**
|
|
290
|
+
* @primitive b.logStream.onIncoming
|
|
291
|
+
* @signature b.logStream.onIncoming(handler)
|
|
292
|
+
* @since 0.0.13
|
|
293
|
+
* @related b.logStream.deliverIncoming
|
|
294
|
+
*
|
|
295
|
+
* Register a handler for inbound command-channel events. Returns an
|
|
296
|
+
* unsubscribe function. Handlers may be `async` and may return a
|
|
297
|
+
* value; `deliverIncoming` collects every handler's result and reports
|
|
298
|
+
* per-handler success / failure. Throws on a non-function argument.
|
|
299
|
+
*
|
|
300
|
+
* @example
|
|
301
|
+
* var off = b.logStream.onIncoming(async function (payload) {
|
|
302
|
+
* if (payload.command === "raise-log-level") return { applied: true };
|
|
303
|
+
* return { applied: false };
|
|
304
|
+
* });
|
|
305
|
+
* // Later, when teardown is needed:
|
|
306
|
+
* off();
|
|
307
|
+
*/
|
|
174
308
|
function onIncoming(handler) {
|
|
175
309
|
if (typeof handler !== "function") {
|
|
176
310
|
throw _err("INVALID_HANDLER", "onIncoming requires a function handler", true);
|
|
@@ -182,6 +316,31 @@ function onIncoming(handler) {
|
|
|
182
316
|
};
|
|
183
317
|
}
|
|
184
318
|
|
|
319
|
+
/**
|
|
320
|
+
* @primitive b.logStream.deliverIncoming
|
|
321
|
+
* @signature b.logStream.deliverIncoming(payload, opts?)
|
|
322
|
+
* @since 0.0.13
|
|
323
|
+
* @related b.logStream.onIncoming, b.audit.safeEmit
|
|
324
|
+
*
|
|
325
|
+
* Dispatch an inbound command-channel payload to every registered
|
|
326
|
+
* handler. The payload is redacted before audit and before handlers
|
|
327
|
+
* run, so even a noisy webhook receiver cannot smuggle secrets into
|
|
328
|
+
* the audit chain. Audit-logs the receipt under
|
|
329
|
+
* `system.log.incoming` BEFORE invoking handlers — handler exceptions
|
|
330
|
+
* never erase the receipt. Returns a per-handler `[{ ok, value? |
|
|
331
|
+
* error? }]` array; one handler throwing does not abort the rest.
|
|
332
|
+
*
|
|
333
|
+
* @opts
|
|
334
|
+
* actor: { userId?, sessionId?, ip?, userAgent? }, // audit context
|
|
335
|
+
* source: string, // transport name
|
|
336
|
+
*
|
|
337
|
+
* @example
|
|
338
|
+
* var results = await b.logStream.deliverIncoming(
|
|
339
|
+
* { command: "rotate-sink", sink: "file" },
|
|
340
|
+
* { actor: { userId: "ops-42" }, source: "webhook" }
|
|
341
|
+
* );
|
|
342
|
+
* // → [{ ok: true, value: { applied: false } }]
|
|
343
|
+
*/
|
|
185
344
|
async function deliverIncoming(payload, opts) {
|
|
186
345
|
opts = opts || {};
|
|
187
346
|
var redacted = redactor.redact(payload);
|
|
@@ -204,6 +363,24 @@ async function deliverIncoming(payload, opts) {
|
|
|
204
363
|
return results;
|
|
205
364
|
}
|
|
206
365
|
|
|
366
|
+
/**
|
|
367
|
+
* @primitive b.logStream.shutdown
|
|
368
|
+
* @signature b.logStream.shutdown()
|
|
369
|
+
* @since 0.0.13
|
|
370
|
+
* @related b.logStream.init, b.appShutdown.create
|
|
371
|
+
*
|
|
372
|
+
* Drain pending fire-and-forget emits, close every sink (file fds,
|
|
373
|
+
* webhook keep-alive sockets, syslog connections, OTLP gRPC streams),
|
|
374
|
+
* and clear registered incoming handlers. Idempotent — safe to call
|
|
375
|
+
* twice. Records queued just before shutdown reach disk / the wire
|
|
376
|
+
* because in-flight Promises are tracked and awaited before close.
|
|
377
|
+
*
|
|
378
|
+
* @example
|
|
379
|
+
* process.on("SIGTERM", async function () {
|
|
380
|
+
* await b.logStream.shutdown();
|
|
381
|
+
* process.exit(0);
|
|
382
|
+
* });
|
|
383
|
+
*/
|
|
207
384
|
async function shutdown() {
|
|
208
385
|
if (!initialized) return;
|
|
209
386
|
// Drain any in-flight emits before closing sink fds so records
|
|
@@ -222,6 +399,23 @@ async function shutdown() {
|
|
|
222
399
|
initialized = false;
|
|
223
400
|
}
|
|
224
401
|
|
|
402
|
+
/**
|
|
403
|
+
* @primitive b.logStream.listSinks
|
|
404
|
+
* @signature b.logStream.listSinks()
|
|
405
|
+
* @since 0.0.13
|
|
406
|
+
* @related b.logStream.init
|
|
407
|
+
*
|
|
408
|
+
* Return one descriptor per configured sink: `{ name, protocol, stats
|
|
409
|
+
* }`. Sinks that expose a `stats()` method (file rotation counters,
|
|
410
|
+
* webhook batch metrics, OTLP queue depth) report through it; those
|
|
411
|
+
* that don't return `null`. Returns `[]` before `init()` runs, so
|
|
412
|
+
* health endpoints can call it unconditionally.
|
|
413
|
+
*
|
|
414
|
+
* @example
|
|
415
|
+
* var snapshot = b.logStream.listSinks();
|
|
416
|
+
* // → [{ name: "file", protocol: "local",
|
|
417
|
+
* // stats: { rotations: 2, bytesWritten: 4194304 } }]
|
|
418
|
+
*/
|
|
225
419
|
function listSinks() {
|
|
226
420
|
if (!initialized) return [];
|
|
227
421
|
return Object.keys(sinks).map(function (name) {
|
|
@@ -255,6 +449,42 @@ function listSinks() {
|
|
|
255
449
|
// BLAMEJS_LOG_STREAM_CLOUDWATCH_LOG_STREAM
|
|
256
450
|
// local-only:
|
|
257
451
|
// BLAMEJS_LOG_STREAM_PATH
|
|
452
|
+
/**
|
|
453
|
+
* @primitive b.logStream.bootFromEnv
|
|
454
|
+
* @signature b.logStream.bootFromEnv(opts?)
|
|
455
|
+
* @since 0.6.25
|
|
456
|
+
* @related b.logStream.init, b.network.bootFromEnv
|
|
457
|
+
*
|
|
458
|
+
* Operator-friendly env-driven init. Reads `BLAMEJS_LOG_STREAM_*` (and
|
|
459
|
+
* standard `AWS_*`) variables and constructs a single-sink
|
|
460
|
+
* configuration. Returns `false` and skips silently when
|
|
461
|
+
* `BLAMEJS_LOG_STREAM_PROTOCOL` is unset, so deployments that wire
|
|
462
|
+
* sinks through `init()` keep their existing config. Throws on an
|
|
463
|
+
* unknown protocol value.
|
|
464
|
+
*
|
|
465
|
+
* Recognised variables: `BLAMEJS_LOG_STREAM_PROTOCOL` (`local` |
|
|
466
|
+
* `webhook` | `otlp` | `cloudwatch`), `BLAMEJS_LOG_STREAM_MIN_LEVEL`,
|
|
467
|
+
* `BLAMEJS_LOG_STREAM_URL`, `BLAMEJS_LOG_STREAM_TOKEN`,
|
|
468
|
+
* `BLAMEJS_LOG_STREAM_SERVICE_NAME`, `BLAMEJS_LOG_STREAM_PATH`,
|
|
469
|
+
* `BLAMEJS_LOG_STREAM_CLOUDWATCH_LOG_GROUP`, plus `AWS_REGION` /
|
|
470
|
+
* `AWS_ACCESS_KEY_ID` / `AWS_SECRET_ACCESS_KEY` / `AWS_SESSION_TOKEN`.
|
|
471
|
+
*
|
|
472
|
+
* @opts
|
|
473
|
+
* env: object, // override process.env (testing / fixtures)
|
|
474
|
+
*
|
|
475
|
+
* @example
|
|
476
|
+
* // Operator sets BLAMEJS_LOG_STREAM_PROTOCOL=otlp and the URL in
|
|
477
|
+
* // the deployment manifest; the framework wires the sink at boot.
|
|
478
|
+
* var wired = b.logStream.bootFromEnv({
|
|
479
|
+
* env: {
|
|
480
|
+
* BLAMEJS_LOG_STREAM_PROTOCOL: "otlp",
|
|
481
|
+
* BLAMEJS_LOG_STREAM_URL: "https://collector.internal:4318/v1/logs",
|
|
482
|
+
* BLAMEJS_LOG_STREAM_SERVICE_NAME: "checkout",
|
|
483
|
+
* BLAMEJS_LOG_STREAM_MIN_LEVEL: "info",
|
|
484
|
+
* },
|
|
485
|
+
* });
|
|
486
|
+
* // → true (false when BLAMEJS_LOG_STREAM_PROTOCOL is unset)
|
|
487
|
+
*/
|
|
258
488
|
function bootFromEnv(opts) {
|
|
259
489
|
opts = opts || {};
|
|
260
490
|
var env = opts.env || process.env;
|