@blamejs/core 0.8.42 → 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 +93 -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/template.js
CHANGED
|
@@ -1,13 +1,37 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
*
|
|
3
|
+
* @module b.template
|
|
4
|
+
* @nav HTTP
|
|
5
|
+
* @title Template
|
|
6
|
+
*
|
|
7
|
+
* @intro
|
|
8
|
+
* Server-side HTML template engine. Handlebars-flavoured tag
|
|
9
|
+
* syntax (`{{ expr }}` HTML-escaped, `{{{ expr }}}` raw, `{{> name }}`
|
|
10
|
+
* partials, `{% extends "layout" %}` / `{% block name %}` inheritance,
|
|
11
|
+
* `{% if %}` / `{% for %}` directives) parsed into a small AST and
|
|
12
|
+
* walked at render time against an operator-supplied data scope.
|
|
13
|
+
*
|
|
14
|
+
* No `eval`, no dynamic Function constructor, no `vm.runInThisContext`
|
|
15
|
+
* — the expression grammar is a fixed recursive-descent Pratt parser
|
|
16
|
+
* and member access is restricted to own properties (the parser
|
|
17
|
+
* refuses `foo.constructor` / `foo.__proto__` walks out of the data
|
|
18
|
+
* scope). Custom helpers are operator-provided functions in the data
|
|
19
|
+
* scope (e.g. `{{ helpers.formatDate(d) }}`); when `opts.sandbox ===
|
|
20
|
+
* true` each helper source string is wrapped through `b.sandbox.run`
|
|
21
|
+
* so helper code runs in a worker-thread isolate with timeout + byte
|
|
22
|
+
* cap.
|
|
23
|
+
*
|
|
24
|
+
* `precompileAll()` walks `viewsDir` at boot, parsing every `.html`
|
|
25
|
+
* file so template syntax errors fail the deploy rather than the
|
|
26
|
+
* first user request. Compiled ASTs are cached unless `cache: false`
|
|
27
|
+
* is set on the engine — operators turn caching off for live-reload
|
|
28
|
+
* workflows.
|
|
4
29
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
*
|
|
10
|
-
* RCE the framework, period."
|
|
30
|
+
* @card
|
|
31
|
+
* Server-side HTML template engine.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Server-side HTML template engine — eval-free.
|
|
11
35
|
*
|
|
12
36
|
* Tag syntax:
|
|
13
37
|
*
|
|
@@ -67,8 +91,14 @@
|
|
|
67
91
|
*/
|
|
68
92
|
var fs = require("fs");
|
|
69
93
|
var path = require("path");
|
|
94
|
+
var lazyRequire = require("./lazy-require");
|
|
70
95
|
var validateOpts = require("./validate-opts");
|
|
71
96
|
|
|
97
|
+
// Lazy because b.template can be loaded before b.sandbox (which pulls
|
|
98
|
+
// in node:worker_threads). Operators not opting into sandboxed helpers
|
|
99
|
+
// shouldn't pay the worker_threads boot.
|
|
100
|
+
var sandboxModule = lazyRequire(function () { return require("./sandbox"); });
|
|
101
|
+
|
|
72
102
|
// Maximum nesting depth for layout {% extends %} chains and partial
|
|
73
103
|
// {{> ... }} recursion. Hex form so the byte-literal lint doesn't trip
|
|
74
104
|
// on the multiple-of-8 cap; high enough that a real template tree
|
|
@@ -82,6 +112,26 @@ var MAX_TEMPLATE_DEPTH = 0x10;
|
|
|
82
112
|
var ESCAPE_MAP = { "&": "&", "<": "<", ">": ">", '"': """, "'": "'" };
|
|
83
113
|
var ESCAPE_RE = /[&<>"']/g;
|
|
84
114
|
|
|
115
|
+
/**
|
|
116
|
+
* @primitive b.template.escapeHtml
|
|
117
|
+
* @signature b.template.escapeHtml(value)
|
|
118
|
+
* @since 0.1.0
|
|
119
|
+
* @related b.template.create, b.template.render
|
|
120
|
+
*
|
|
121
|
+
* HTML-entity escapes the five attack-relevant characters (`&`, `<`,
|
|
122
|
+
* `>`, `"`, `'`). Non-string inputs are coerced via `String(value)`;
|
|
123
|
+
* `null` and `undefined` become the empty string. Used internally by
|
|
124
|
+
* `{{ expr }}` interpolation; exported because operators occasionally
|
|
125
|
+
* reach for the same escape from non-template paths (form-error
|
|
126
|
+
* rendering, CSV-cell-as-HTML pre-escape).
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* b.template.escapeHtml("<script>alert(1)</script>");
|
|
130
|
+
* // → "<script>alert(1)</script>"
|
|
131
|
+
*
|
|
132
|
+
* b.template.escapeHtml(null); // → ""
|
|
133
|
+
* b.template.escapeHtml(42); // → "42"
|
|
134
|
+
*/
|
|
85
135
|
function escapeHtml(value) {
|
|
86
136
|
if (value === null || value === undefined) return "";
|
|
87
137
|
var s = typeof value === "string" ? value : String(value);
|
|
@@ -683,9 +733,41 @@ function _evalBlock(nodes, scopes, escFn) {
|
|
|
683
733
|
// Engine instance
|
|
684
734
|
// ============================================================
|
|
685
735
|
|
|
736
|
+
/**
|
|
737
|
+
* @primitive b.template.create
|
|
738
|
+
* @signature b.template.create(opts)
|
|
739
|
+
* @since 0.1.0
|
|
740
|
+
* @related b.template.render, b.template.escapeHtml
|
|
741
|
+
*
|
|
742
|
+
* Builds an engine instance bound to `opts.viewsDir`. The returned
|
|
743
|
+
* object exposes `render(viewName, data?)` for one-shot rendering,
|
|
744
|
+
* `compile(viewName)` for AST-only access (caches under viewName),
|
|
745
|
+
* `precompileAll()` for boot-time validation of every `.html` file
|
|
746
|
+
* under `viewsDir`, and `reset()` to drop the AST cache (useful in
|
|
747
|
+
* live-reload workflows).
|
|
748
|
+
*
|
|
749
|
+
* View names are resolved against `viewsDir`; names containing `..`
|
|
750
|
+
* or NUL are refused, and resolved paths outside `viewsDir` throw.
|
|
751
|
+
* Layout-extends and partial-inclusion recursion are bounded at
|
|
752
|
+
* depth 16 to defend against accidental cycles.
|
|
753
|
+
*
|
|
754
|
+
* @opts
|
|
755
|
+
* viewsDir: string, // required — absolute or cwd-relative directory of .html templates
|
|
756
|
+
* cache: boolean, // default true; set false for live-reload
|
|
757
|
+
* escapeHtml: function (value) → string, // override the default 5-character HTML escape
|
|
758
|
+
* sandbox: boolean, // when true, sandboxHelpers run through b.sandbox.run
|
|
759
|
+
* sandboxHelpers: Object<string, string>, // map of helperName → JS source executed inside the sandbox
|
|
760
|
+
* sandboxOpts: { timeoutMs, maxBytes, allowed },
|
|
761
|
+
*
|
|
762
|
+
* @example
|
|
763
|
+
* var engine = b.template.create({ viewsDir: "./views" });
|
|
764
|
+
* engine.precompileAll(); // fail boot on syntax errors
|
|
765
|
+
* var html = engine.render("dashboard", { user: { name: "Ada" } });
|
|
766
|
+
* // → "<h1>Hello Ada</h1>"
|
|
767
|
+
*/
|
|
686
768
|
function create(opts) {
|
|
687
769
|
opts = opts || {};
|
|
688
|
-
validateOpts(opts, ["viewsDir", "cache", "escapeHtml"], "b.template");
|
|
770
|
+
validateOpts(opts, ["viewsDir", "cache", "escapeHtml", "sandbox", "sandboxHelpers", "sandboxOpts"], "b.template");
|
|
689
771
|
if (!opts.viewsDir) {
|
|
690
772
|
throw new Error("template.create({ viewsDir }) is required");
|
|
691
773
|
}
|
|
@@ -697,6 +779,47 @@ function create(opts) {
|
|
|
697
779
|
var customEscape = typeof opts.escapeHtml === "function" ? opts.escapeHtml : escapeHtml;
|
|
698
780
|
var astCache = {};
|
|
699
781
|
|
|
782
|
+
// Sandbox integration. When opts.sandbox === true, every operator-
|
|
783
|
+
// supplied helper in opts.sandboxHelpers (a { name -> source-string }
|
|
784
|
+
// map) is wrapped into an async-shaped callable that delegates to
|
|
785
|
+
// b.sandbox.run with the operator's per-engine sandboxOpts (timeoutMs,
|
|
786
|
+
// maxBytes, allowed). The helper signature is `helperFn(input)` which
|
|
787
|
+
// returns a Promise; templates can pre-compute helper results in the
|
|
788
|
+
// route handler and pass the resolved values into the data scope.
|
|
789
|
+
// The template engine itself stays synchronous + eval-free.
|
|
790
|
+
var sandboxedHelpers = null;
|
|
791
|
+
if (opts.sandbox === true) {
|
|
792
|
+
var sbHelpers = opts.sandboxHelpers || {};
|
|
793
|
+
if (typeof sbHelpers !== "object" || Array.isArray(sbHelpers)) {
|
|
794
|
+
throw new Error("template.create: opts.sandboxHelpers must be a { name -> source } object");
|
|
795
|
+
}
|
|
796
|
+
var sbOpts = opts.sandboxOpts || {};
|
|
797
|
+
if (typeof sbOpts !== "object" || Array.isArray(sbOpts)) {
|
|
798
|
+
throw new Error("template.create: opts.sandboxOpts must be an object");
|
|
799
|
+
}
|
|
800
|
+
var sandbox = sandboxModule();
|
|
801
|
+
sandboxedHelpers = {};
|
|
802
|
+
var helperNames = Object.keys(sbHelpers);
|
|
803
|
+
for (var hi = 0; hi < helperNames.length; hi += 1) {
|
|
804
|
+
var hname = helperNames[hi];
|
|
805
|
+
var hsource = sbHelpers[hname];
|
|
806
|
+
if (typeof hsource !== "string" || hsource.length === 0) {
|
|
807
|
+
throw new Error("template.create: opts.sandboxHelpers[" + JSON.stringify(hname) + "] must be a non-empty string");
|
|
808
|
+
}
|
|
809
|
+
sandboxedHelpers[hname] = (function (capturedSource) {
|
|
810
|
+
return function (helperInput) {
|
|
811
|
+
return sandbox.run({
|
|
812
|
+
source: capturedSource,
|
|
813
|
+
input: helperInput,
|
|
814
|
+
timeoutMs: sbOpts.timeoutMs,
|
|
815
|
+
maxBytes: sbOpts.maxBytes,
|
|
816
|
+
allowed: sbOpts.allowed,
|
|
817
|
+
}).then(function (r) { return r.result; });
|
|
818
|
+
};
|
|
819
|
+
}(hsource));
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
|
|
700
823
|
function compile(viewName) {
|
|
701
824
|
if (cacheOn && astCache[viewName]) return astCache[viewName];
|
|
702
825
|
var viewPath = _resolveViewPath(viewsDir, viewName);
|
|
@@ -777,6 +900,23 @@ function _ensureDefault() {
|
|
|
777
900
|
return _default;
|
|
778
901
|
}
|
|
779
902
|
|
|
903
|
+
/**
|
|
904
|
+
* @primitive b.template.render
|
|
905
|
+
* @signature b.template.render(viewName, data?)
|
|
906
|
+
* @since 0.1.0
|
|
907
|
+
* @related b.template.create
|
|
908
|
+
*
|
|
909
|
+
* Convenience renderer that lazily binds a default engine instance
|
|
910
|
+
* to `<cwd>/views` on first call, then dispatches to its `render()`.
|
|
911
|
+
* Operators with custom view directories (multi-tenant apps,
|
|
912
|
+
* non-cwd-rooted deploys) call `b.template.create({ viewsDir })`
|
|
913
|
+
* instead and keep the engine in their app scope.
|
|
914
|
+
*
|
|
915
|
+
* @example
|
|
916
|
+
* // Project layout: ./views/welcome.html
|
|
917
|
+
* var html = b.template.render("welcome", { name: "Ada" });
|
|
918
|
+
* // → "<h1>Welcome, Ada</h1>"
|
|
919
|
+
*/
|
|
780
920
|
function render(viewName, data) {
|
|
781
921
|
return _ensureDefault().render(viewName, data);
|
|
782
922
|
}
|