@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/deprecate.js
CHANGED
|
@@ -1,53 +1,49 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* @module b.deprecate
|
|
4
|
+
* @nav Production
|
|
5
|
+
* @title Deprecate
|
|
4
6
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* @intro
|
|
8
|
+
* Runtime deprecation-warning system for the framework's LTS
|
|
9
|
+
* contract. Operators see a one-time stderr warning the first time
|
|
10
|
+
* deprecated surface is used, naming the version it was deprecated
|
|
11
|
+
* in and the version it will be removed in — so behavior changes
|
|
12
|
+
* ship visible at least one minor before the breakage lands in a
|
|
13
|
+
* major.
|
|
11
14
|
*
|
|
12
|
-
*
|
|
15
|
+
* Three usage shapes:
|
|
13
16
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
17
|
+
* - `warn(name, opts)` — emit a warning at the call site of an
|
|
18
|
+
* inline deprecated path.
|
|
19
|
+
* - `wrap(fn, name, opts)` — return a wrapper around the
|
|
20
|
+
* replacement function so calls to the old name auto-warn and
|
|
21
|
+
* delegate.
|
|
22
|
+
* - `alias(target, oldKey, newKey, opts)` — define `oldKey` on
|
|
23
|
+
* `target` as a getter/setter that warns on access and reads
|
|
24
|
+
* through to `newKey`.
|
|
21
25
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
* });
|
|
26
|
+
* Warnings dedupe by `(name, since)` — calling `warn` ten thousand
|
|
27
|
+
* times with the same args emits a single stderr line; the per-name
|
|
28
|
+
* call counter is still incremented so `list()` reflects real usage
|
|
29
|
+
* volume for ops dashboards.
|
|
27
30
|
*
|
|
28
|
-
*
|
|
29
|
-
* dep.alias(targetObj, "oldKey", "newKey", {
|
|
30
|
-
* since: "0.2.0", removeIn: "0.4.0",
|
|
31
|
-
* });
|
|
32
|
-
*
|
|
33
|
-
* dep.list(); // → [{ name, since, removeIn, callCount, firstSeen }]
|
|
34
|
-
* dep.reset(); // clears the seen-set; tests
|
|
31
|
+
* `BLAMEJS_DEPRECATIONS` env var controls runtime behavior:
|
|
35
32
|
*
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
33
|
+
* - `"warn"` — stderr warning on first use (default outside
|
|
34
|
+
* production).
|
|
35
|
+
* - `"silent"` — skip entirely (default in production; operators
|
|
36
|
+
* do not want stderr noise from deprecated paths
|
|
37
|
+
* in code they do not own).
|
|
38
|
+
* - `"error"` — throw on first use; development tool to surface
|
|
39
|
+
* every deprecated call site as a hard failure
|
|
40
|
+
* during a sweep.
|
|
42
41
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
* 2. "silent" when process.env.NODE_ENV === "production"
|
|
46
|
-
* 3. "warn" otherwise
|
|
42
|
+
* Mode resolution: explicit env var first, then `"silent"` when
|
|
43
|
+
* `NODE_ENV=production`, otherwise `"warn"`.
|
|
47
44
|
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* call counter is still incremented so dep.list() shows usage volume.
|
|
45
|
+
* @card
|
|
46
|
+
* Runtime deprecation-warning system for the framework's LTS contract.
|
|
51
47
|
*/
|
|
52
48
|
|
|
53
49
|
var safeEnv = require("./parsers/safe-env");
|
|
@@ -95,6 +91,38 @@ function _validateOpts(opts, fnName) {
|
|
|
95
91
|
validateOpts.requireNonEmptyString(opts.removeIn, fnName + ": opts.removeIn (version string)", DeprecateError, "deprecate/bad-opts");
|
|
96
92
|
}
|
|
97
93
|
|
|
94
|
+
/**
|
|
95
|
+
* @primitive b.deprecate.warn
|
|
96
|
+
* @signature b.deprecate.warn(name, opts)
|
|
97
|
+
* @since 0.1.90
|
|
98
|
+
* @status stable
|
|
99
|
+
* @related b.deprecate.wrap, b.deprecate.alias, b.deprecate.list
|
|
100
|
+
*
|
|
101
|
+
* Emit a deprecation warning for an inline call site. First call for a
|
|
102
|
+
* given `(name, since)` pair writes a single line to stderr in `"warn"`
|
|
103
|
+
* mode, throws `DeprecateError` in `"error"` mode, and is suppressed
|
|
104
|
+
* in `"silent"` mode. Subsequent calls dedupe but still increment the
|
|
105
|
+
* per-name call counter so `list()` reports real usage volume. Throws
|
|
106
|
+
* `DeprecateError` (`deprecate/bad-name`) on missing `name` and
|
|
107
|
+
* (`deprecate/bad-opts`) when `since` or `removeIn` are missing or
|
|
108
|
+
* empty.
|
|
109
|
+
*
|
|
110
|
+
* @opts
|
|
111
|
+
* since: string, // required; semver this surface was deprecated in
|
|
112
|
+
* removeIn: string, // required; semver of planned removal
|
|
113
|
+
* message: string, // optional human-readable replacement guidance
|
|
114
|
+
* hint: string, // optional cross-reference (MIGRATING.md anchor)
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* var b = require("@blamejs/core");
|
|
118
|
+
* b.deprecate.warn("auth.legacyVerify", {
|
|
119
|
+
* since: "0.2.0",
|
|
120
|
+
* removeIn: "0.4.0",
|
|
121
|
+
* message: "use auth.password.verify(stored, plain) instead",
|
|
122
|
+
* hint: "see MIGRATING.md#0-2-to-0-4",
|
|
123
|
+
* });
|
|
124
|
+
* // → undefined (stderr: [blamejs:deprecated] auth.legacyVerify (since 0.2.0); removed in 0.4.0 — ...)
|
|
125
|
+
*/
|
|
98
126
|
function warn(name, opts) {
|
|
99
127
|
if (typeof name !== "string" || name.length === 0) {
|
|
100
128
|
throw new DeprecateError("deprecate/bad-name",
|
|
@@ -137,6 +165,38 @@ function warn(name, opts) {
|
|
|
137
165
|
// Wrap a function so calling it issues a deprecation warning + delegates.
|
|
138
166
|
// The wrapper preserves the original function's `.length` (arity) so
|
|
139
167
|
// callers introspecting it as a callable see the same shape.
|
|
168
|
+
/**
|
|
169
|
+
* @primitive b.deprecate.wrap
|
|
170
|
+
* @signature b.deprecate.wrap(fn, name, opts)
|
|
171
|
+
* @since 0.1.90
|
|
172
|
+
* @status stable
|
|
173
|
+
* @related b.deprecate.warn, b.deprecate.alias
|
|
174
|
+
*
|
|
175
|
+
* Return a function that warns on first invocation then delegates to
|
|
176
|
+
* `fn` with the same `this` and arguments. Use to keep the old export
|
|
177
|
+
* name working through one minor version after rename. The wrapper's
|
|
178
|
+
* `.name` is set to `<name>:deprecated` for stack-trace clarity. Same
|
|
179
|
+
* dedupe + mode rules as `warn`. Throws `DeprecateError`
|
|
180
|
+
* (`deprecate/bad-target`) when `fn` is not a function and
|
|
181
|
+
* (`deprecate/bad-name`) on missing `name`.
|
|
182
|
+
*
|
|
183
|
+
* @opts
|
|
184
|
+
* since: string, // required; semver this surface was deprecated in
|
|
185
|
+
* removeIn: string, // required; semver of planned removal
|
|
186
|
+
* message: string, // optional human-readable replacement guidance
|
|
187
|
+
* hint: string, // optional cross-reference (MIGRATING.md anchor)
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* var b = require("@blamejs/core");
|
|
191
|
+
* function passwordVerify(stored, plain) { return stored === plain; }
|
|
192
|
+
* var legacyVerify = b.deprecate.wrap(passwordVerify, "auth.legacyVerify", {
|
|
193
|
+
* since: "0.2.0",
|
|
194
|
+
* removeIn: "0.4.0",
|
|
195
|
+
* message: "renamed to auth.password.verify",
|
|
196
|
+
* });
|
|
197
|
+
* var ok = legacyVerify("stored", "plain");
|
|
198
|
+
* // → false (stderr warns once on first call)
|
|
199
|
+
*/
|
|
140
200
|
function wrap(fn, name, opts) {
|
|
141
201
|
if (typeof fn !== "function") {
|
|
142
202
|
throw new DeprecateError("deprecate/bad-target",
|
|
@@ -159,6 +219,39 @@ function wrap(fn, name, opts) {
|
|
|
159
219
|
// Define `oldKey` on `target` as a getter that warns then returns
|
|
160
220
|
// `target[newKey]`. The setter writes through so existing assignments
|
|
161
221
|
// still work, but the getter access trips the warning.
|
|
222
|
+
/**
|
|
223
|
+
* @primitive b.deprecate.alias
|
|
224
|
+
* @signature b.deprecate.alias(target, oldKey, newKey, opts)
|
|
225
|
+
* @since 0.1.90
|
|
226
|
+
* @status stable
|
|
227
|
+
* @related b.deprecate.wrap, b.deprecate.warn
|
|
228
|
+
*
|
|
229
|
+
* Define a getter/setter on `target.oldKey` that warns on access and
|
|
230
|
+
* reads/writes through to `target.newKey`. Use to keep a renamed
|
|
231
|
+
* property accessible for one minor without losing visibility into
|
|
232
|
+
* who still reads the old name. The aliased property is non-
|
|
233
|
+
* enumerable (so it does not leak into `Object.keys` / JSON
|
|
234
|
+
* serialization) but configurable so tests can redefine it. Throws
|
|
235
|
+
* `DeprecateError` (`deprecate/bad-target`) when `target` is not an
|
|
236
|
+
* object and (`deprecate/bad-name`) on missing `oldKey` / `newKey`.
|
|
237
|
+
*
|
|
238
|
+
* @opts
|
|
239
|
+
* since: string, // required; semver this surface was deprecated in
|
|
240
|
+
* removeIn: string, // required; semver of planned removal
|
|
241
|
+
* message: string, // optional override; defaults to "use 'newKey' instead"
|
|
242
|
+
* hint: string, // optional cross-reference (MIGRATING.md anchor)
|
|
243
|
+
* aliasName: string, // optional override for the warned identifier
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* var b = require("@blamejs/core");
|
|
247
|
+
* var settings = { timeout: 5000 };
|
|
248
|
+
* b.deprecate.alias(settings, "timeoutMs", "timeout", {
|
|
249
|
+
* since: "0.3.0",
|
|
250
|
+
* removeIn: "0.5.0",
|
|
251
|
+
* });
|
|
252
|
+
* var v = settings.timeoutMs;
|
|
253
|
+
* // → 5000 (stderr warns once on first read)
|
|
254
|
+
*/
|
|
162
255
|
function alias(target, oldKey, newKey, opts) {
|
|
163
256
|
if (!target || typeof target !== "object") {
|
|
164
257
|
throw new DeprecateError("deprecate/bad-target",
|
|
@@ -187,6 +280,28 @@ function alias(target, oldKey, newKey, opts) {
|
|
|
187
280
|
});
|
|
188
281
|
}
|
|
189
282
|
|
|
283
|
+
/**
|
|
284
|
+
* @primitive b.deprecate.list
|
|
285
|
+
* @signature b.deprecate.list()
|
|
286
|
+
* @since 0.1.90
|
|
287
|
+
* @status stable
|
|
288
|
+
* @related b.deprecate.warn, b.deprecate.reset, b.deprecate.getMode
|
|
289
|
+
*
|
|
290
|
+
* Return an array of every deprecated identifier hit during this
|
|
291
|
+
* process's lifetime — `{ name, since, removeIn, callCount,
|
|
292
|
+
* firstSeen }`. Sorted most-frequent first, ties broken by earliest
|
|
293
|
+
* `firstSeen`. Use from an ops dashboard or boot diagnostic to surface
|
|
294
|
+
* which deprecated paths the running deployment still exercises so
|
|
295
|
+
* the team can prioritize migrations before the `removeIn` major
|
|
296
|
+
* lands.
|
|
297
|
+
*
|
|
298
|
+
* @example
|
|
299
|
+
* var b = require("@blamejs/core");
|
|
300
|
+
* b.deprecate.warn("auth.legacyVerify", { since: "0.2.0", removeIn: "0.4.0" });
|
|
301
|
+
* var rows = b.deprecate.list();
|
|
302
|
+
* // → [{ name: "auth.legacyVerify", since: "0.2.0", removeIn: "0.4.0",
|
|
303
|
+
* // callCount: 1, firstSeen: "2026-05-09T12:00:00.000Z" }]
|
|
304
|
+
*/
|
|
190
305
|
function list() {
|
|
191
306
|
var out = [];
|
|
192
307
|
_seen.forEach(function (v) {
|
|
@@ -206,9 +321,49 @@ function list() {
|
|
|
206
321
|
return out;
|
|
207
322
|
}
|
|
208
323
|
|
|
324
|
+
/**
|
|
325
|
+
* @primitive b.deprecate.reset
|
|
326
|
+
* @signature b.deprecate.reset()
|
|
327
|
+
* @since 0.1.90
|
|
328
|
+
* @status stable
|
|
329
|
+
* @related b.deprecate.list, b.deprecate.warn
|
|
330
|
+
*
|
|
331
|
+
* Clear the seen-set so subsequent `warn` / `wrap` / `alias` calls
|
|
332
|
+
* re-emit their first-use warnings. Used by tests that exercise the
|
|
333
|
+
* deprecation path repeatedly; not meant for production code, where
|
|
334
|
+
* the dedupe is intentional.
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* var b = require("@blamejs/core");
|
|
338
|
+
* b.deprecate.warn("auth.legacyVerify", { since: "0.2.0", removeIn: "0.4.0" });
|
|
339
|
+
* b.deprecate.reset();
|
|
340
|
+
* var seen = b.deprecate.list();
|
|
341
|
+
* // → []
|
|
342
|
+
*/
|
|
209
343
|
function reset() { _seen.clear(); }
|
|
210
344
|
|
|
211
345
|
// Export the resolved mode so tests + ops dashboards can introspect
|
|
346
|
+
/**
|
|
347
|
+
* @primitive b.deprecate.getMode
|
|
348
|
+
* @signature b.deprecate.getMode()
|
|
349
|
+
* @since 0.1.90
|
|
350
|
+
* @status stable
|
|
351
|
+
* @related b.deprecate.warn, b.deprecate.list
|
|
352
|
+
*
|
|
353
|
+
* Return the resolved deprecation mode for the current process —
|
|
354
|
+
* `"warn"`, `"silent"`, or `"error"`. Resolution order: explicit
|
|
355
|
+
* `BLAMEJS_DEPRECATIONS` env var, then `"silent"` when
|
|
356
|
+
* `NODE_ENV=production`, otherwise `"warn"`. Use from boot diagnostics
|
|
357
|
+
* or test setup to confirm the active posture before exercising
|
|
358
|
+
* deprecated paths.
|
|
359
|
+
*
|
|
360
|
+
* @example
|
|
361
|
+
* var b = require("@blamejs/core");
|
|
362
|
+
* var mode = b.deprecate.getMode();
|
|
363
|
+
* // → "warn" (development default)
|
|
364
|
+
* // → "silent" (NODE_ENV=production)
|
|
365
|
+
* // → "error" (BLAMEJS_DEPRECATIONS=error)
|
|
366
|
+
*/
|
|
212
367
|
function getMode() { return _modeFromEnv(); }
|
|
213
368
|
|
|
214
369
|
module.exports = {
|
package/lib/dev.js
CHANGED
|
@@ -1,50 +1,51 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* @module b.dev
|
|
4
|
+
* @nav Tools
|
|
5
|
+
* @title Dev
|
|
4
6
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* "I just edited a route handler and want to see it."
|
|
7
|
+
* @intro
|
|
8
|
+
* Dev-mode helpers — hot-reload signal (file watch + child-process
|
|
9
|
+
* restart), route-list dump exposed via `dev.stats()`, and a request
|
|
10
|
+
* inspector courtesy of `stdio: 'inherit'` so the operator sees the
|
|
11
|
+
* spawned app's logs unchanged.
|
|
11
12
|
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
* killTimeoutMs: 4000, // SIGKILL after this if SIGTERM is ignored
|
|
20
|
-
* log: logInstance, // optional structured logger
|
|
21
|
-
* env: { ...process.env, BLAMEJS_DEV: "1" },
|
|
22
|
-
* cwd: process.cwd(),
|
|
23
|
-
* });
|
|
13
|
+
* The hot-reload loop spawns the app as a child process, watches the
|
|
14
|
+
* source directories with `fs.watch({ recursive: true })`, and
|
|
15
|
+
* restarts the child when an unignored file changes. On-disk state
|
|
16
|
+
* (vault keys, encrypted DB, sealed cookies) survives the restart
|
|
17
|
+
* because the child re-opens the files; only in-process state is
|
|
18
|
+
* lost, which is the correct semantic for "I just edited a route
|
|
19
|
+
* handler and want to see it."
|
|
24
20
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
21
|
+
* Hygiene baked in:
|
|
22
|
+
* - Bursts of file events (save-everything keystrokes, multi-file
|
|
23
|
+
* format-on-save) collapse into one restart via the `graceMs`
|
|
24
|
+
* debounce (default 250 ms).
|
|
25
|
+
* - A restart-in-flight queues at most one follow-up — many edits
|
|
26
|
+
* during a slow restart yield two restarts, not N.
|
|
27
|
+
* - Ignored kinds by default: `node_modules/`, `.git/`, dotfiles,
|
|
28
|
+
* SQLite journal/WAL/SHM siblings, `.log`, editor scratch files
|
|
29
|
+
* (`.swp`, `~$`).
|
|
30
|
+
* - Crash without a pending stop/restart leaves the child corpse
|
|
31
|
+
* in place and waits for a file change rather than spawn-thrashing.
|
|
32
|
+
* - Graceful kill via `SIGTERM`; `SIGKILL` escalation after
|
|
33
|
+
* `killTimeoutMs` (default 4000 ms) if the child ignores it.
|
|
27
34
|
*
|
|
28
|
-
* dev.
|
|
35
|
+
* Production refusal: `dev.create()` throws `dev/refused-in-production`
|
|
36
|
+
* when `NODE_ENV=production`, unless the operator explicitly sets
|
|
37
|
+
* `opts.allowProduction: true` with an audited reason. This is what
|
|
38
|
+
* `blamejs dev` (CLI) calls; production deployments that accidentally
|
|
39
|
+
* wire it crash loudly at boot rather than spawning shells on every
|
|
40
|
+
* save.
|
|
29
41
|
*
|
|
30
|
-
*
|
|
42
|
+
* Test seams: `opts._spawn(cmd, args, sopts)` and
|
|
43
|
+
* `opts._watch(dir, wopts, listener)` default to `child_process.spawn`
|
|
44
|
+
* and `fs.watch`; unit tests pass fakes to drive the engine without
|
|
45
|
+
* real subprocesses.
|
|
31
46
|
*
|
|
32
|
-
*
|
|
33
|
-
* -
|
|
34
|
-
* file format-on-save) collapse into one restart via debounce.
|
|
35
|
-
* - The child is spawned with stdio: 'inherit' so the operator sees
|
|
36
|
-
* their app's output unchanged.
|
|
37
|
-
* - Parent SIGINT/SIGTERM are forwarded: stop() before exit so an
|
|
38
|
-
* orphan child can't outlive the dev session.
|
|
39
|
-
* - Restart in-flight when a new event arrives: queue one followup,
|
|
40
|
-
* no more — many edits during a slow restart still result in only
|
|
41
|
-
* two restarts, not N.
|
|
42
|
-
*
|
|
43
|
-
* Test seams:
|
|
44
|
-
* opts._spawn(cmd, args, sopts) → child-process-shaped object
|
|
45
|
-
* opts._watch(dir, wopts, listener) → fs.watcher-shaped object
|
|
46
|
-
* These default to child_process.spawn and fs.watch; tests pass
|
|
47
|
-
* fakes to drive the engine without real subprocesses.
|
|
47
|
+
* @card
|
|
48
|
+
* Dev-mode helpers — hot-reload signal (file watch + child-process restart), route-list dump exposed via `dev.stats()`, and a request inspector courtesy of `stdio: 'inherit'` so the operator sees the spawned app's logs unchanged.
|
|
48
49
|
*/
|
|
49
50
|
|
|
50
51
|
var path = require("path");
|
|
@@ -114,6 +115,48 @@ function _logVia(log, level, message, fields) {
|
|
|
114
115
|
emit(line);
|
|
115
116
|
}
|
|
116
117
|
|
|
118
|
+
/**
|
|
119
|
+
* @primitive b.dev.create
|
|
120
|
+
* @signature b.dev.create(opts)
|
|
121
|
+
* @since 0.4.0
|
|
122
|
+
* @status stable
|
|
123
|
+
*
|
|
124
|
+
* Build a hot-reload supervisor — spawn `opts.command` with `opts.args`,
|
|
125
|
+
* watch `opts.watch` directories, and restart the child on every
|
|
126
|
+
* unignored file change. Returns `{ start, stop, restart, stats }`;
|
|
127
|
+
* `stats()` reports `{ pid, running, restarts, lastRestartAt, watchers }`.
|
|
128
|
+
*
|
|
129
|
+
* Throws `DevError` at config time on a missing command, a non-finite
|
|
130
|
+
* `graceMs` / `killTimeoutMs`, or an attempt to load with
|
|
131
|
+
* `NODE_ENV=production` (without `opts.allowProduction`).
|
|
132
|
+
*
|
|
133
|
+
* @opts
|
|
134
|
+
* command: string, // required — program to spawn (e.g. "node")
|
|
135
|
+
* args: [string], // argv after command; default []
|
|
136
|
+
* watch: [string], // directories to watch (recursive); default ["."]
|
|
137
|
+
* ignore: [RegExp | string], // appended to the framework default-ignore list
|
|
138
|
+
* graceMs: number, // debounce window (ms); default 250
|
|
139
|
+
* killSignal: string, // initial kill signal; default "SIGTERM"
|
|
140
|
+
* killTimeoutMs: number, // SIGKILL escalation budget (ms); default 4000
|
|
141
|
+
* log: object, // structured logger ({ info, warn, error })
|
|
142
|
+
* env: object, // child env; default process.env
|
|
143
|
+
* cwd: string, // child cwd; default process.cwd()
|
|
144
|
+
* stdio: string | array, // child stdio; default "inherit"
|
|
145
|
+
* allowProduction: boolean, // override the production refusal (audited reason required)
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* var dev = b.dev.create({
|
|
149
|
+
* command: "node",
|
|
150
|
+
* args: ["./server.js"],
|
|
151
|
+
* watch: ["./routes", "./views", "./lib"],
|
|
152
|
+
* ignore: [/\.tmp$/],
|
|
153
|
+
* graceMs: 250,
|
|
154
|
+
* });
|
|
155
|
+
*
|
|
156
|
+
* // await dev.start();
|
|
157
|
+
* // dev.stats(); // → { pid: <number>, running: true, restarts: 0, lastRestartAt: null, watchers: 3 }
|
|
158
|
+
* // await dev.stop();
|
|
159
|
+
*/
|
|
117
160
|
function create(opts) {
|
|
118
161
|
opts = opts || {};
|
|
119
162
|
validateOpts.requireNonEmptyString(opts.command, "dev.create: opts.command (the program to spawn)", DevError, "dev/no-command");
|
package/lib/dora.js
CHANGED
|
@@ -1,56 +1,29 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* b.dora
|
|
3
|
+
* @module b.dora
|
|
4
|
+
* @nav Compliance
|
|
5
|
+
* @title DORA
|
|
4
6
|
*
|
|
5
|
-
*
|
|
6
|
-
* Article 17
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* classification rubric, the
|
|
12
|
-
* intermediate / final), and
|
|
7
|
+
* @intro
|
|
8
|
+
* DORA Article 17 ICT-related incident-reporting workflow. The
|
|
9
|
+
* Digital Operational Resilience Act (Regulation (EU) 2022/2554)
|
|
10
|
+
* Article 17 requires every "financial entity" subject to DORA to
|
|
11
|
+
* classify, document, and report ICT-related incidents according to
|
|
12
|
+
* the harmonized RTS template (Commission Delegated Regulation
|
|
13
|
+
* 2024/1772). The framework owns the classification rubric, the
|
|
14
|
+
* three-stage report shape (initial / intermediate / final), and
|
|
15
|
+
* the audit-chain integration; operators wire the produced
|
|
16
|
+
* RTS-template-shaped records into their submission code (channel
|
|
17
|
+
* + ESA / national-supervisor credentials are operator-specific —
|
|
18
|
+
* the framework does NOT submit on the operator's behalf).
|
|
13
19
|
*
|
|
14
|
-
*
|
|
20
|
+
* Adjacent regimes (NIS2 Art. 23, CRA Art. 14, HIPAA breach
|
|
21
|
+
* notification) share the deadline-tracking shape; reference
|
|
22
|
+
* constants live on the module so operators don't pin literal hour
|
|
23
|
+
* counts in their reporters.
|
|
15
24
|
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
* systemsAffected: ["payments-gateway", "core-ledger"],
|
|
19
|
-
* durationMs: C.TIME.hours(4),
|
|
20
|
-
* severityIndicator: "critical" | "high" | "medium" | "low",
|
|
21
|
-
* economicImpact: { eur: 50000 },
|
|
22
|
-
* affectedClients: 1200,
|
|
23
|
-
* geographicScope: ["DE", "FR"],
|
|
24
|
-
* reputationalImpact: "media" | "internal" | "none",
|
|
25
|
-
* });
|
|
26
|
-
* // → { classification: "major" | "significant" | "minor",
|
|
27
|
-
* // mustReport: true|false, mustReportInitialBy: ms-since-detection,
|
|
28
|
-
* // reasons: [...] }
|
|
29
|
-
*
|
|
30
|
-
* var initial = dora.report({
|
|
31
|
-
* incidentId: "INC-2026-0042",
|
|
32
|
-
* classification: "major",
|
|
33
|
-
* stage: "initial",
|
|
34
|
-
* detectedAt: Date.now() - C.TIME.minutes(60),
|
|
35
|
-
* description: "Payment-gateway outage — 2-hour customer-facing impact",
|
|
36
|
-
* causeKnown: false,
|
|
37
|
-
* mitigationStarted: true,
|
|
38
|
-
* });
|
|
39
|
-
*
|
|
40
|
-
* // 72h after detection: intermediate update
|
|
41
|
-
* dora.report(Object.assign({}, initial, { stage: "intermediate", ... }));
|
|
42
|
-
* // 1 month later (or upon closure): final report
|
|
43
|
-
* dora.report(Object.assign({}, initial, { stage: "final", rootCause: "...", ... }));
|
|
44
|
-
*
|
|
45
|
-
* Audit posture (audit namespace "dora"):
|
|
46
|
-
* - dora.incident.classified — every classify() call
|
|
47
|
-
* - dora.incident.reported — every report() submission
|
|
48
|
-
* - dora.incident.draftFinal — every draftFinalReport() generation
|
|
49
|
-
*
|
|
50
|
-
* The primitive does NOT submit to ESAs / national supervisors — that
|
|
51
|
-
* step is operator-side (channel + credentials are operator-specific).
|
|
52
|
-
* The primitive produces the RTS-template-shaped record that the
|
|
53
|
-
* operator's submission code drops into the regulator's API.
|
|
25
|
+
* @card
|
|
26
|
+
* DORA Article 17 ICT-related incident-reporting workflow.
|
|
54
27
|
*/
|
|
55
28
|
|
|
56
29
|
var lazyRequire = require("./lazy-require");
|
|
@@ -253,6 +226,52 @@ function _validateReportInput(input) {
|
|
|
253
226
|
|
|
254
227
|
// ---- Public surface ----
|
|
255
228
|
|
|
229
|
+
/**
|
|
230
|
+
* @primitive b.dora.create
|
|
231
|
+
* @signature b.dora.create(opts)
|
|
232
|
+
* @since 0.7.25
|
|
233
|
+
* @status stable
|
|
234
|
+
* @compliance dora, nis2, cra, hipaa
|
|
235
|
+
* @related b.audit.safeEmit
|
|
236
|
+
*
|
|
237
|
+
* Build a DORA reporter handle exposing `classify`, `report`, and
|
|
238
|
+
* `draftFinalReport`. `classify` runs the RTS 2024/1772 Articles
|
|
239
|
+
* 1-12 thresholds (severity / affected clients / economic impact /
|
|
240
|
+
* geographic scope / duration / reputational / sensitive-data
|
|
241
|
+
* classes) and returns the regulatory tier (`"major"` / `"significant"`
|
|
242
|
+
* / `"minor"`) plus a deadline hint. `report` validates and shapes
|
|
243
|
+
* the operator's payload into an RTS-template record carrying the
|
|
244
|
+
* `nextStageDueAt` deadline (Art. 19 — 24h initial / 72h intermediate
|
|
245
|
+
* / 30-day final). `draftFinalReport` clones a prior record into a
|
|
246
|
+
* Stage-final skeleton with the operator-fillable fields zeroed.
|
|
247
|
+
* Each call emits an audit row in the `dora.*` namespace.
|
|
248
|
+
*
|
|
249
|
+
* @opts
|
|
250
|
+
* audit: boolean (default true; set false to skip audit emits),
|
|
251
|
+
* observability: boolean (reserved — observability counter is always
|
|
252
|
+
* best-effort and ignored on failure),
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* var dora = b.dora.create({ audit: true });
|
|
256
|
+
* var rv = dora.classify({
|
|
257
|
+
* dataAffected: "financial",
|
|
258
|
+
* severityIndicator: "critical",
|
|
259
|
+
* affectedClients: 1200,
|
|
260
|
+
* economicImpact: { eur: 50000 },
|
|
261
|
+
* durationMs: 4 * 60 * 60 * 1000,
|
|
262
|
+
* });
|
|
263
|
+
* rv.classification; // → "major"
|
|
264
|
+
* rv.mustReport; // → true
|
|
265
|
+
*
|
|
266
|
+
* var initial = dora.report({
|
|
267
|
+
* incidentId: "INC-2026-0042",
|
|
268
|
+
* classification: rv.classification,
|
|
269
|
+
* stage: "initial",
|
|
270
|
+
* detectedAt: Date.now(),
|
|
271
|
+
* description: "Payment-gateway outage — 2h customer-facing impact",
|
|
272
|
+
* });
|
|
273
|
+
* initial.stage; // → "initial"
|
|
274
|
+
*/
|
|
256
275
|
function create(opts) {
|
|
257
276
|
opts = opts || {};
|
|
258
277
|
validateOpts(opts, ["audit", "observability"], "dora.create");
|