@blamejs/core 0.7.107 → 0.8.4

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 (100) hide show
  1. package/CHANGELOG.md +41 -1
  2. package/NOTICE +17 -1
  3. package/README.md +4 -3
  4. package/index.js +15 -0
  5. package/lib/asyncapi-bindings.js +160 -0
  6. package/lib/asyncapi-traits.js +143 -0
  7. package/lib/asyncapi.js +531 -0
  8. package/lib/audit-sign.js +1 -1
  9. package/lib/audit.js +68 -2
  10. package/lib/auth/acr-vocabulary.js +265 -0
  11. package/lib/auth/auth-time-tracker.js +111 -0
  12. package/lib/auth/elevation-grant.js +306 -0
  13. package/lib/auth/jwt.js +13 -0
  14. package/lib/auth/lockout.js +16 -3
  15. package/lib/auth/oauth.js +15 -1
  16. package/lib/auth/password.js +22 -2
  17. package/lib/auth/sd-jwt-vc-issuer.js +2 -2
  18. package/lib/auth/sd-jwt-vc.js +7 -2
  19. package/lib/auth/step-up-policy.js +335 -0
  20. package/lib/auth/step-up.js +445 -0
  21. package/lib/break-glass.js +53 -14
  22. package/lib/cache-redis.js +1 -1
  23. package/lib/cache.js +6 -1
  24. package/lib/cli.js +3 -3
  25. package/lib/cluster.js +24 -1
  26. package/lib/compliance-ai-act-logging.js +190 -0
  27. package/lib/compliance-ai-act-prohibited.js +205 -0
  28. package/lib/compliance-ai-act-risk.js +189 -0
  29. package/lib/compliance-ai-act-transparency.js +200 -0
  30. package/lib/compliance-ai-act.js +558 -0
  31. package/lib/compliance.js +12 -2
  32. package/lib/config-drift.js +2 -2
  33. package/lib/crypto-field.js +21 -1
  34. package/lib/crypto.js +114 -1
  35. package/lib/db.js +35 -4
  36. package/lib/dev.js +30 -3
  37. package/lib/dual-control.js +19 -1
  38. package/lib/external-db.js +10 -0
  39. package/lib/file-upload.js +30 -3
  40. package/lib/flag-cache.js +136 -0
  41. package/lib/flag-evaluation-context.js +135 -0
  42. package/lib/flag-providers.js +279 -0
  43. package/lib/flag-targeting.js +210 -0
  44. package/lib/flag.js +284 -0
  45. package/lib/guard-all.js +33 -16
  46. package/lib/guard-csv.js +16 -2
  47. package/lib/guard-html.js +35 -0
  48. package/lib/guard-svg.js +20 -0
  49. package/lib/http-client.js +57 -11
  50. package/lib/inbox.js +391 -0
  51. package/lib/log-stream-syslog.js +8 -0
  52. package/lib/log-stream.js +1 -1
  53. package/lib/mail-arc-sign.js +372 -0
  54. package/lib/mail-auth.js +2 -0
  55. package/lib/mail.js +40 -0
  56. package/lib/middleware/ai-act-disclosure.js +166 -0
  57. package/lib/middleware/asyncapi-serve.js +136 -0
  58. package/lib/middleware/attach-user.js +25 -2
  59. package/lib/middleware/bearer-auth.js +71 -6
  60. package/lib/middleware/body-parser.js +13 -0
  61. package/lib/middleware/cors.js +10 -0
  62. package/lib/middleware/csrf-protect.js +34 -3
  63. package/lib/middleware/dpop.js +3 -3
  64. package/lib/middleware/flag-context.js +76 -0
  65. package/lib/middleware/host-allowlist.js +1 -1
  66. package/lib/middleware/index.js +15 -0
  67. package/lib/middleware/openapi-serve.js +143 -0
  68. package/lib/middleware/require-aal.js +2 -2
  69. package/lib/middleware/require-step-up.js +186 -0
  70. package/lib/middleware/trace-propagate.js +1 -1
  71. package/lib/mtls-ca.js +23 -29
  72. package/lib/mtls-engine-default.js +21 -1
  73. package/lib/network-tls.js +21 -6
  74. package/lib/object-store/sigv4-bucket-ops.js +41 -0
  75. package/lib/observability-otlp-exporter.js +35 -2
  76. package/lib/openapi-paths-builder.js +248 -0
  77. package/lib/openapi-schema-walk.js +192 -0
  78. package/lib/openapi-security.js +169 -0
  79. package/lib/openapi-yaml.js +154 -0
  80. package/lib/openapi.js +443 -0
  81. package/lib/outbox.js +3 -3
  82. package/lib/permissions.js +10 -1
  83. package/lib/pqc-agent.js +22 -1
  84. package/lib/pqc-software.js +195 -0
  85. package/lib/pubsub.js +8 -4
  86. package/lib/redact.js +26 -1
  87. package/lib/retention.js +26 -0
  88. package/lib/router.js +1 -0
  89. package/lib/scheduler.js +57 -1
  90. package/lib/session.js +3 -3
  91. package/lib/ssrf-guard.js +19 -4
  92. package/lib/static.js +12 -0
  93. package/lib/totp.js +16 -0
  94. package/lib/vault/index.js +3 -0
  95. package/lib/vault-aad.js +259 -0
  96. package/lib/vendor/MANIFEST.json +29 -0
  97. package/lib/vendor/noble-post-quantum.cjs +18 -0
  98. package/lib/ws-client.js +978 -0
  99. package/package.json +1 -1
  100. package/sbom.cyclonedx.json +6 -6
