@blamejs/blamejs-shop 0.5.6 → 0.5.8

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.
Files changed (28) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/lib/asset-manifest.json +1 -1
  3. package/lib/cost-layers.js +86 -49
  4. package/lib/plan-changes.js +14 -0
  5. package/lib/storefront.js +30 -17
  6. package/lib/vendor/MANIFEST.json +31 -15
  7. package/lib/vendor/blamejs/.github/workflows/release-container.yml +2 -2
  8. package/lib/vendor/blamejs/CHANGELOG.md +2 -0
  9. package/lib/vendor/blamejs/api-snapshot.json +2 -2
  10. package/lib/vendor/blamejs/examples/wiki/package-lock.json +1 -1
  11. package/lib/vendor/blamejs/lib/content-credentials.js +43 -2
  12. package/lib/vendor/blamejs/lib/guard-sql.js +29 -0
  13. package/lib/vendor/blamejs/lib/mcp.js +37 -4
  14. package/lib/vendor/blamejs/lib/metrics.js +15 -3
  15. package/lib/vendor/blamejs/lib/middleware/tus-upload.js +9 -2
  16. package/lib/vendor/blamejs/lib/parsers/safe-yaml.js +33 -2
  17. package/lib/vendor/blamejs/lib/safe-buffer.js +11 -1
  18. package/lib/vendor/blamejs/package-lock.json +2 -2
  19. package/lib/vendor/blamejs/package.json +1 -1
  20. package/lib/vendor/blamejs/release-notes/v0.16.3.json +71 -0
  21. package/lib/vendor/blamejs/test/layer-0-primitives/content-credentials-coverage.test.js +319 -0
  22. package/lib/vendor/blamejs/test/layer-0-primitives/cycle2-bugfixes.test.js +142 -0
  23. package/lib/vendor/blamejs/test/layer-0-primitives/guard-sql-coverage.test.js +432 -0
  24. package/lib/vendor/blamejs/test/layer-0-primitives/mcp-coverage.test.js +443 -0
  25. package/lib/vendor/blamejs/test/layer-0-primitives/metrics-coverage.test.js +395 -0
  26. package/lib/vendor/blamejs/test/layer-0-primitives/middleware-tus-upload-coverage.test.js +402 -0
  27. package/lib/vendor/blamejs/test/layer-0-primitives/parsers-safe-yaml-coverage.test.js +292 -0
  28. package/package.json +1 -1
