@blamejs/core 0.14.18 → 0.14.20
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 +4 -0
- package/README.md +2 -2
- package/lib/archive.js +206 -52
- package/lib/auth/oauth.js +794 -1
- package/lib/auth/oid4vci.js +84 -27
- package/lib/auth/sd-jwt-vc-holder.js +46 -1
- package/lib/crypto-field.js +274 -17
- package/lib/mail-auth.js +887 -55
- package/lib/middleware/fetch-metadata.js +115 -14
- package/lib/middleware/scim-server.js +294 -10
- package/lib/middleware/security-headers.js +47 -0
- package/lib/observability.js +39 -1
- package/lib/openapi-paths-builder.js +105 -29
- package/lib/openapi.js +225 -100
- package/package.json +1 -1
- package/sbom.cdx.json +6 -6
package/lib/observability.js
CHANGED
|
@@ -309,7 +309,12 @@ function timed(name, fn, labels) {
|
|
|
309
309
|
// pass attribute keys that should match the keys below. The map is
|
|
310
310
|
// frozen — adding a new attribute requires a release.
|
|
311
311
|
//
|
|
312
|
-
//
|
|
312
|
+
// References:
|
|
313
|
+
// https://opentelemetry.io/docs/specs/semconv/general/attributes/
|
|
314
|
+
// https://opentelemetry.io/docs/specs/semconv/resource/ (resource,
|
|
315
|
+
// telemetry-sdk, deployment-environment)
|
|
316
|
+
// https://opentelemetry.io/docs/specs/semconv/resource/k8s/
|
|
317
|
+
// https://opentelemetry.io/docs/specs/semconv/resource/faas/
|
|
313
318
|
var SEMCONV = Object.freeze({
|
|
314
319
|
// HTTP server (stable per OTel semconv)
|
|
315
320
|
HTTP_REQUEST_METHOD: "http.request.method",
|
|
@@ -370,10 +375,33 @@ var SEMCONV = Object.freeze({
|
|
|
370
375
|
SERVICE_NAME: "service.name",
|
|
371
376
|
SERVICE_VERSION: "service.version",
|
|
372
377
|
SERVICE_INSTANCE_ID: "service.instance.id",
|
|
378
|
+
// peer.service — logical name of the remote service a span talks to,
|
|
379
|
+
// distinct from server.address (the host). OTel semconv (general).
|
|
380
|
+
PEER_SERVICE: "peer.service",
|
|
381
|
+
// Deployment environment (aka deployment tier: "production",
|
|
382
|
+
// "staging"). The bare `deployment.environment` key was deprecated in
|
|
383
|
+
// favour of `deployment.environment.name`; this carries the current
|
|
384
|
+
// stable key. OTel semconv resource/deployment-environment.
|
|
385
|
+
DEPLOYMENT_ENVIRONMENT_NAME: "deployment.environment.name",
|
|
373
386
|
// Telemetry SDK self-identification
|
|
374
387
|
TELEMETRY_SDK_NAME: "telemetry.sdk.name",
|
|
375
388
|
TELEMETRY_SDK_LANGUAGE: "telemetry.sdk.language",
|
|
376
389
|
TELEMETRY_SDK_VERSION: "telemetry.sdk.version",
|
|
390
|
+
// Telemetry distribution self-identification — the redistribution of
|
|
391
|
+
// an OTel SDK an operator runs (e.g. a vendor distro). OTel semconv
|
|
392
|
+
// resource/telemetry-sdk.
|
|
393
|
+
TELEMETRY_DISTRO_NAME: "telemetry.distro.name",
|
|
394
|
+
TELEMETRY_DISTRO_VERSION: "telemetry.distro.version",
|
|
395
|
+
// Instrumentation scope self-identification — the scope (library)
|
|
396
|
+
// that produced a span/metric. OTel semconv otel namespace.
|
|
397
|
+
OTEL_SCOPE_NAME: "otel.scope.name",
|
|
398
|
+
OTEL_SCOPE_VERSION: "otel.scope.version",
|
|
399
|
+
// FaaS (serverless) — function-as-a-service execution context. OTel
|
|
400
|
+
// semconv resource/faas + attributes-registry/faas.
|
|
401
|
+
FAAS_NAME: "faas.name",
|
|
402
|
+
FAAS_VERSION: "faas.version",
|
|
403
|
+
FAAS_INSTANCE: "faas.instance",
|
|
404
|
+
FAAS_TRIGGER: "faas.trigger",
|
|
377
405
|
// GenAI — OpenTelemetry semantic conventions for generative AI
|
|
378
406
|
// workloads (LLM clients, vector DB queries, agent frameworks).
|
|
379
407
|
// Tracking the otel-spec experimental namespace; covers the stable
|
|
@@ -410,9 +438,19 @@ var SEMCONV = Object.freeze({
|
|
|
410
438
|
CONTAINER_ID: "container.id",
|
|
411
439
|
CONTAINER_IMAGE_NAME: "container.image.name",
|
|
412
440
|
CONTAINER_IMAGE_TAG: "container.image.tag",
|
|
441
|
+
// Kubernetes — OTel semconv resource/k8s. Namespace / pod /
|
|
442
|
+
// deployment plus the surrounding workload + node + cluster context.
|
|
413
443
|
K8S_NAMESPACE_NAME: "k8s.namespace.name",
|
|
414
444
|
K8S_POD_NAME: "k8s.pod.name",
|
|
415
445
|
K8S_DEPLOYMENT_NAME: "k8s.deployment.name",
|
|
446
|
+
K8S_NODE_NAME: "k8s.node.name",
|
|
447
|
+
K8S_CLUSTER_NAME: "k8s.cluster.name",
|
|
448
|
+
K8S_CONTAINER_NAME: "k8s.container.name",
|
|
449
|
+
K8S_STATEFULSET_NAME: "k8s.statefulset.name",
|
|
450
|
+
K8S_DAEMONSET_NAME: "k8s.daemonset.name",
|
|
451
|
+
K8S_JOB_NAME: "k8s.job.name",
|
|
452
|
+
K8S_CRONJOB_NAME: "k8s.cronjob.name",
|
|
453
|
+
K8S_REPLICASET_NAME: "k8s.replicaset.name",
|
|
416
454
|
});
|
|
417
455
|
|
|
418
456
|
// W3C Trace Context — parse / build the `traceparent` HTTP header
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
/**
|
|
3
|
-
* OpenAPI 3.1 — paths / operations builder.
|
|
3
|
+
* OpenAPI 3.1 / 3.2 — paths / operations + webhooks builder.
|
|
4
4
|
*
|
|
5
5
|
* Internal to lib/openapi.js. Holds the per-path operation table
|
|
6
6
|
* (method to operationObject) and produces the final `paths` map used
|
|
@@ -13,6 +13,14 @@
|
|
|
13
13
|
*
|
|
14
14
|
* Operation methods accepted: get / put / post / delete / options /
|
|
15
15
|
* head / patch / trace (RFC 9110 + OpenAPI 3.1 §4.8.5).
|
|
16
|
+
*
|
|
17
|
+
* `WebhooksBuilder` shares the same Operation Object normalisation but
|
|
18
|
+
* keys by a free-form webhook NAME (not a URL pattern): the top-level
|
|
19
|
+
* `webhooks` field is a map of named Path Item Objects describing
|
|
20
|
+
* out-of-band requests the API initiates (OpenAPI 3.2 §4.8.2, "Fixed
|
|
21
|
+
* Fields" — `webhooks`; carried forward unchanged from 3.1.0 §4.1).
|
|
22
|
+
* Webhook keys are not URL templates, so the `/`-prefix and
|
|
23
|
+
* path-template-placeholder checks are intentionally not applied.
|
|
16
24
|
*/
|
|
17
25
|
|
|
18
26
|
var validateOpts = require("./validate-opts");
|
|
@@ -39,25 +47,23 @@ function PathsBuilder() {
|
|
|
39
47
|
this._paths = {};
|
|
40
48
|
}
|
|
41
49
|
|
|
42
|
-
|
|
43
|
-
|
|
50
|
+
// _buildOperation — normalise a single Operation Object from operator
|
|
51
|
+
// opts. Shared by PathsBuilder.add and WebhooksBuilder.add. `label` is
|
|
52
|
+
// the caller-facing prefix used in error messages. `declaredPathParams`
|
|
53
|
+
// (out-param object) records every in=path parameter so the caller can
|
|
54
|
+
// verify path-template placeholders against it; webhooks have no URL
|
|
55
|
+
// template so the caller simply ignores it.
|
|
56
|
+
function _buildOperation(method, opts, label, declaredPathParams) {
|
|
44
57
|
if (typeof method !== "string" || VALID_METHODS.indexOf(method.toLowerCase()) === -1) {
|
|
45
58
|
throw new OpenApiError("openapi/bad-method",
|
|
46
|
-
"
|
|
59
|
+
label + ": method must be one of " + VALID_METHODS.join(", ") +
|
|
47
60
|
" - got " + JSON.stringify(method));
|
|
48
61
|
}
|
|
49
|
-
validateOpts.requireNonEmptyString(urlPattern, "paths.add: urlPattern",
|
|
50
|
-
OpenApiError, "openapi/bad-path");
|
|
51
|
-
if (urlPattern.charAt(0) !== "/") {
|
|
52
|
-
throw new OpenApiError("openapi/bad-path",
|
|
53
|
-
"paths.add: urlPattern must start with '/' - got " +
|
|
54
|
-
JSON.stringify(urlPattern));
|
|
55
|
-
}
|
|
56
62
|
validateOpts(opts, [
|
|
57
63
|
"summary", "description", "operationId", "tags",
|
|
58
64
|
"parameters", "requestBody", "responses",
|
|
59
65
|
"security", "deprecated", "servers", "externalDocs",
|
|
60
|
-
],
|
|
66
|
+
], label);
|
|
61
67
|
|
|
62
68
|
var op = {};
|
|
63
69
|
if (typeof opts.summary === "string") op.summary = opts.summary;
|
|
@@ -67,50 +73,65 @@ PathsBuilder.prototype.add = function (method, urlPattern, opts) {
|
|
|
67
73
|
op.tags = opts.tags.map(function (t) {
|
|
68
74
|
if (typeof t !== "string" || t.length === 0) {
|
|
69
75
|
throw new OpenApiError("openapi/bad-tag",
|
|
70
|
-
"
|
|
76
|
+
label + ": tags must be non-empty strings");
|
|
71
77
|
}
|
|
72
78
|
return t;
|
|
73
79
|
});
|
|
74
80
|
}
|
|
75
81
|
|
|
76
82
|
// Parameters
|
|
77
|
-
var declaredPathParams = Object.create(null);
|
|
78
83
|
if (Array.isArray(opts.parameters)) {
|
|
79
84
|
op.parameters = [];
|
|
80
85
|
for (var i = 0; i < opts.parameters.length; i += 1) {
|
|
81
|
-
var p = _normaliseParameter(opts.parameters[i], "
|
|
86
|
+
var p = _normaliseParameter(opts.parameters[i], label + ": parameters[" + i + "]");
|
|
82
87
|
op.parameters.push(p);
|
|
83
88
|
if (p.in === "path") declaredPathParams[p.name] = true;
|
|
84
89
|
}
|
|
85
90
|
}
|
|
86
|
-
// Verify every {placeholder} in path is declared.
|
|
87
|
-
var placeholders = _extractPathParams(urlPattern);
|
|
88
|
-
for (var j = 0; j < placeholders.length; j += 1) {
|
|
89
|
-
if (!declaredPathParams[placeholders[j]]) {
|
|
90
|
-
throw new OpenApiError("openapi/missing-path-param",
|
|
91
|
-
"paths.add: path template " + JSON.stringify(urlPattern) +
|
|
92
|
-
" references {" + placeholders[j] +
|
|
93
|
-
"} but no parameter with in=path name=" + JSON.stringify(placeholders[j]) +
|
|
94
|
-
" was declared");
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
91
|
|
|
98
92
|
// Request body
|
|
99
93
|
if (opts.requestBody) {
|
|
100
|
-
op.requestBody = _normaliseRequestBody(opts.requestBody, "
|
|
94
|
+
op.requestBody = _normaliseRequestBody(opts.requestBody, label + ": requestBody");
|
|
101
95
|
}
|
|
102
96
|
|
|
103
97
|
// Responses (required)
|
|
104
98
|
if (!opts.responses || typeof opts.responses !== "object") {
|
|
105
99
|
throw new OpenApiError("openapi/missing-responses",
|
|
106
|
-
"
|
|
100
|
+
label + ": responses object is required (per OpenAPI 3.1 §4.8.5)");
|
|
107
101
|
}
|
|
108
|
-
op.responses = _normaliseResponses(opts.responses, "
|
|
102
|
+
op.responses = _normaliseResponses(opts.responses, label + ": responses");
|
|
109
103
|
|
|
110
104
|
if (Array.isArray(opts.security)) op.security = opts.security.slice();
|
|
111
105
|
if (opts.deprecated === true) op.deprecated = true;
|
|
112
106
|
if (Array.isArray(opts.servers)) op.servers = opts.servers.slice();
|
|
113
107
|
if (opts.externalDocs) op.externalDocs = opts.externalDocs;
|
|
108
|
+
return op;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
PathsBuilder.prototype.add = function (method, urlPattern, opts) {
|
|
112
|
+
opts = opts || {};
|
|
113
|
+
validateOpts.requireNonEmptyString(urlPattern, "paths.add: urlPattern",
|
|
114
|
+
OpenApiError, "openapi/bad-path");
|
|
115
|
+
if (urlPattern.charAt(0) !== "/") {
|
|
116
|
+
throw new OpenApiError("openapi/bad-path",
|
|
117
|
+
"paths.add: urlPattern must start with '/' - got " +
|
|
118
|
+
JSON.stringify(urlPattern));
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
var declaredPathParams = Object.create(null);
|
|
122
|
+
var op = _buildOperation(method, opts, "paths.add", declaredPathParams);
|
|
123
|
+
|
|
124
|
+
// Verify every {placeholder} in path is declared.
|
|
125
|
+
var placeholders = _extractPathParams(urlPattern);
|
|
126
|
+
for (var j = 0; j < placeholders.length; j += 1) {
|
|
127
|
+
if (!declaredPathParams[placeholders[j]]) {
|
|
128
|
+
throw new OpenApiError("openapi/missing-path-param",
|
|
129
|
+
"paths.add: path template " + JSON.stringify(urlPattern) +
|
|
130
|
+
" references {" + placeholders[j] +
|
|
131
|
+
"} but no parameter with in=path name=" + JSON.stringify(placeholders[j]) +
|
|
132
|
+
" was declared");
|
|
133
|
+
}
|
|
134
|
+
}
|
|
114
135
|
|
|
115
136
|
if (!this._paths[urlPattern]) this._paths[urlPattern] = {};
|
|
116
137
|
if (this._paths[urlPattern][method.toLowerCase()]) {
|
|
@@ -240,8 +261,63 @@ PathsBuilder.prototype.toMap = function () {
|
|
|
240
261
|
return out;
|
|
241
262
|
};
|
|
242
263
|
|
|
264
|
+
// WebhooksBuilder — the top-level `webhooks` field is a map of named
|
|
265
|
+
// Path Item Objects describing requests the API initiates out-of-band
|
|
266
|
+
// (OpenAPI 3.2 §4.8.2 Fixed Fields → `webhooks`; unchanged from
|
|
267
|
+
// 3.1.0 §4.1). Keys are free-form webhook names (e.g. "newPet"), NOT
|
|
268
|
+
// URL templates — no `/`-prefix and no path-template-placeholder
|
|
269
|
+
// validation. Each named entry holds the same Operation Objects as a
|
|
270
|
+
// regular path item.
|
|
271
|
+
function WebhooksBuilder() {
|
|
272
|
+
// Null-prototype map so a free-form webhook name that collides with an
|
|
273
|
+
// Object.prototype member (__proto__ / constructor / prototype) becomes
|
|
274
|
+
// an own property instead of mutating the prototype (CWE-1321).
|
|
275
|
+
this._webhooks = Object.create(null);
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
WebhooksBuilder.prototype.add = function (name, method, opts) {
|
|
279
|
+
opts = opts || {};
|
|
280
|
+
validateOpts.requireNonEmptyString(name, "webhook.add: name",
|
|
281
|
+
OpenApiError, "openapi/bad-webhook");
|
|
282
|
+
if (name === "__proto__" || name === "constructor" || name === "prototype") {
|
|
283
|
+
throw new OpenApiError("openapi/bad-webhook",
|
|
284
|
+
"webhook.add: name must not be a reserved object key (" + JSON.stringify(name) + ")");
|
|
285
|
+
}
|
|
286
|
+
var declaredPathParams = Object.create(null);
|
|
287
|
+
var op = _buildOperation(method, opts, "webhook.add", declaredPathParams);
|
|
288
|
+
if (!this._webhooks[name]) this._webhooks[name] = {};
|
|
289
|
+
if (this._webhooks[name][method.toLowerCase()]) {
|
|
290
|
+
throw new OpenApiError("openapi/duplicate-operation",
|
|
291
|
+
"webhook.add: duplicate operation " + method.toUpperCase() +
|
|
292
|
+
" on webhook " + JSON.stringify(name));
|
|
293
|
+
}
|
|
294
|
+
this._webhooks[name][method.toLowerCase()] = op;
|
|
295
|
+
return op;
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
WebhooksBuilder.prototype.count = function () {
|
|
299
|
+
return Object.keys(this._webhooks).length;
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
WebhooksBuilder.prototype.toMap = function () {
|
|
303
|
+
var sorted = Object.keys(this._webhooks).sort();
|
|
304
|
+
var out = {};
|
|
305
|
+
for (var i = 0; i < sorted.length; i += 1) {
|
|
306
|
+
var name = sorted[i];
|
|
307
|
+
var item = this._webhooks[name];
|
|
308
|
+
var ordered = {};
|
|
309
|
+
for (var j = 0; j < VALID_METHODS.length; j += 1) {
|
|
310
|
+
var method = VALID_METHODS[j];
|
|
311
|
+
if (item[method]) ordered[method] = item[method];
|
|
312
|
+
}
|
|
313
|
+
out[name] = ordered;
|
|
314
|
+
}
|
|
315
|
+
return out;
|
|
316
|
+
};
|
|
317
|
+
|
|
243
318
|
module.exports = {
|
|
244
319
|
PathsBuilder: PathsBuilder,
|
|
320
|
+
WebhooksBuilder: WebhooksBuilder,
|
|
245
321
|
VALID_METHODS: VALID_METHODS,
|
|
246
322
|
_extractPathParams: _extractPathParams,
|
|
247
323
|
OpenApiError: OpenApiError,
|