@blamejs/core 0.9.46 → 0.9.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 +15 -0
- package/index.js +5 -0
- package/lib/guard-imap-command.js +335 -0
- package/lib/mail-server-imap.js +1064 -0
- package/lib/mail-server-mx.js +124 -4
- package/lib/mail-server-rate-limit.js +256 -0
- package/lib/mail-server-submission.js +986 -0
- package/lib/metrics.js +50 -7
- package/lib/self-update.js +35 -4
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/metrics.js
CHANGED
|
@@ -853,18 +853,43 @@ function snapshotRead(p) {
|
|
|
853
853
|
* Format a snapshot object for human or machine consumption.
|
|
854
854
|
*
|
|
855
855
|
* format: "text" — operator-readable lines, one field per row (default)
|
|
856
|
-
* format: "prometheus" — Prometheus 0.0.4 text format
|
|
857
|
-
*
|
|
858
|
-
*
|
|
856
|
+
* format: "prometheus" — Prometheus 0.0.4 text format
|
|
857
|
+
*
|
|
858
|
+
* ## Type detection (`prometheus` format only)
|
|
859
|
+
*
|
|
860
|
+
* Per Prometheus naming convention + OpenMetrics 1.0.0 §6.2, counter
|
|
861
|
+
* metric families MUST carry the `_total` suffix; every other numeric
|
|
862
|
+
* field renders as a gauge. The renderer auto-detects by suffix:
|
|
863
|
+
*
|
|
864
|
+
* - field name ends in `_total` → `# TYPE <name> counter`
|
|
865
|
+
* - everything else → `# TYPE <name> gauge`
|
|
866
|
+
*
|
|
867
|
+
* Operators with metrics that don't fit the convention (e.g. a counter
|
|
868
|
+
* named `bytes_sent` without the `_total` suffix, or a gauge that
|
|
869
|
+
* happens to end in `_total`) opt the right type via `opts.fieldTypes`:
|
|
870
|
+
*
|
|
871
|
+
* render(snap, { format: "prometheus", fieldTypes: {
|
|
872
|
+
* bytes_sent: "counter", // override default gauge
|
|
873
|
+
* ratio_total: "gauge", // override default counter
|
|
874
|
+
* }});
|
|
875
|
+
*
|
|
876
|
+
* Pre-v0.9.47 every field rendered as gauge regardless of name, which
|
|
877
|
+
* broke `rate()` queries against counter-shaped series. Operators
|
|
878
|
+
* scraping a long-running deployment will see `rate(*_total[5m])`
|
|
879
|
+
* queries start returning the right answer once the new types reach
|
|
880
|
+
* the scrape target.
|
|
859
881
|
*
|
|
860
882
|
* @opts
|
|
861
|
-
* format:
|
|
862
|
-
* prefix:
|
|
883
|
+
* format: "text" | "prometheus", // default: "text"
|
|
884
|
+
* prefix: string, // prometheus-only; default: "blamejs"
|
|
885
|
+
* fieldTypes: Object, // prometheus-only; per-field type override
|
|
886
|
+
* // map. Values: "counter" | "gauge".
|
|
863
887
|
*
|
|
864
888
|
* @example
|
|
865
889
|
* var snap = b.metrics.snapshot.read("/run/blamejs/metrics.json");
|
|
866
890
|
* process.stdout.write(b.metrics.snapshot.render(snap));
|
|
867
|
-
* // or for Prometheus scraping
|
|
891
|
+
* // or for Prometheus scraping (auto-detects http_requests_total
|
|
892
|
+
* // as a counter via the _total suffix):
|
|
868
893
|
* res.setHeader("Content-Type", "text/plain; version=0.0.4");
|
|
869
894
|
* res.end(b.metrics.snapshot.render(snap, { format: "prometheus", prefix: "myapp" }));
|
|
870
895
|
*/
|
|
@@ -899,6 +924,11 @@ function snapshotRender(snap, opts) {
|
|
|
899
924
|
throw new MetricsError("metrics-snapshot/bad-prefix",
|
|
900
925
|
"metrics.snapshot.render: prometheus prefix must match [a-zA-Z_][a-zA-Z0-9_]*, got '" + prefix + "'");
|
|
901
926
|
}
|
|
927
|
+
var fieldTypes = opts.fieldTypes || {};
|
|
928
|
+
if (typeof fieldTypes !== "object" || fieldTypes === null || Array.isArray(fieldTypes)) {
|
|
929
|
+
throw new MetricsError("metrics-snapshot/bad-field-types",
|
|
930
|
+
"metrics.snapshot.render: opts.fieldTypes must be an object mapping field-name → 'counter' | 'gauge'");
|
|
931
|
+
}
|
|
902
932
|
var out = [];
|
|
903
933
|
// allow:bare-canonicalize-walk — sort is for stable Prometheus
|
|
904
934
|
// exposition output ordering, not canonicalize-for-hashing
|
|
@@ -909,7 +939,20 @@ function snapshotRender(snap, opts) {
|
|
|
909
939
|
if (typeof v2 !== "number" || !isFinite(v2)) continue; // only numeric scalars
|
|
910
940
|
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(k2)) continue; // skip prom-incompatible names
|
|
911
941
|
var metric = prefix + "_" + k2;
|
|
912
|
-
|
|
942
|
+
var declared = fieldTypes[k2];
|
|
943
|
+
var fieldType;
|
|
944
|
+
if (declared !== undefined) {
|
|
945
|
+
if (declared !== "counter" && declared !== "gauge") {
|
|
946
|
+
throw new MetricsError("metrics-snapshot/bad-field-type",
|
|
947
|
+
"metrics.snapshot.render: opts.fieldTypes." + k2 + " must be 'counter' or 'gauge', got '" + declared + "'");
|
|
948
|
+
}
|
|
949
|
+
fieldType = declared;
|
|
950
|
+
} else {
|
|
951
|
+
// Prometheus naming convention + OpenMetrics 1.0.0 §6.2:
|
|
952
|
+
// counter family names carry the _total suffix.
|
|
953
|
+
fieldType = /_total$/.test(k2) ? "counter" : "gauge";
|
|
954
|
+
}
|
|
955
|
+
out.push("# TYPE " + metric + " " + fieldType);
|
|
913
956
|
out.push(metric + " " + v2);
|
|
914
957
|
}
|
|
915
958
|
return out.join("\n") + "\n";
|
package/lib/self-update.js
CHANGED
|
@@ -86,14 +86,41 @@ function _safeAuditEmit(action, outcome, metadata) {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
// ---- semver-shaped comparison (tag_name like "v0.7.30" or "0.7.30") ----
|
|
89
|
-
// Strips a leading "v" / "V" then parses dot-separated numeric components.
|
|
90
|
-
// Non-numeric components are compared lexicographically (handles release
|
|
91
|
-
// suffixes like "1.0.0-rc.1" by falling back to string comparison after
|
|
92
|
-
// the matching numeric prefix). Returns -1 / 0 / +1.
|
|
93
89
|
function _normalizeTag(tag) {
|
|
94
90
|
if (typeof tag !== "string") return "";
|
|
95
91
|
return tag.replace(/^v/i, "").trim();
|
|
96
92
|
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* @primitive b.selfUpdate.compareTags
|
|
96
|
+
* @signature b.selfUpdate.compareTags(a, b)
|
|
97
|
+
* @since 0.9.47
|
|
98
|
+
* @status stable
|
|
99
|
+
*
|
|
100
|
+
* Compare two release tags / version strings. Returns `-1` if `a < b`,
|
|
101
|
+
* `+1` if `a > b`, `0` if equal. Strips a leading `v` / `V`, then walks
|
|
102
|
+
* dot-separated components: numeric pairs compared numerically; any
|
|
103
|
+
* non-numeric component (release suffixes like `1.0.0-rc.1`) falls back
|
|
104
|
+
* to lexicographic compare on that component. Missing components on
|
|
105
|
+
* either side are treated as `"0"`.
|
|
106
|
+
*
|
|
107
|
+
* Shape follows SemVer 2.0.0 §11 precedence rules for the numeric prefix.
|
|
108
|
+
* Deviations from the full SemVer §11 spec — pre-release identifiers
|
|
109
|
+
* (`-rc.1` < release) are compared lexicographically rather than the
|
|
110
|
+
* SemVer-mandated "alphanumeric identifiers compared as numbers if all
|
|
111
|
+
* numeric" rule. For most version-shaped strings the result is identical;
|
|
112
|
+
* exotic pre-release shapes (`1.0.0-alpha.10` vs `1.0.0-alpha.9`) sort
|
|
113
|
+
* lexicographically here (`10` < `9` as strings) rather than numerically.
|
|
114
|
+
* Operators with strict SemVer §11 needs should use a dedicated SemVer
|
|
115
|
+
* parser; this primitive targets the common framework-update polling
|
|
116
|
+
* shape (`v0.9.46` vs `v0.9.47`) where pre-release tags are rare.
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* b.selfUpdate.compareTags("v0.9.46", "v0.9.47"); // → -1
|
|
120
|
+
* b.selfUpdate.compareTags("v0.9.47", "0.9.47"); // → 0 (leading "v" stripped)
|
|
121
|
+
* b.selfUpdate.compareTags("1.10.0", "1.9.0"); // → +1 (numeric, not lex)
|
|
122
|
+
* b.selfUpdate.compareTags("v0.7.30", "v0.7.30"); // → 0
|
|
123
|
+
*/
|
|
97
124
|
function _compareTags(a, b) {
|
|
98
125
|
var na = _normalizeTag(a);
|
|
99
126
|
var nb2 = _normalizeTag(b);
|
|
@@ -648,6 +675,10 @@ module.exports = {
|
|
|
648
675
|
SelfUpdateError: SelfUpdateError,
|
|
649
676
|
ALLOWED_HASH_ALGS: ALLOWED_HASH_ALGS,
|
|
650
677
|
DEFAULT_HASH_ALG: DEFAULT_HASH_ALG,
|
|
678
|
+
// Public surface — same impl as the internal `_compareTags`;
|
|
679
|
+
// downstream consumers replacing one-off compareVersions helpers
|
|
680
|
+
// call this.
|
|
681
|
+
compareTags: _compareTags,
|
|
651
682
|
// Internal — exposed for the layer-0 test suite only.
|
|
652
683
|
_compareTags: _compareTags,
|
|
653
684
|
};
|
package/package.json
CHANGED
package/sbom.cdx.json
CHANGED
|
@@ -2,10 +2,10 @@
|
|
|
2
2
|
"$schema": "http://cyclonedx.org/schema/bom-1.5.schema.json",
|
|
3
3
|
"bomFormat": "CycloneDX",
|
|
4
4
|
"specVersion": "1.6",
|
|
5
|
-
"serialNumber": "urn:uuid:
|
|
5
|
+
"serialNumber": "urn:uuid:21323cdb-5bfe-4b88-a63f-906795a497e6",
|
|
6
6
|
"version": 1,
|
|
7
7
|
"metadata": {
|
|
8
|
-
"timestamp": "2026-05-
|
|
8
|
+
"timestamp": "2026-05-16T03:34:31.380Z",
|
|
9
9
|
"lifecycles": [
|
|
10
10
|
{
|
|
11
11
|
"phase": "build"
|
|
@@ -19,14 +19,14 @@
|
|
|
19
19
|
}
|
|
20
20
|
],
|
|
21
21
|
"component": {
|
|
22
|
-
"bom-ref": "@blamejs/core@0.9.
|
|
22
|
+
"bom-ref": "@blamejs/core@0.9.49",
|
|
23
23
|
"type": "library",
|
|
24
24
|
"name": "blamejs",
|
|
25
|
-
"version": "0.9.
|
|
25
|
+
"version": "0.9.49",
|
|
26
26
|
"scope": "required",
|
|
27
27
|
"author": "blamejs contributors",
|
|
28
28
|
"description": "The Node framework that owns its stack.",
|
|
29
|
-
"purl": "pkg:npm/%40blamejs/core@0.9.
|
|
29
|
+
"purl": "pkg:npm/%40blamejs/core@0.9.49",
|
|
30
30
|
"properties": [],
|
|
31
31
|
"externalReferences": [
|
|
32
32
|
{
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"components": [],
|
|
55
55
|
"dependencies": [
|
|
56
56
|
{
|
|
57
|
-
"ref": "@blamejs/core@0.9.
|
|
57
|
+
"ref": "@blamejs/core@0.9.49",
|
|
58
58
|
"dependsOn": []
|
|
59
59
|
}
|
|
60
60
|
]
|