@@ -0,0 +1,395 @@
1
+ // SPDX-License-Identifier: Apache-2.0
2
+ // Copyright (c) blamejs contributors
3
+ "use strict";
4
+ /**
5
+ * b.metrics — error-path + adversarial-input coverage for the core
6
+ * registry (counter / gauge / histogram / exposition / requestMiddleware
7
+ * / tap dispatch) and the snapshot + shadow-registry surfaces.
8
+ *
9
+ * The happy path is exercised by the smoke + integration suites; this
10
+ * file drives the validation refusals, resource-limit rejections,
11
+ * wrong-state / unknown-command branches, and typed-error paths those
12
+ * suites never reach. Every assertion drives the public API
13
+ * (`b.metrics.*`) — never a private internal.
14
+ *
15
+ * Run standalone: `node test/layer-0-primitives/metrics-coverage.test.js`
16
+ * Or via smoke: `node test/smoke.js`
17
+ */
18
+
19
+ var helpers = require("../helpers");
20
+ var b = helpers.b;
21
+ var check = helpers.check;
22
+
23
+ var BACKSLASH = String.fromCharCode(92);
24
+ var NEWLINE = String.fromCharCode(10);
25
+
26
+ // Shared throw-capture helpers — one shape, reused across every refusal
27
+ // assertion (audit-existing: mirrors the expectThrow shape the sibling
28
+ // metrics-snapshot / metrics-shadow-registry tests already use).
29
+ function expectCode(label, fn, codeMatch) {
30
+ var threw = null;
31
+ try { fn(); } catch (e) { threw = e; }
32
+ check(label, !!(threw && (threw.code || "").indexOf(codeMatch) !== -1));
33
+ }
34
+ function expectThrowMsg(label, fn, re) {
35
+ var threw = null;
36
+ try { fn(); } catch (e) { threw = e; }
37
+ check(label, !!(threw && re.test(threw.message || "")));
38
+ }
39
+
40
+ // ---- create() opt validation (entry-point / throw tier) ----
41
+
42
+ function testCreateRejectsUnknownOpt() {
43
+ expectThrowMsg("create: unknown opt rejected",
44
+ function () { b.metrics.create({ bogus: 1 }); },
45
+ /unknown option/);
46
+ }
47
+
48
+ function testCreateRejectsBadCardinalityCap() {
49
+ expectCode("create: cardinalityCap 0 rejected",
50
+ function () { b.metrics.create({ labelCardinalityCap: 0 }); }, "metrics/bad-opt");
51
+ expectCode("create: cardinalityCap negative rejected",
52
+ function () { b.metrics.create({ labelCardinalityCap: -1 }); }, "metrics/bad-opt");
53
+ expectCode("create: cardinalityCap non-integer rejected",
54
+ function () { b.metrics.create({ labelCardinalityCap: 1.5 }); }, "metrics/bad-opt");
55
+ expectCode("create: cardinalityCap Infinity rejected",
56
+ function () { b.metrics.create({ labelCardinalityCap: Infinity }); }, "metrics/bad-opt");
57
+ }
58
+
59
+ function testCreateRejectsBadDefaultLabelName() {
60
+ expectCode("create: invalid defaultLabels name rejected",
61
+ function () { b.metrics.create({ defaultLabels: { "bad-name": "x" } }); }, "metrics/bad-label");
62
+ }
63
+
64
+ // ---- metric-name / label-name validation ----
65
+
66
+ function testMetricNameValidation() {
67
+ var m = b.metrics.create();
68
+ expectCode("counter: hyphen in name rejected",
69
+ function () { m.counter("bad-name!", {}); }, "metrics/bad-name");
70
+ expectCode("counter: empty name rejected",
71
+ function () { m.counter("", {}); }, "metrics/bad-name");
72
+ expectCode("counter: non-string name rejected",
73
+ function () { m.counter(123, {}); }, "metrics/bad-name");
74
+ expectCode("counter: over-long name rejected",
75
+ function () { m.counter(new Array(250).join("x"), {}); }, "metrics/bad-name");
76
+ expectCode("gauge: bad labelName rejected",
77
+ function () { m.gauge("okg", { labelNames: ["bad-name"] }); }, "metrics/bad-label");
78
+ expectCode("histogram: bad labelName rejected",
79
+ function () { m.histogram("okh", { labelNames: ["also bad"] }); }, "metrics/bad-label");
80
+ }
81
+
82
+ function testDuplicateRegistration() {
83
+ var m = b.metrics.create();
84
+ m.counter("dup_total", {});
85
+ expectCode("counter: duplicate name rejected",
86
+ function () { m.counter("dup_total", {}); }, "metrics/duplicate");
87
+ // A gauge re-using a counter's fully-qualified name also collides.
88
+ expectCode("gauge: collides with existing counter name",
89
+ function () { m.gauge("dup_total", {}); }, "metrics/duplicate");
90
+ }
91
+
92
+ // ---- counter error branches ----
93
+
94
+ function testCounterDecrementRefused() {
95
+ var m = b.metrics.create();
96
+ var c = m.counter("reqs_total", {});
97
+ expectCode("counter.inc: negative value refused",
98
+ function () { c.inc(-1); }, "metrics/counter-decrement");
99
+ expectCode("counter.inc: negative with labels refused",
100
+ function () { m.counter("reqs2_total", { labelNames: ["a"] }).inc({ a: "x" }, -5); },
101
+ "metrics/counter-decrement");
102
+ }
103
+
104
+ function testLabelResolution() {
105
+ var m = b.metrics.create();
106
+ var c = m.counter("http_total", { labelNames: ["method"] });
107
+ expectCode("inc: undeclared label rejected",
108
+ function () { c.inc({ method: "GET", route: "/x" }); }, "metrics/undeclared-label");
109
+ expectCode("inc: missing required label rejected",
110
+ function () { c.inc({}); }, "metrics/missing-label");
111
+ // Declared + present → succeeds; get reflects the increment.
112
+ c.inc({ method: "GET" }, 3);
113
+ check("inc: declared label increments", c.get({ method: "GET" }) === 3);
114
+ check("get: unknown labelset defaults to 0", c.get({ method: "POST" }) === 0);
115
+ }
116
+
117
+ function testCardinalityCapDropsSilently() {
118
+ var m = b.metrics.create({ namespace: "cap", labelCardinalityCap: 2 });
119
+ var c = m.counter("k_total", { labelNames: ["id"] });
120
+ c.inc({ id: "a" });
121
+ c.inc({ id: "b" });
122
+ c.inc({ id: "c" }); // third distinct label set — over cap, dropped
123
+ check("cap: first labelset kept", c.get({ id: "a" }) === 1);
124
+ check("cap: second labelset kept", c.get({ id: "b" }) === 1);
125
+ check("cap: over-cap labelset dropped (stays 0)", c.get({ id: "c" }) === 0);
126
+ // An already-seen labelset still increments after the cap is hit.
127
+ c.inc({ id: "a" });
128
+ check("cap: existing labelset still increments post-cap", c.get({ id: "a" }) === 2);
129
+ // Exposition renders only the retained series (no third series line).
130
+ var out = m.exposition();
131
+ check("cap: over-cap series absent from exposition",
132
+ out.indexOf('cap_k_total{id="c"}') === -1);
133
+ }
134
+
135
+ // ---- gauge error branches ----
136
+
137
+ function testGaugeBadValueRefused() {
138
+ var m = b.metrics.create();
139
+ var g = m.gauge("temp", {});
140
+ expectCode("gauge.set: NaN refused",
141
+ function () { g.set(NaN); }, "metrics/gauge-bad-value");
142
+ expectCode("gauge.set: missing value (undefined) refused",
143
+ function () { g.set({}); }, "metrics/gauge-bad-value");
144
+ expectCode("gauge.set: string value refused",
145
+ function () { g.set("hot"); }, "metrics/gauge-bad-value");
146
+ // inc / dec adjust an existing series; get returns the running value.
147
+ g.set(10);
148
+ g.inc(5);
149
+ g.dec(3);
150
+ check("gauge.set/inc/dec compose", g.get() === 12);
151
+ }
152
+
153
+ // ---- histogram error branches ----
154
+
155
+ function testHistogramBadBuckets() {
156
+ var m = b.metrics.create();
157
+ expectCode("histogram: empty buckets refused",
158
+ function () { m.histogram("h1", { buckets: [] }); }, "metrics/bad-buckets");
159
+ expectCode("histogram: non-array buckets refused",
160
+ function () { m.histogram("h2", { buckets: "nope" }); }, "metrics/bad-buckets");
161
+ expectCode("histogram: non-numeric bucket boundary refused",
162
+ function () { m.histogram("h3", { buckets: [1, "x", 3] }); }, "metrics/bad-buckets");
163
+ expectCode("histogram: NaN bucket boundary refused",
164
+ function () { m.histogram("h4", { buckets: [1, NaN] }); }, "metrics/bad-buckets");
165
+ expectCode("histogram: non-ascending buckets refused (equal)",
166
+ function () { m.histogram("h5", { buckets: [1, 1] }); }, "metrics/bad-buckets");
167
+ expectCode("histogram: non-ascending buckets refused (descending)",
168
+ function () { m.histogram("h6", { buckets: [2, 1] }); }, "metrics/bad-buckets");
169
+ }
170
+
171
+ function testHistogramObserveBadValue() {
172
+ var m = b.metrics.create();
173
+ var h = m.histogram("lat", { buckets: [0.5, 1] });
174
+ expectCode("histogram.observe: NaN refused",
175
+ function () { h.observe(NaN); }, "metrics/histogram-bad-value");
176
+ expectCode("histogram.observe: string refused",
177
+ function () { h.observe("slow"); }, "metrics/histogram-bad-value");
178
+ // A valid observation lands in the right bucket + the +Inf bucket.
179
+ h.observe(0.1);
180
+ var out = m.exposition();
181
+ check("histogram: le bucket rendered", out.indexOf('lat_bucket{le="0.5"} 1') !== -1);
182
+ check("histogram: +Inf bucket rendered", out.indexOf('lat_bucket{le="+Inf"} 1') !== -1);
183
+ check("histogram: count rendered", out.indexOf("lat_count 1") !== -1);
184
+ }
185
+
186
+ // ---- exposition wire-format escaping + content negotiation ----
187
+
188
+ function testLabelValueEscaping() {
189
+ var m = b.metrics.create({ namespace: "esc" });
190
+ var c = m.counter("k_total", { labelNames: ["p"] });
191
+ c.inc({ p: 'x"y' + NEWLINE + "z" }); // short, non-credential value
192
+ var out = m.exposition();
193
+ var line = out.split(NEWLINE).filter(function (l) { return l.indexOf("esc_k_total{") === 0; })[0] || "";
194
+ check("escape: no raw newline leaks into the exposition line", line.indexOf(NEWLINE) === -1);
195
+ check("escape: double-quote escaped", line.indexOf(BACKSLASH + '"') !== -1);
196
+ check("escape: newline escaped to backslash-n", line.indexOf(BACKSLASH + "n") !== -1);
197
+ }
198
+
199
+ function testExpositionHandlerNegotiation() {
200
+ var m = b.metrics.create();
201
+ m.counter("hits_total", {}).inc();
202
+ var handler = m.expositionHandler();
203
+
204
+ function run(accept) {
205
+ var req = b.testing.mockReq({ headers: accept ? { accept: accept } : {} });
206
+ var res = b.testing.mockRes();
207
+ handler(req, res);
208
+ return res._captured();
209
+ }
210
+
211
+ var noAccept = run(null);
212
+ check("negotiate: no Accept defaults to Prometheus 0.0.4",
213
+ (noAccept.headers["content-type"] || "").indexOf("version=0.0.4") !== -1);
214
+ check("negotiate: exposition status is 200", noAccept.status === 200);
215
+ check("negotiate: Cache-Control no-store set", noAccept.headers["cache-control"] === "no-store");
216
+ check("negotiate: Content-Length is a byte count", typeof noAccept.headers["content-length"] === "number");
217
+
218
+ var om = run("application/openmetrics-text; version=1.0.0");
219
+ check("negotiate: OpenMetrics Accept selects OpenMetrics 1.0.0",
220
+ (om.headers["content-type"] || "").indexOf("openmetrics-text") !== -1);
221
+ check("negotiate: OpenMetrics body carries the # EOF terminator",
222
+ om.body.indexOf("# EOF") !== -1);
223
+
224
+ // RFC 9110 weighted negotiation: text/plain q=1 beats openmetrics q=0.
225
+ var weighted = run("text/plain;q=1.0, application/openmetrics-text;q=0");
226
+ check("negotiate: q=0 OpenMetrics loses to q=1 text/plain (Prometheus wins)",
227
+ (weighted.headers["content-type"] || "").indexOf("version=0.0.4") !== -1);
228
+ }
229
+
230
+ // ---- requestMiddleware auto-instrumentation ----
231
+
232
+ function testRequestMiddlewareCountsAndTimes() {
233
+ var m = b.metrics.create();
234
+ var mw = m.requestMiddleware();
235
+ var req = b.testing.mockReq({ method: "GET", url: "/users?q=1" });
236
+ req.routePattern = "/users/:id"; // matcher-set route template
237
+ var res = b.testing.mockRes();
238
+ var nextCalled = false;
239
+ mw(req, res, function () { nextCalled = true; });
240
+ res.writeHead(200);
241
+ res.end("body");
242
+ check("middleware: next() invoked", nextCalled === true);
243
+ var reqs = m.metrics.get("framework_http_requests_total");
244
+ check("middleware: counts by route TEMPLATE not raw path",
245
+ reqs.get({ method: "GET", route: "/users/:id", status: "200" }) === 1);
246
+ var dur = m.metrics.get("framework_http_request_duration_seconds");
247
+ check("middleware: latency histogram observed",
248
+ dur.values.size === 1);
249
+ }
250
+
251
+ // ---- tap dispatch (global no-op stub + registry-driven handler) ----
252
+
253
+ function testTapDispatch() {
254
+ b.metrics._resetForTest();
255
+ // Before any registry is active, tap is a zero-cost no-op — never throws.
256
+ var noThrow = true;
257
+ try { b.metrics.tap("audit.record", 1, { action: "x", outcome: "ok" }); }
258
+ catch (_e) { noThrow = false; }
259
+ check("tap: no-op (no throw) before a registry is active", noThrow);
260
+
261
+ var m = b.metrics.create();
262
+ b.metrics.tap("audit.record", 2, { action: "login", outcome: "success" });
263
+ check("tap: audit.record routes into framework_audit_events_total",
264
+ m.metrics.get("framework_audit_events_total").get({ action: "login", outcome: "success" }) === 2);
265
+
266
+ b.metrics.tap("queue.enqueue", 3, { queueName: "q" });
267
+ check("tap: queue.enqueue raises queue depth gauge",
268
+ m.metrics.get("framework_queue_depth").get({ queueName: "q" }) === 3);
269
+ b.metrics.tap("queue.complete", 1, { queueName: "q" });
270
+ check("tap: queue.complete lowers queue depth gauge",
271
+ m.metrics.get("framework_queue_depth").get({ queueName: "q" }) === 2);
272
+
273
+ // Unknown / unsupported tap name falls through the dispatch with no
274
+ // effect — no throw, no metric mutated.
275
+ var before = m.metrics.get("framework_errors_total").values.size;
276
+ var unknownOk = true;
277
+ try { b.metrics.tap("nonexistent.event", 1, {}); } catch (_e) { unknownOk = false; }
278
+ check("tap: unknown command is a silent no-op", unknownOk &&
279
+ m.metrics.get("framework_errors_total").values.size === before);
280
+
281
+ // deactivate() releases the global handler → tap is a no-op again.
282
+ m.deactivate();
283
+ var seal = m.metrics.get("framework_vault_seal_total").get();
284
+ b.metrics.tap("vault.seal", 1, {});
285
+ check("tap: no-op after deactivate()",
286
+ m.metrics.get("framework_vault_seal_total").get() === seal);
287
+
288
+ b.metrics._resetForTest();
289
+ }
290
+
291
+ // ---- snapshot.startWriter validation (uncovered opt branches) ----
292
+
293
+ function testSnapshotStartWriterValidation() {
294
+ function baseOpts(extra) {
295
+ var o = { path: "/tmp/metrics-cov.json", intervalMs: 1000, fields: function () { return {}; } };
296
+ var k = Object.keys(extra);
297
+ for (var i = 0; i < k.length; i++) o[k[i]] = extra[k[i]];
298
+ return o;
299
+ }
300
+ expectCode("startWriter: non-registry registry object rejected",
301
+ function () { b.metrics.snapshot.startWriter(baseOpts({ registry: 5 })); },
302
+ "metrics-snapshot/bad-registry");
303
+ expectCode("startWriter: registry without .metrics rejected",
304
+ function () { b.metrics.snapshot.startWriter(baseOpts({ registry: { nope: 1 } })); },
305
+ "metrics-snapshot/bad-registry");
306
+ expectCode("startWriter: negative fileMode rejected",
307
+ function () { b.metrics.snapshot.startWriter(baseOpts({ fileMode: -1 })); },
308
+ "metrics-snapshot/bad-file-mode");
309
+ expectCode("startWriter: fileMode above 0o777 rejected",
310
+ function () { b.metrics.snapshot.startWriter(baseOpts({ fileMode: 0o1000 })); },
311
+ "metrics-snapshot/bad-file-mode");
312
+ expectCode("startWriter: non-integer fileMode rejected",
313
+ function () { b.metrics.snapshot.startWriter(baseOpts({ fileMode: 1.5 })); },
314
+ "metrics-snapshot/bad-file-mode");
315
+ }
316
+
317
+ // ---- shadowRegistry error branches (uncovered) ----
318
+
319
+ function testShadowRegistryValidation() {
320
+ expectCode("shadow: bad onCardinalityExceeded policy rejected",
321
+ function () { b.metrics.snapshot.shadowRegistry({ namespace: "ns", onCardinalityExceeded: "explode" }); },
322
+ "metrics-shadow/bad-policy");
323
+ expectCode("shadow: negative cardinalityCap rejected",
324
+ function () { b.metrics.snapshot.shadowRegistry({ namespace: "ns", cardinalityCap: -1 }); },
325
+ "metrics-shadow/bad-cap");
326
+ expectCode("shadow: non-integer cardinalityCap rejected",
327
+ function () { b.metrics.snapshot.shadowRegistry({ namespace: "ns", cardinalityCap: 1.5 }); },
328
+ "metrics-shadow/bad-cap");
329
+ expectCode("shadow: empty-string info name rejected",
330
+ function () { b.metrics.snapshot.shadowRegistry({ namespace: "ns", info: [""] }); },
331
+ "metrics-shadow/bad-info");
332
+ expectCode("shadow: non-string counter name rejected",
333
+ function () { b.metrics.snapshot.shadowRegistry({ namespace: "ns", counters: [123] }); },
334
+ "metrics-shadow/bad-counters");
335
+ }
336
+
337
+ function testShadowRegistryGaugeValueRefusal() {
338
+ var sh = b.metrics.snapshot.shadowRegistry({ namespace: "ns", gauges: ["gd"] });
339
+ expectCode("shadow.set: NaN gauge value refused",
340
+ function () { sh.set("gd", NaN); }, "metrics-shadow/bad-gauge-value");
341
+ expectCode("shadow.set: Infinity gauge value refused",
342
+ function () { sh.set("gd", Infinity); }, "metrics-shadow/bad-gauge-value");
343
+ expectCode("shadow.set: string gauge value refused",
344
+ function () { sh.set("gd", "x"); }, "metrics-shadow/bad-gauge-value");
345
+ }
346
+
347
+ function testShadowRegistryDropPolicyAndReset() {
348
+ // Default "drop" policy: over-cap label sets silently dropped, no throw.
349
+ var sh = b.metrics.snapshot.shadowRegistry({
350
+ namespace: "ns", counters: ["hits_total"], cardinalityCap: 2,
351
+ });
352
+ var noThrow = true;
353
+ try {
354
+ sh.inc("hits_total", { id: "a" });
355
+ sh.inc("hits_total", { id: "b" });
356
+ sh.inc("hits_total", { id: "c" }); // over cap — dropped, not thrown
357
+ } catch (_e) { noThrow = false; }
358
+ check("shadow drop-policy: over-cap inc does not throw", noThrow);
359
+ var snap = sh.snapshot();
360
+ check("shadow drop-policy: over-cap series absent",
361
+ snap.counters.hits_total['{"id":"c"}'] === undefined);
362
+ // Non-mirrored names are ignored (setInfo only stores declared names).
363
+ sh.setInfo("not_declared", "x");
364
+ check("shadow: setInfo ignores non-mirrored name",
365
+ sh.snapshot().info.not_declared === undefined);
366
+ // reset() clears all accumulated state.
367
+ sh.reset();
368
+ check("shadow reset: counters cleared",
369
+ Object.keys(sh.snapshot().counters).length === 0);
370
+ }
371
+
372
+ function run() {
373
+ testCreateRejectsUnknownOpt();
374
+ testCreateRejectsBadCardinalityCap();
375
+ testCreateRejectsBadDefaultLabelName();
376
+ testMetricNameValidation();
377
+ testDuplicateRegistration();
378
+ testCounterDecrementRefused();
379
+ testLabelResolution();
380
+ testCardinalityCapDropsSilently();
381
+ testGaugeBadValueRefused();
382
+ testHistogramBadBuckets();
383
+ testHistogramObserveBadValue();
384
+ testLabelValueEscaping();
385
+ testExpositionHandlerNegotiation();
386
+ testRequestMiddlewareCountsAndTimes();
387
+ testTapDispatch();
388
+ testSnapshotStartWriterValidation();
389
+ testShadowRegistryValidation();
390
+ testShadowRegistryGaugeValueRefusal();
391
+ testShadowRegistryDropPolicyAndReset();
392
+ }
393
+
394
+ if (require.main === module) run();
395
+ module.exports = { run: run };