@@ -0,0 +1,200 @@
1
+ "use strict";
2
+ /**
3
+ * EU AI Act Article 50 — transparency obligations.
4
+ *
5
+ * Per Regulation (EU) 2024/1689 Art. 50, providers / deployers of
6
+ * certain AI systems must inform end-users that they are interacting
7
+ * with an AI system, OR that content was AI-generated, OR that AI
8
+ * detected emotions / biometric attributes. Effective 2026-08-02.
9
+ *
10
+ * Four obligations:
11
+ *
12
+ * §1 — AI systems intended to interact directly with natural
13
+ * persons MUST disclose to the user that they are interacting
14
+ * with AI (unless this is obvious from context).
15
+ *
16
+ * §2 — Providers of GPAI / generative AI systems generating synthetic
17
+ * audio / image / video / text MUST mark the output as
18
+ * artificially generated or manipulated, in a machine-readable
19
+ * format and detectable as such.
20
+ *
21
+ * §3 — Deployers of emotion-recognition or biometric categorisation
22
+ * systems MUST inform exposed natural persons.
23
+ *
24
+ * §4 — Deployers generating / manipulating image / audio / video
25
+ * constituting a deep fake MUST disclose that the content is
26
+ * artificially generated. Deployers generating / manipulating
27
+ * text published to inform on matters of public interest MUST
28
+ * disclose that the text is AI-generated, unless reviewed by a
29
+ * human editor with editorial responsibility.
30
+ *
31
+ * The framework provides:
32
+ *
33
+ * - banner({ kind }) → builder for the standard disclosure banner
34
+ * - watermark({ kind, ... }) → builder for content-marking tags
35
+ * - cspMetaTag({ ... }) → meta tag pair for HTML pages
36
+ * - jsonLdDisclosure({ ... }) → JSON-LD <script> for structured-data emit
37
+ * - C2pa-stub → operator-feeds-claims pattern for
38
+ * C2PA Content Credentials integration
39
+ */
40
+
41
+ var validateOpts = require("./validate-opts");
42
+ var { ComplianceError } = require("./framework-error");
43
+
44
+ var BANNER_KINDS = Object.freeze([
45
+ "ai-interaction", // Art. 50(1)
46
+ "ai-generated-content", // Art. 50(2) / 50(4)
47
+ "emotion-recognition", // Art. 50(3)
48
+ "biometric-categorisation", // Art. 50(3)
49
+ "deep-fake", // Art. 50(4)
50
+ "ai-text-public-interest", // Art. 50(4) text variant
51
+ ]);
52
+
53
+ var BANNER_TEXT_EN = Object.freeze({
54
+ "ai-interaction": "You are interacting with an AI system.",
55
+ "ai-generated-content": "This content was generated or modified by AI.",
56
+ "emotion-recognition": "This system uses AI to recognise emotional state.",
57
+ "biometric-categorisation": "This system uses AI biometric categorisation.",
58
+ "deep-fake": "This media was generated or modified by AI (deep-fake).",
59
+ "ai-text-public-interest": "This text was generated by AI on a matter of public interest.",
60
+ });
61
+
62
+ function banner(opts) {
63
+ opts = opts || {};
64
+ validateOpts(opts, [
65
+ "kind", "lang", "deployerName", "controllerContact",
66
+ "linkPolicy", "linkContact",
67
+ ], "compliance.aiAct.transparency.banner");
68
+ if (BANNER_KINDS.indexOf(opts.kind) === -1) {
69
+ throw new ComplianceError("compliance-ai-act/bad-banner-kind",
70
+ "transparency.banner: kind must be one of " + BANNER_KINDS.join(", ") +
71
+ " — got " + JSON.stringify(opts.kind));
72
+ }
73
+ var lang = (typeof opts.lang === "string" && opts.lang.length > 0) ? opts.lang : "en";
74
+ var text = BANNER_TEXT_EN[opts.kind];
75
+ // Operators with a non-en lang supply their own translation via the
76
+ // returned object — the framework only ships en defaults for now.
77
+ var out = {
78
+ kind: opts.kind,
79
+ lang: lang,
80
+ text: text,
81
+ article: _articleFor(opts.kind),
82
+ };
83
+ if (typeof opts.deployerName === "string" && opts.deployerName.length > 0) {
84
+ out.deployerName = opts.deployerName;
85
+ }
86
+ if (typeof opts.controllerContact === "string" && opts.controllerContact.length > 0) {
87
+ out.controllerContact = opts.controllerContact;
88
+ }
89
+ if (typeof opts.linkPolicy === "string" && opts.linkPolicy.length > 0) {
90
+ out.linkPolicy = opts.linkPolicy;
91
+ }
92
+ if (typeof opts.linkContact === "string" && opts.linkContact.length > 0) {
93
+ out.linkContact = opts.linkContact;
94
+ }
95
+ return out;
96
+ }
97
+
98
+ function _articleFor(kind) {
99
+ switch (kind) {
100
+ case "ai-interaction": return "Art. 50(1)";
101
+ case "ai-generated-content": return "Art. 50(2)";
102
+ case "emotion-recognition": return "Art. 50(3)";
103
+ case "biometric-categorisation": return "Art. 50(3)";
104
+ case "deep-fake": return "Art. 50(4)";
105
+ case "ai-text-public-interest": return "Art. 50(4)";
106
+ default: return null;
107
+ }
108
+ }
109
+
110
+ function htmlBanner(opts) {
111
+ var b = banner(opts);
112
+ var attrs =
113
+ 'role="status" data-blamejs-aiAct="' + b.article +
114
+ '" data-blamejs-kind="' + b.kind +
115
+ '" lang="' + b.lang + '"';
116
+ return '<div ' + attrs + '>' + _escapeHtml(b.text) + '</div>';
117
+ }
118
+
119
+ function _escapeHtml(s) {
120
+ if (typeof s !== "string") return "";
121
+ return s.replace(/&/g, "&amp;")
122
+ .replace(/</g, "&lt;")
123
+ .replace(/>/g, "&gt;")
124
+ .replace(/"/g, "&quot;");
125
+ }
126
+
127
+ // Watermark builder for Art. 50(2). Operators integrate with C2PA /
128
+ // SynthID / SoundID / hidden-watermark schemes; the framework emits a
129
+ // machine-readable manifest fragment that downstream tooling can attach
130
+ // or hash into the asset.
131
+ function watermark(opts) {
132
+ opts = opts || {};
133
+ validateOpts(opts, [
134
+ "mediaKind", "modelId", "modelVersion", "createdAt", "promptHash",
135
+ "manipulation", "deployerName", "encoding",
136
+ ], "compliance.aiAct.transparency.watermark");
137
+ if (typeof opts.mediaKind !== "string" ||
138
+ ["image", "audio", "video", "text"].indexOf(opts.mediaKind) === -1) {
139
+ throw new ComplianceError("compliance-ai-act/bad-watermark",
140
+ "transparency.watermark: mediaKind must be one of image/audio/video/text — got " +
141
+ JSON.stringify(opts.mediaKind));
142
+ }
143
+ validateOpts.requireNonEmptyString(opts.modelId,
144
+ "transparency.watermark: modelId", ComplianceError, "compliance-ai-act/bad-watermark");
145
+ var manifest = {
146
+ "@context": "https://blamejs.com/schemas/ai-act-watermark/v1",
147
+ aiActArticle: "Art. 50(2)",
148
+ mediaKind: opts.mediaKind,
149
+ modelId: opts.modelId,
150
+ modelVersion: opts.modelVersion || null,
151
+ createdAt: opts.createdAt || new Date().toISOString(),
152
+ promptHash: opts.promptHash || null,
153
+ manipulation: opts.manipulation === true ? true : false,
154
+ deployerName: opts.deployerName || null,
155
+ encoding: opts.encoding || "json",
156
+ };
157
+ return manifest;
158
+ }
159
+
160
+ function jsonLdDisclosure(opts) {
161
+ var w = watermark(opts);
162
+ var script = '<script type="application/ld+json" ' +
163
+ 'data-blamejs-aiAct="Art. 50(2)">' +
164
+ JSON.stringify(w) + '</script>';
165
+ return script;
166
+ }
167
+
168
+ // CSP-meta-tag pair for HTML pages — the disclosure-policy URI plus
169
+ // the AI-Act-Notice header are emitted as <meta> equivalents so static
170
+ // renderers can include them.
171
+ function metaTags(opts) {
172
+ opts = opts || {};
173
+ validateOpts(opts, [
174
+ "kind", "policyUri", "deployerName",
175
+ ], "compliance.aiAct.transparency.metaTags");
176
+ if (BANNER_KINDS.indexOf(opts.kind) === -1) {
177
+ throw new ComplianceError("compliance-ai-act/bad-banner-kind",
178
+ "transparency.metaTags: kind must be one of " + BANNER_KINDS.join(", "));
179
+ }
180
+ var out = [];
181
+ out.push('<meta name="ai-act-notice" content="' + _escapeHtml(opts.kind) + '">');
182
+ out.push('<meta name="ai-act-article" content="' + _escapeHtml(_articleFor(opts.kind)) + '">');
183
+ if (typeof opts.policyUri === "string" && opts.policyUri.length > 0) {
184
+ out.push('<link rel="ai-act-policy" href="' + _escapeHtml(opts.policyUri) + '">');
185
+ }
186
+ if (typeof opts.deployerName === "string" && opts.deployerName.length > 0) {
187
+ out.push('<meta name="ai-act-deployer" content="' + _escapeHtml(opts.deployerName) + '">');
188
+ }
189
+ return out.join("\n");
190
+ }
191
+
192
+ module.exports = {
193
+ BANNER_KINDS: BANNER_KINDS,
194
+ BANNER_TEXT_EN: BANNER_TEXT_EN,
195
+ banner: banner,
196
+ htmlBanner: htmlBanner,
197
+ watermark: watermark,
198
+ jsonLdDisclosure: jsonLdDisclosure,
199
+ metaTags: metaTags,
200
+ };