@naylence/advanced-security 0.3.14 → 0.3.15

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.
@@ -1,5 +1,6 @@
1
1
  'use strict';
2
2
 
3
+ var factory = require('@naylence/factory');
3
4
  var runtime = require('@naylence/runtime');
4
5
  var asn1Schema = require('@peculiar/asn1-schema');
5
6
  var asn1Csr = require('@peculiar/asn1-csr');
@@ -12,603 +13,1127 @@ var ed25519_js = require('@noble/curves/ed25519.js');
12
13
  var hkdf_js = require('@noble/hashes/hkdf.js');
13
14
  var utils_js = require('@noble/hashes/utils.js');
14
15
  var jose = require('jose');
15
- var factory = require('@naylence/factory');
16
16
  var sha256_js = require('@noble/hashes/sha256.js');
17
17
  var x509 = require('@peculiar/x509');
18
18
 
19
- // This file is auto-generated during build - do not edit manually
20
- // Generated from package.json version: 0.3.14
21
19
  /**
22
- * The package version, injected at build time.
23
- * @internal
20
+ * AUTO-GENERATED FILE. DO NOT EDIT DIRECTLY.
21
+ * Generated by scripts/generate-factory-manifest.mjs
22
+ *
23
+ * Provides the list of advanced security factory modules for registration.
24
24
  */
25
- const VERSION = '0.3.14';
25
+ const MODULES = [
26
+ "./security/cert/default-ca-service-factory.js",
27
+ "./security/cert/default-certificate-manager-factory.js",
28
+ "./security/cert/trust-store/browser-trust-store-provider-factory.js",
29
+ "./security/cert/trust-store/node-trust-store-provider-factory.js",
30
+ "./security/encryption/channel/channel-encryption-manager-factory.js",
31
+ "./security/encryption/composite-encryption-manager-factory.js",
32
+ "./security/encryption/default-secure-channel-manager-factory.js",
33
+ "./security/encryption/sealed/x25519-encryption-manager-factory.js",
34
+ "./security/keys/x5c-key-manager-factory.js",
35
+ "./security/signing/eddsa-envelope-signer-factory.js",
36
+ "./security/signing/eddsa-envelope-verifier-factory.js",
37
+ "./stickiness/aft-load-balancer-stickiness-manager-factory.js",
38
+ "./stickiness/aft-replica-stickiness-manager-factory.js",
39
+ "./welcome/advanced-welcome-service-factory.js"
40
+ ];
41
+ const MODULE_LOADERS = {
42
+ "./security/cert/default-ca-service-factory.js": () => Promise.resolve().then(function () { return defaultCaServiceFactory; }),
43
+ "./security/cert/default-certificate-manager-factory.js": () => Promise.resolve().then(function () { return defaultCertificateManagerFactory; }),
44
+ "./security/cert/trust-store/browser-trust-store-provider-factory.js": () => Promise.resolve().then(function () { return browserTrustStoreProviderFactory; }),
45
+ "./security/cert/trust-store/node-trust-store-provider-factory.js": () => Promise.resolve().then(function () { return nodeTrustStoreProviderFactory; }),
46
+ "./security/encryption/channel/channel-encryption-manager-factory.js": () => Promise.resolve().then(function () { return channelEncryptionManagerFactory; }),
47
+ "./security/encryption/composite-encryption-manager-factory.js": () => Promise.resolve().then(function () { return compositeEncryptionManagerFactory; }),
48
+ "./security/encryption/default-secure-channel-manager-factory.js": () => Promise.resolve().then(function () { return defaultSecureChannelManagerFactory; }),
49
+ "./security/encryption/sealed/x25519-encryption-manager-factory.js": () => Promise.resolve().then(function () { return x25519EncryptionManagerFactory; }),
50
+ "./security/keys/x5c-key-manager-factory.js": () => Promise.resolve().then(function () { return x5cKeyManagerFactory; }),
51
+ "./security/signing/eddsa-envelope-signer-factory.js": () => Promise.resolve().then(function () { return eddsaEnvelopeSignerFactory; }),
52
+ "./security/signing/eddsa-envelope-verifier-factory.js": () => Promise.resolve().then(function () { return eddsaEnvelopeVerifierFactory; }),
53
+ "./stickiness/aft-load-balancer-stickiness-manager-factory.js": () => Promise.resolve().then(function () { return aftLoadBalancerStickinessManagerFactory; }),
54
+ "./stickiness/aft-replica-stickiness-manager-factory.js": () => Promise.resolve().then(function () { return aftReplicaStickinessManagerFactory; }),
55
+ "./welcome/advanced-welcome-service-factory.js": () => Promise.resolve().then(function () { return advancedWelcomeServiceFactory; }),
56
+ };
26
57
 
27
- const logger$h = runtime.getLogger("naylence.fame.security.cert.util");
28
- const CACHE_LIMIT = 512;
29
- const OID_ED25519 = "1.3.101.112";
30
- const textEncoder = new TextEncoder();
31
- const trustCache = new Map();
32
- function publicKeyFromX5c(x5c, options = {}) {
33
- if (!Array.isArray(x5c) || x5c.length === 0) {
34
- throw new Error("Empty certificate chain");
58
+ const logger$h = runtime.getLogger("naylence.fame.security.encryption.encryption_manager_registry");
59
+ class EncryptionManagerFactoryRegistry {
60
+ constructor(autoDiscover = true) {
61
+ this.factories = [];
62
+ this.algorithmToFactory = new Map();
63
+ this.typeToFactories = new Map();
64
+ this.factorySet = new Set();
65
+ this.autoDiscoveredFactories = new Set();
66
+ this.autoDiscovered = false;
67
+ if (autoDiscover) {
68
+ this.autoDiscoverFactories();
69
+ }
35
70
  }
36
- const callId = generateCallId();
37
- const enforceNameConstraints = options.enforceNameConstraints ?? true;
38
- const trustStorePem = normalizeTrustStoreOption(options.trustStorePem ?? null);
39
- const returnCertificate = options.returnCertificate ?? false;
40
- const { parsed, chainBytes } = parseCertificateChain(x5c);
41
- logger$h.debug("public_key_from_x5c_called", {
42
- call_id: callId,
43
- x5c_count: parsed.length,
44
- enforce_name_constraints: enforceNameConstraints,
45
- has_trust_store: Boolean(trustStorePem),
46
- return_cert: returnCertificate,
47
- });
48
- let cacheKey = null;
49
- if (!returnCertificate) {
50
- cacheKey = buildCacheKey(chainBytes, trustStorePem, enforceNameConstraints);
51
- const cached = getCachedPublicKey(cacheKey);
52
- if (cached) {
53
- logger$h.debug("certificate_cache_hit", {
54
- call_id: callId,
55
- cache_key: cacheKey,
71
+ autoDiscoverFactories() {
72
+ if (this.autoDiscovered) {
73
+ return;
74
+ }
75
+ try {
76
+ const extensionInfos = factory.ExtensionManager.getExtensionsByType(runtime.ENCRYPTION_MANAGER_FACTORY_BASE_TYPE);
77
+ let registeredCount = 0;
78
+ for (const [factoryName, info] of extensionInfos) {
79
+ if (factoryName === "CompositeEncryptionManager") {
80
+ logger$h.debug("skipping_composite_factory_to_avoid_circular_dependency", {
81
+ factory_name: factoryName,
82
+ });
83
+ continue;
84
+ }
85
+ try {
86
+ const factoryInstance = (info.instance ??
87
+ factory.ExtensionManager.getGlobalFactory(runtime.ENCRYPTION_MANAGER_FACTORY_BASE_TYPE, factoryName));
88
+ this.registerFactory(factoryInstance, { autoDiscovered: true });
89
+ registeredCount += 1;
90
+ logger$h.debug("auto_discovered_factory", {
91
+ factory_name: factoryName,
92
+ factory_class: factoryInstance.constructor.name,
93
+ algorithms: factoryInstance.getSupportedAlgorithms(),
94
+ encryption_type: factoryInstance.getEncryptionType(),
95
+ priority: factoryInstance.getPriority(),
96
+ });
97
+ }
98
+ catch (error) {
99
+ logger$h.warning("failed_to_auto_register_factory", {
100
+ factory_name: factoryName,
101
+ error: error instanceof Error ? error.message : String(error),
102
+ });
103
+ }
104
+ }
105
+ this.autoDiscovered = true;
106
+ logger$h.debug("completed_auto_discovery", {
107
+ registered_factories: registeredCount,
108
+ total_discovered: extensionInfos.size,
109
+ skipped_composite: true,
110
+ });
111
+ }
112
+ catch (error) {
113
+ logger$h.warning("failed_auto_discovery_of_factories", {
114
+ error: error instanceof Error ? error.message : String(error),
56
115
  });
57
- return cached;
58
116
  }
59
- logger$h.debug("certificate_cache_miss", {
60
- call_id: callId,
61
- cache_key: cacheKey,
62
- });
63
117
  }
64
- const validation = validateCertificateChain(parsed, enforceNameConstraints, trustStorePem);
65
- if (cacheKey) {
66
- setCachedPublicKey(cacheKey, validation.publicKey, validation.notAfter);
118
+ registerFactory(factory, options = {}) {
119
+ if (this.factorySet.has(factory)) {
120
+ return;
121
+ }
122
+ this.factorySet.add(factory);
123
+ this.factories.push(factory);
124
+ if (options.autoDiscovered) {
125
+ this.autoDiscoveredFactories.add(factory);
126
+ }
127
+ for (const algorithm of factory.getSupportedAlgorithms()) {
128
+ const existing = this.algorithmToFactory.get(algorithm);
129
+ if (!existing || factory.getPriority() > existing.getPriority()) {
130
+ this.algorithmToFactory.set(algorithm, factory);
131
+ logger$h.debug("registered_algorithm_mapping", {
132
+ algorithm,
133
+ factory: factory.constructor.name,
134
+ priority: factory.getPriority(),
135
+ });
136
+ }
137
+ }
138
+ const encryptionType = factory.getEncryptionType();
139
+ const typeFactories = this.typeToFactories.get(encryptionType) ?? [];
140
+ typeFactories.push(factory);
141
+ typeFactories.sort((a, b) => b.getPriority() - a.getPriority());
142
+ this.typeToFactories.set(encryptionType, typeFactories);
143
+ logger$h.debug("registered_encryption_manager_factory", {
144
+ factory: factory.constructor.name,
145
+ encryption_type: encryptionType,
146
+ algorithms: factory.getSupportedAlgorithms(),
147
+ priority: factory.getPriority(),
148
+ auto_discovered: options.autoDiscovered ?? false,
149
+ });
67
150
  }
68
- if (returnCertificate) {
69
- return {
70
- publicKey: validation.publicKey.slice(),
71
- certificate: validation.certificate,
72
- };
151
+ getFactoryForAlgorithm(algorithm) {
152
+ this.ensureAutoDiscovery();
153
+ return this.algorithmToFactory.get(algorithm);
73
154
  }
74
- return validation.publicKey.slice();
75
- }
76
- function validateJwkX5cCertificate(options) {
77
- const { jwk, trustStorePem = null, enforceNameConstraints = true, strict = true, } = options;
78
- if (!jwk || typeof jwk !== "object") {
79
- const error = "Invalid JWK object";
80
- if (strict) {
81
- throw new Error(error);
155
+ getFactoryForOptions(opts) {
156
+ this.ensureAutoDiscovery();
157
+ for (const factory of this.factories) {
158
+ if (factory.supportsOptions(opts ?? undefined)) {
159
+ logger$h.debug("found_factory_for_options", {
160
+ factory: factory.constructor.name,
161
+ encryption_type: factory.getEncryptionType(),
162
+ });
163
+ return factory;
164
+ }
82
165
  }
83
- return { isValid: false, error };
166
+ logger$h.debug("no_factory_found_for_options", { opts });
167
+ return undefined;
84
168
  }
85
- const x5c = jwk.x5c;
86
- if (x5c === undefined) {
87
- return { isValid: true };
169
+ getFactoriesByType(encryptionType) {
170
+ this.ensureAutoDiscovery();
171
+ return this.typeToFactories.get(encryptionType) ?? [];
88
172
  }
89
- if (!Array.isArray(x5c) ||
90
- x5c.length === 0 ||
91
- x5c.some((entry) => typeof entry !== "string")) {
92
- const error = "Invalid x5c field in JWK";
93
- if (strict) {
94
- throw new Error(error);
95
- }
96
- return { isValid: false, error };
173
+ getAllSupportedAlgorithms() {
174
+ this.ensureAutoDiscovery();
175
+ return Array.from(this.algorithmToFactory.keys());
97
176
  }
98
- try {
99
- publicKeyFromX5c(x5c, {
100
- trustStorePem,
101
- enforceNameConstraints,
102
- });
103
- return { isValid: true };
177
+ getRegistryInfo() {
178
+ return {
179
+ totalFactories: this.factories.length,
180
+ autoDiscovered: this.autoDiscovered,
181
+ algorithmMappings: Object.fromEntries(Array.from(this.algorithmToFactory.entries()).map(([algorithm, factory]) => [algorithm, factory.constructor.name])),
182
+ typeMappings: Object.fromEntries(Array.from(this.typeToFactories.entries()).map(([encType, factories]) => [
183
+ encType,
184
+ factories.map((factory) => factory.constructor.name),
185
+ ])),
186
+ };
104
187
  }
105
- catch (error) {
106
- const message = error instanceof Error ? error.message : String(error ?? "unknown");
107
- const normalized = `Certificate validation failed: ${message}`;
108
- if (strict) {
109
- throw new Error(normalized);
188
+ forceRediscovery() {
189
+ const manualFactories = this.factories.filter((factory) => !this.autoDiscoveredFactories.has(factory));
190
+ this.autoDiscovered = false;
191
+ this.algorithmToFactory.clear();
192
+ this.typeToFactories.clear();
193
+ this.factories.length = 0;
194
+ this.factorySet.clear();
195
+ this.autoDiscoveredFactories.clear();
196
+ for (const factory of manualFactories) {
197
+ this.registerFactory(factory);
110
198
  }
111
- return { isValid: false, error: normalized };
199
+ this.autoDiscoverFactories();
112
200
  }
113
- }
114
- function validateCertificateChain(parsed, enforceNameConstraints, trustStorePem) {
115
- const leaf = parsed[0];
116
- const nowMs = Date.now();
117
- const notBefore = leaf.certificate.tbsCertificate.validity.notBefore.getTime();
118
- const notAfter = leaf.certificate.tbsCertificate.validity.notAfter.getTime();
119
- const notBeforeMs = notBefore.getTime();
120
- const notAfterMs = notAfter.getTime();
121
- if (nowMs < notBeforeMs || nowMs > notAfterMs) {
122
- throw new Error(`Certificate is not currently valid (notBefore: ${notBefore.toISOString()}, notAfter: ${notAfter.toISOString()}, now: ${new Date(nowMs).toISOString()})`);
201
+ isAutoDiscovered() {
202
+ return this.autoDiscovered;
123
203
  }
124
- const issuers = parsed.slice(1);
125
- if (enforceNameConstraints && issuers.length > 0) {
126
- const leafUris = extractUrisFromCert(leaf.certificate);
127
- validateNameConstraints(issuers, leafUris);
204
+ ensureInitialized() {
205
+ this.ensureAutoDiscovery();
128
206
  }
129
- if (trustStorePem) {
130
- validateTrustAnchor(parsed, trustStorePem);
207
+ ensureAutoDiscovery() {
208
+ if (!this.autoDiscovered) {
209
+ this.autoDiscoverFactories();
210
+ }
131
211
  }
132
- validateChainContinuity(parsed);
133
- const publicKey = leaf.subjectPublicKey.slice();
134
- return {
135
- publicKey,
136
- certificate: leaf.certificate,
137
- notAfter,
138
- };
139
212
  }
140
- function parseCertificateChain(x5c) {
141
- const parsed = [];
142
- const derChunks = [];
143
- for (let index = 0; index < x5c.length; index += 1) {
144
- const entry = x5c[index];
145
- if (typeof entry !== "string" || entry.trim().length === 0) {
146
- throw new Error(`Invalid certificate at index ${index}`);
147
- }
148
- let der;
149
- try {
150
- der = decodeBase64$2(entry);
151
- }
152
- catch (error) {
153
- const reason = error instanceof Error ? error.message : String(error);
154
- throw new Error(`Failed to decode certificate at index ${index}: ${reason}`);
155
- }
156
- let certificate;
213
+ const globalRegistry = new EncryptionManagerFactoryRegistry(true);
214
+ function getEncryptionManagerFactoryRegistry() {
215
+ globalRegistry.ensureInitialized();
216
+ return globalRegistry;
217
+ }
218
+
219
+ const SECURITY_PREFIX = "./security/";
220
+ const SECURITY_MODULES = MODULES.filter((spec) => spec.startsWith(SECURITY_PREFIX));
221
+ const EXTRA_MODULES = MODULES.filter((spec) => !spec.startsWith(SECURITY_PREFIX));
222
+ const NODE_ONLY_MODULES = new Set([
223
+ "./security/cert/default-ca-service-factory.js",
224
+ "./security/cert/trust-store/node-trust-store-provider-factory.js",
225
+ ]);
226
+ const FACTORY_MODULE_PREFIX$1 = "@naylence/advanced-security/naylence/fame/";
227
+ const BROWSER_DIST_SEGMENT = "/dist/browser/";
228
+ function detectModuleUrl() {
229
+ if (typeof __filename === "string") {
157
230
  try {
158
- certificate = asn1Schema.AsnConvert.parse(der, asn1X509.Certificate);
231
+ return __filename.startsWith("file://")
232
+ ? __filename
233
+ : `file://${__filename}`;
159
234
  }
160
- catch (error) {
161
- const reason = error instanceof Error ? error.message : String(error);
162
- throw new Error(`Failed to parse certificate at index ${index}: ${reason}`);
235
+ catch {
236
+ // fall through to stack parsing
163
237
  }
164
- parsed.push(createParsedCertificate(certificate, der));
165
- derChunks.push(der);
166
238
  }
167
- return { parsed, chainBytes: concatBytes(derChunks) };
168
- }
169
- function createParsedCertificate(certificate, raw) {
170
- return {
171
- raw,
172
- certificate,
173
- serialNumber: toHex(new Uint8Array(certificate.tbsCertificate.serialNumber)).toUpperCase(),
174
- subjectName: serializeName(certificate.tbsCertificate.subject),
175
- issuerName: serializeName(certificate.tbsCertificate.issuer),
176
- subjectPublicKey: new Uint8Array(certificate.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey).slice(),
177
- };
178
- }
179
- function extractUrisFromCert(cert) {
180
- const extension = findExtension(cert, asn1X509.id_ce_subjectAltName);
181
- if (!extension) {
182
- return [];
239
+ try {
240
+ throw new Error();
183
241
  }
184
- const subjectAlternativeName = asn1Schema.AsnConvert.parse(extension.extnValue.buffer, asn1X509.SubjectAlternativeName);
185
- const uris = [];
186
- for (const generalName of subjectAlternativeName) {
187
- if (generalName.uniformResourceIdentifier) {
188
- uris.push(generalName.uniformResourceIdentifier);
242
+ catch (error) {
243
+ const stack = typeof error === "object" && error && "stack" in error
244
+ ? String(error.stack ?? "")
245
+ : "";
246
+ const lines = stack.split("\n");
247
+ for (const line of lines) {
248
+ const match = line.match(/(https?:\/\/[^\s)]+|file:\/\/[^\s)]+\.(?:js|ts)|\/(?:[^\s)]+\.(?:js|ts)))/u);
249
+ const candidate = match?.[1];
250
+ if (!candidate) {
251
+ continue;
252
+ }
253
+ if (candidate.startsWith("http://") || candidate.startsWith("https://")) {
254
+ return candidate;
255
+ }
256
+ if (candidate.startsWith("file://")) {
257
+ return candidate;
258
+ }
259
+ return `file://${candidate}`;
189
260
  }
190
261
  }
191
- return uris;
262
+ return null;
192
263
  }
193
- function validateNameConstraints(issuers, leafUris) {
194
- for (const issuer of issuers) {
195
- const extension = findExtension(issuer.certificate, asn1X509.id_ce_nameConstraints);
196
- if (!extension) {
197
- continue;
198
- }
199
- const constraints = asn1Schema.AsnConvert.parse(extension.extnValue.buffer, asn1X509.NameConstraints);
200
- if (!constraints.permittedSubtrees) {
201
- continue;
202
- }
203
- const permittedUris = collectPermittedUris(Array.from(constraints.permittedSubtrees));
204
- if (permittedUris.length === 0) {
205
- continue;
206
- }
207
- for (const uri of leafUris) {
208
- const allowed = permittedUris.some((prefix) => uri.startsWith(prefix));
209
- if (!allowed) {
210
- throw new Error(`URI '${uri}' violates name constraints - not in permitted subtrees: ${permittedUris.join(", ")}`);
264
+ function computeBrowserFactoryBase(rawUrl) {
265
+ if (!rawUrl) {
266
+ return null;
267
+ }
268
+ const sanitized = rawUrl.split("?")[0]?.split("#")[0] ?? rawUrl;
269
+ const esmMarker = "/dist/esm/naylence/fame/";
270
+ const distMarker = "/dist/";
271
+ if (sanitized.includes(esmMarker)) {
272
+ return sanitized.slice(0, sanitized.indexOf(esmMarker) + esmMarker.length);
273
+ }
274
+ if (rawUrl.includes(BROWSER_DIST_SEGMENT)) {
275
+ return new URL("../esm/naylence/fame/", rawUrl).href;
276
+ }
277
+ if (sanitized.includes(BROWSER_DIST_SEGMENT)) {
278
+ const base = sanitized.slice(0, sanitized.indexOf(BROWSER_DIST_SEGMENT) + BROWSER_DIST_SEGMENT.length);
279
+ return `${base.replace(/browser\/?$/u, "")}esm/naylence/fame/`;
280
+ }
281
+ if (sanitized.includes(distMarker)) {
282
+ const index = sanitized.indexOf(distMarker);
283
+ const base = sanitized.slice(0, index + distMarker.length);
284
+ return `${base}esm/naylence/fame/`;
285
+ }
286
+ const srcMarker = "/src/naylence/fame/";
287
+ if (sanitized.includes(srcMarker)) {
288
+ const index = sanitized.indexOf(srcMarker);
289
+ const projectRoot = sanitized.slice(0, index);
290
+ return `${projectRoot}/dist/esm/naylence/fame/`;
291
+ }
292
+ if (sanitized.startsWith("http://") || sanitized.startsWith("https://")) {
293
+ try {
294
+ const parsed = new URL(rawUrl);
295
+ const viteDepsSegment = "/node_modules/.vite/deps/";
296
+ if (parsed.pathname.includes(viteDepsSegment)) {
297
+ const baseOrigin = `${parsed.protocol}//${parsed.host}`;
298
+ return `${baseOrigin}/node_modules/@naylence/advanced-security/dist/esm/naylence/fame/`;
211
299
  }
212
300
  }
213
- }
214
- }
215
- function collectPermittedUris(subtrees) {
216
- const uris = [];
217
- for (const subtree of subtrees) {
218
- if (subtree.base.uniformResourceIdentifier &&
219
- subtree.base.uniformResourceIdentifier.length > 0) {
220
- uris.push(subtree.base.uniformResourceIdentifier);
301
+ catch {
302
+ // ignore
221
303
  }
222
304
  }
223
- return uris;
305
+ return null;
224
306
  }
225
- function validateTrustAnchor(chain, trustStorePem) {
226
- const trustedCerts = parseTrustStore(trustStorePem);
227
- if (trustedCerts.length === 0) {
228
- throw new Error("No valid certificates found in trust store");
307
+ const moduleUrl = detectModuleUrl();
308
+ const browserFactoryBase = computeBrowserFactoryBase(moduleUrl);
309
+ const prefersSource = typeof moduleUrl === "string" && moduleUrl.includes("/src/");
310
+ function resolveFactoryModuleSpecifier$1(specifier) {
311
+ if (specifier.startsWith("../")) {
312
+ return `${FACTORY_MODULE_PREFIX$1}${specifier.slice("../".length)}`;
229
313
  }
230
- logger$h.debug("trust_anchor_validation_start", {
231
- chain_length: chain.length,
232
- trust_store_cert_count: trustedCerts.length,
233
- });
234
- const chainInfo = chain.map((cert, index) => `[${index}] ${cert.subjectName} (Serial: ${cert.serialNumber})`);
235
- const trustedInfo = trustedCerts.map((cert, index) => `[${index}] ${cert.subjectName} (Serial: ${cert.serialNumber})`);
236
- logger$h.debug("certificate_chain_validation", {
237
- chain_certificates: chainInfo,
238
- trust_store_certificates: trustedInfo,
239
- });
240
- // Strategy 1: direct trust (exact certificate match)
241
- for (let i = 0; i < chain.length; i += 1) {
242
- const cert = chain[i];
243
- const match = trustedCerts.find((trusted) => trusted.serialNumber === cert.serialNumber &&
244
- namesEqual(trusted.certificate.tbsCertificate.subject, cert.certificate.tbsCertificate.subject));
245
- if (match) {
246
- logger$h.debug("certificate_chain_trust_validation_passed", {
247
- matching_serial: match.serialNumber,
248
- validation_strategy: `direct_trust_cert_${i}`,
249
- });
250
- return;
251
- }
314
+ if (specifier.startsWith("./")) {
315
+ return `${FACTORY_MODULE_PREFIX$1}${specifier.slice("./".length)}`;
252
316
  }
253
- const leaf = chain[0];
254
- // Strategy 2: leaf issuer in trust store
255
- for (const trusted of trustedCerts) {
256
- if (namesEqual(trusted.certificate.tbsCertificate.subject, leaf.certificate.tbsCertificate.issuer) &&
257
- trusted.serialNumber !== leaf.serialNumber) {
258
- verifyCertificateSignature(leaf.certificate, trusted.certificate);
259
- logger$h.debug("certificate_chain_trust_validation_passed", {
260
- matching_serial: trusted.serialNumber,
261
- validation_strategy: "leaf_issuer_trust",
262
- });
317
+ return null;
318
+ }
319
+ function resolveModuleCandidates(spec) {
320
+ const candidates = [];
321
+ const seen = new Set();
322
+ const addCandidate = (candidate) => {
323
+ if (!candidate) {
263
324
  return;
264
325
  }
265
- }
266
- // Strategy 3: any intermediate issuer in trust store
267
- for (let index = 1; index < chain.length; index += 1) {
268
- const intermediate = chain[index];
269
- for (const trusted of trustedCerts) {
270
- if (namesEqual(trusted.certificate.tbsCertificate.subject, intermediate.certificate.tbsCertificate.issuer) &&
271
- trusted.serialNumber !== intermediate.serialNumber) {
272
- verifyCertificateSignature(intermediate.certificate, trusted.certificate);
273
- logger$h.debug("certificate_chain_trust_validation_passed", {
274
- matching_serial: trusted.serialNumber,
275
- validation_strategy: `intermediate_issuer_trust_cert_${index}`,
276
- });
277
- return;
278
- }
326
+ if (!seen.has(candidate)) {
327
+ seen.add(candidate);
328
+ candidates.push(candidate);
329
+ }
330
+ };
331
+ if (prefersSource && spec.startsWith("./")) {
332
+ const sourceCandidate = `../${spec.slice(2)}`;
333
+ addCandidate(sourceCandidate);
334
+ if (sourceCandidate.endsWith(".js")) {
335
+ addCandidate(sourceCandidate.replace(/\.js$/u, ".ts"));
279
336
  }
280
337
  }
281
- logger$h.warning("certificate_chain_trust_validation_failed", {
282
- leaf_subject: leaf.subjectName,
283
- leaf_issuer: leaf.issuerName,
284
- leaf_serial: leaf.serialNumber,
285
- trusted_certificates: trustedInfo,
286
- chain_certificates: chainInfo,
287
- reason: "no_matching_trust_anchor",
288
- });
289
- throw new Error("Certificate chain is not rooted in a trusted anchor");
290
- }
291
- function parseTrustStore(trustStorePem) {
292
- const normalized = normalizePem$2(trustStorePem);
293
- const blocks = extractPemBlocks$1(normalized);
294
- const parsed = [];
295
- for (const block of blocks) {
338
+ if (browserFactoryBase && spec.startsWith("./")) {
296
339
  try {
297
- const der = decodeBase64$2(block);
298
- const certificate = asn1Schema.AsnConvert.parse(der, asn1X509.Certificate);
299
- parsed.push(createParsedCertificate(certificate, der));
340
+ const browserCandidate = new URL(spec.slice("./".length), browserFactoryBase).href;
341
+ addCandidate(browserCandidate);
342
+ if (browserCandidate.endsWith(".js")) {
343
+ addCandidate(browserCandidate.replace(/\.js$/u, ".ts"));
344
+ }
300
345
  }
301
- catch (error) {
302
- const reason = error instanceof Error ? error.message : String(error);
303
- logger$h.debug("trust_store_certificate_parse_failed", { reason });
346
+ catch {
347
+ // ignore resolution failures for browser base
304
348
  }
305
349
  }
306
- return parsed;
307
- }
308
- function extractPemBlocks$1(pem) {
309
- const blocks = [];
310
- const regex = /-----BEGIN CERTIFICATE-----([\s\S]*?)-----END CERTIFICATE-----/gu;
311
- let match;
312
- // eslint-disable-next-line no-cond-assign
313
- while ((match = regex.exec(pem)) !== null) {
314
- const body = match[1] ?? "";
315
- blocks.push(body.replace(/\s+/gu, ""));
350
+ const packageCandidate = resolveFactoryModuleSpecifier$1(spec);
351
+ addCandidate(packageCandidate);
352
+ if (packageCandidate?.endsWith(".js")) {
353
+ addCandidate(packageCandidate.replace(/\.js$/u, ".ts"));
316
354
  }
317
- return blocks;
318
- }
319
- function validateChainContinuity(chain) {
320
- if (chain.length <= 1) {
321
- return;
355
+ const fallback = spec.startsWith("./") ? `../${spec.slice(2)}` : spec;
356
+ addCandidate(fallback);
357
+ if (fallback.endsWith(".js")) {
358
+ addCandidate(fallback.replace(/\.js$/u, ".ts"));
322
359
  }
323
- logger$h.debug("validating_chain_continuity", { chain_length: chain.length });
324
- for (let index = 0; index < chain.length - 1; index += 1) {
325
- const cert = chain[index];
326
- const issuer = chain[index + 1];
327
- if (!namesEqual(cert.certificate.tbsCertificate.issuer, issuer.certificate.tbsCertificate.subject)) {
328
- logger$h.warning("certificate_chain_continuity_failed", {
329
- cert_index: index,
330
- cert_subject: cert.subjectName,
331
- cert_issuer: cert.issuerName,
332
- expected_issuer_subject: issuer.subjectName,
333
- reason: "issuer_name_mismatch",
334
- });
335
- throw new Error(`Certificate chain continuity broken: certificate at index ${index} issuer does not match next certificate subject`);
336
- }
337
- try {
338
- verifyCertificateSignature(cert.certificate, issuer.certificate);
339
- logger$h.debug("chain_continuity_verification_success", {
340
- cert_index: index,
341
- cert_serial: cert.serialNumber,
342
- issuer_serial: issuer.serialNumber,
343
- });
344
- }
345
- catch (error) {
346
- const reason = error instanceof Error ? error.message : String(error);
347
- logger$h.warning("certificate_chain_continuity_failed", {
348
- cert_index: index,
349
- cert_subject: cert.subjectName,
350
- issuer_subject: issuer.subjectName,
351
- cert_serial: cert.serialNumber,
352
- issuer_serial: issuer.serialNumber,
353
- error: reason,
354
- reason: "signature_verification_failed",
355
- });
356
- throw new Error(`Certificate chain continuity broken: certificate at index ${index} was not signed by certificate at index ${index + 1}: ${reason}`);
357
- }
360
+ addCandidate(spec);
361
+ if (spec.endsWith(".js")) {
362
+ addCandidate(spec.replace(/\.js$/u, ".ts"));
358
363
  }
359
- logger$h.debug("chain_continuity_validation_passed", {
360
- chain_length: chain.length,
361
- });
364
+ return candidates;
362
365
  }
363
- function verifyCertificateSignature(certificate, issuer) {
364
- ensureEd25519Support();
365
- const signatureAlgorithm = certificate.signatureAlgorithm.algorithm;
366
- const issuerAlgorithm = issuer.tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm;
367
- if (signatureAlgorithm !== OID_ED25519 || issuerAlgorithm !== OID_ED25519) {
368
- throw new Error(`Unsupported signature algorithm (certificate: ${signatureAlgorithm}, issuer: ${issuerAlgorithm})`);
369
- }
370
- const signatureBytes = new Uint8Array(certificate.signatureValue);
371
- const tbsBytes = new Uint8Array(asn1Schema.AsnConvert.serialize(certificate.tbsCertificate));
372
- const issuerKey = new Uint8Array(issuer.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey);
373
- if (issuerKey.length !== 32) {
374
- throw new Error("Issuer Ed25519 public key must be 32 bytes");
375
- }
376
- const valid = ed25519.verify(signatureBytes, tbsBytes, issuerKey);
377
- if (!valid) {
378
- throw new Error("Certificate signature verification failed");
379
- }
366
+ const registeredModules = new Set();
367
+ const inflightModules = new Map();
368
+ const browserSkippedModules = new Set();
369
+ function isNodeEnvironment$5() {
370
+ return (typeof process !== "undefined" &&
371
+ typeof process.release !== "undefined" &&
372
+ process.release?.name === "node");
380
373
  }
381
- function ensureEd25519Support() {
382
- const etcPatch = ed25519.etc;
383
- if (!etcPatch.sha512) {
384
- etcPatch.sha512 = (message) => sha2_js.sha512(message);
374
+ function shouldSkipModule(spec) {
375
+ if (isNodeEnvironment$5()) {
376
+ return false;
385
377
  }
386
- if (!etcPatch.sha512Sync) {
387
- etcPatch.sha512Sync = (...messages) => {
388
- if (messages.length === 1) {
389
- return sha2_js.sha512(messages[0]);
390
- }
391
- const combined = ed25519.etc.concatBytes(...messages);
392
- return sha2_js.sha512(combined);
393
- };
378
+ if (!NODE_ONLY_MODULES.has(spec)) {
379
+ return false;
380
+ }
381
+ if (!browserSkippedModules.has(spec)) {
382
+ // console.warn(
383
+ // "[advanced-security:factory-manifest] skipped browser-incompatible module",
384
+ // spec,
385
+ // );
386
+ browserSkippedModules.add(spec);
394
387
  }
388
+ return true;
395
389
  }
396
- function findExtension(certificate, oid) {
397
- const extensions = certificate.tbsCertificate.extensions;
398
- if (!extensions) {
390
+ function getDynamicImporter() {
391
+ if (typeof globalThis === "undefined") {
399
392
  return null;
400
393
  }
401
- for (const extension of extensions) {
402
- if (extension.extnID === oid) {
403
- return extension;
404
- }
394
+ const candidate = globalThis.__naylenceFactoryDynamicImporter;
395
+ if (typeof candidate === "function") {
396
+ return candidate;
405
397
  }
406
398
  return null;
407
399
  }
408
- function namesEqual(a, b) {
409
- const left = new Uint8Array(asn1Schema.AsnConvert.serialize(a));
410
- const right = new Uint8Array(asn1Schema.AsnConvert.serialize(b));
411
- if (left.length !== right.length) {
412
- return false;
400
+ async function registerModule(spec, registrar) {
401
+ const candidates = resolveModuleCandidates(spec);
402
+ const dynamicImporter = getDynamicImporter();
403
+ const loader = dynamicImporter
404
+ ? (specifier) => dynamicImporter(specifier)
405
+ : (specifier) => import(/* @vite-ignore */ specifier);
406
+ const attempts = [];
407
+ const staticLoader = MODULE_LOADERS?.[spec];
408
+ if (staticLoader) {
409
+ attempts.push({ load: () => staticLoader(), candidate: spec });
413
410
  }
414
- for (let i = 0; i < left.length; i += 1) {
415
- if (left[i] !== right[i]) {
411
+ for (const candidate of candidates) {
412
+ attempts.push({ load: () => loader(candidate), candidate });
413
+ }
414
+ const registerFromModule = (mod) => {
415
+ const meta = mod.FACTORY_META;
416
+ const Ctor = mod.default;
417
+ if (!meta?.base || !meta?.key || typeof Ctor !== "function") {
418
+ console.warn("[debug] invalid factory module", spec, {
419
+ meta,
420
+ hasCtor: typeof Ctor === "function",
421
+ });
422
+ console.warn("[advanced-security:factory-manifest] skipped", spec, "— missing FACTORY_META or default export ctor");
416
423
  return false;
417
424
  }
425
+ const { base, key, ...metadata } = meta;
426
+ const extraMetadata = Object.keys(metadata).length > 0 ? metadata : undefined;
427
+ // console.log("[debug] registering module", { spec, base, key, metadata: extraMetadata });
428
+ registrar.registerFactory(base, key, Ctor, extraMetadata);
429
+ return true;
430
+ };
431
+ for (const [index, { candidate, load }] of attempts.entries()) {
432
+ try {
433
+ const mod = await load();
434
+ return registerFromModule(mod);
435
+ }
436
+ catch (error) {
437
+ const message = error instanceof Error ? error.message : String(error);
438
+ const moduleNotFound = message.includes("Cannot find module") ||
439
+ message.includes("ERR_MODULE_NOT_FOUND") ||
440
+ message.includes("Unknown file extension") ||
441
+ message.includes("Failed to fetch dynamically imported module") ||
442
+ message.includes("Failed to resolve module specifier") ||
443
+ message.includes("Importing a module script failed");
444
+ const isLastAttempt = index === attempts.length - 1;
445
+ if (!moduleNotFound || isLastAttempt) {
446
+ console.warn("[debug] failed to import candidate", {
447
+ spec,
448
+ candidate,
449
+ message,
450
+ });
451
+ console.warn("[advanced-security:factory-manifest] skipped", spec, "-", message);
452
+ return false;
453
+ }
454
+ }
418
455
  }
419
- return true;
420
- }
421
- function serializeName(name) {
422
- const rdns = Array.from(name);
423
- return rdns
424
- .map((rdn) => Array.from(rdn)
425
- .map((attr) => `${oidToLabel$1(attr.type)}=${attr.value.toString()}`)
426
- .join("+"))
427
- .join(",");
456
+ return false;
428
457
  }
429
- function oidToLabel$1(oid) {
430
- switch (oid) {
431
- case "2.5.4.3":
432
- return "CN";
433
- case "2.5.4.6":
434
- return "C";
435
- case "2.5.4.7":
436
- return "L";
437
- case "2.5.4.8":
438
- return "ST";
439
- case "2.5.4.10":
440
- return "O";
441
- case "2.5.4.11":
442
- return "OU";
443
- default:
444
- return oid;
458
+ async function registerModuleOnce(spec, registrar) {
459
+ if (registeredModules.has(spec)) {
460
+ return false;
445
461
  }
446
- }
447
- function concatBytes(chunks) {
448
- const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
449
- const result = new Uint8Array(totalLength);
450
- let offset = 0;
451
- for (const chunk of chunks) {
452
- result.set(chunk, offset);
453
- offset += chunk.length;
462
+ const inflight = inflightModules.get(spec);
463
+ if (inflight) {
464
+ return inflight;
465
+ }
466
+ const registration = (async () => {
467
+ const registered = await registerModule(spec, registrar);
468
+ if (registered) {
469
+ registeredModules.add(spec);
470
+ }
471
+ return registered;
472
+ })();
473
+ inflightModules.set(spec, registration);
474
+ try {
475
+ return await registration;
476
+ }
477
+ finally {
478
+ inflightModules.delete(spec);
454
479
  }
455
- return result;
456
480
  }
457
- function decodeBase64$2(input) {
458
- if (typeof Buffer !== "undefined") {
459
- const normalized = input.replace(/\s+/gu, "");
460
- return new Uint8Array(Buffer.from(normalized, "base64"));
481
+ async function registerModules(modules, registrar) {
482
+ if (modules.length === 0) {
483
+ return 0;
461
484
  }
462
- if (typeof atob === "function") {
463
- const normalized = input.replace(/\s+/gu, "");
464
- const binary = atob(normalized);
465
- const bytes = new Uint8Array(binary.length);
466
- for (let i = 0; i < binary.length; i += 1) {
467
- bytes[i] = binary.charCodeAt(i);
468
- }
469
- return bytes;
485
+ const eligibleModules = modules.filter((spec) => !shouldSkipModule(spec));
486
+ if (eligibleModules.length === 0) {
487
+ return 0;
470
488
  }
471
- throw new Error("No base64 decoder available in this environment");
489
+ const results = await Promise.all(eligibleModules.map((spec) => registerModuleOnce(spec, registrar)));
490
+ return results.reduce((count, registered) => (registered ? count + 1 : count), 0);
472
491
  }
473
- function toHex(data) {
474
- return Array.from(data)
475
- .map((byte) => byte.toString(16).padStart(2, "0"))
476
- .join("");
477
- }
478
- function buildCacheKey(chainBytes, trustStorePem, enforceNameConstraints) {
479
- const chainHash = toHex(sha2_js.sha256(chainBytes));
480
- const trustHash = trustStorePem
481
- ? toHex(sha2_js.sha256(textEncoder.encode(trustStorePem)))
482
- : "no-trust";
483
- const constraintFlag = enforceNameConstraints ? "nc1" : "nc0";
484
- return `${chainHash}|${trustHash}|${constraintFlag}`;
485
- }
486
- function getCachedPublicKey(cacheKey) {
487
- const entry = trustCache.get(cacheKey);
488
- if (!entry) {
489
- return null;
492
+ async function registerAdvancedSecurityFactories(registrar = factory.Registry, options) {
493
+ const newlyRegisteredSecurity = await registerModules(SECURITY_MODULES, registrar);
494
+ if (newlyRegisteredSecurity > 0) {
495
+ getEncryptionManagerFactoryRegistry().forceRediscovery();
490
496
  }
491
- if (Date.now() > entry.expiresAt) {
492
- trustCache.delete(cacheKey);
493
- logger$h.debug("certificate_cache_expired", { cache_key: cacheKey });
494
- return null;
497
+ {
498
+ await registerModules(EXTRA_MODULES, registrar);
495
499
  }
496
- return entry.value.slice();
497
500
  }
498
- function setCachedPublicKey(cacheKey, value, notAfter) {
499
- while (trustCache.size >= CACHE_LIMIT) {
500
- const firstKey = trustCache.keys().next().value;
501
- if (firstKey === undefined) {
502
- break;
501
+
502
+ // This file is auto-generated during build - do not edit manually
503
+ // Generated from package.json version: 0.3.15
504
+ /**
505
+ * The package version, injected at build time.
506
+ * @internal
507
+ */
508
+ const VERSION = '0.3.15';
509
+
510
+ async function registerAdvancedSecurityPluginFactories(registrar = factory.Registry) {
511
+ await registerAdvancedSecurityFactories(registrar);
512
+ }
513
+ let initialized = false;
514
+ let initializing = null;
515
+ const advancedSecurityPlugin = {
516
+ name: "naylence:advanced-security",
517
+ version: VERSION,
518
+ async register() {
519
+ // console.log('[naylence:advanced-security] register() called, initialized=', initialized);
520
+ if (initialized) {
521
+ // console.log('[naylence:advanced-security] already initialized, skipping');
522
+ return;
503
523
  }
504
- trustCache.delete(firstKey);
505
- logger$h.debug("certificate_cache_evicted", { cache_key: firstKey });
524
+ if (initializing) {
525
+ console.log("[naylence:advanced-security] already initializing, awaiting...");
526
+ await initializing;
527
+ return;
528
+ }
529
+ initializing = (async () => {
530
+ try {
531
+ // console.log('[naylence:advanced-security] registering advanced security factories...');
532
+ await registerAdvancedSecurityPluginFactories();
533
+ // console.log('[naylence:advanced-security] advanced security factories registered');
534
+ initialized = true;
535
+ }
536
+ finally {
537
+ initializing = null;
538
+ }
539
+ })();
540
+ await initializing;
541
+ },
542
+ };
543
+ const ADVANCED_SECURITY_PLUGIN_SPECIFIER = advancedSecurityPlugin.name;
544
+
545
+ var plugin = /*#__PURE__*/Object.freeze({
546
+ __proto__: null,
547
+ ADVANCED_SECURITY_PLUGIN_SPECIFIER: ADVANCED_SECURITY_PLUGIN_SPECIFIER,
548
+ default: advancedSecurityPlugin,
549
+ registerAdvancedSecurityPluginFactories: registerAdvancedSecurityPluginFactories
550
+ });
551
+
552
+ const logger$g = runtime.getLogger("naylence.fame.security.cert.util");
553
+ const CACHE_LIMIT = 512;
554
+ const OID_ED25519 = "1.3.101.112";
555
+ const textEncoder = new TextEncoder();
556
+ const trustCache = new Map();
557
+ function publicKeyFromX5c(x5c, options = {}) {
558
+ if (!Array.isArray(x5c) || x5c.length === 0) {
559
+ throw new Error("Empty certificate chain");
506
560
  }
507
- trustCache.set(cacheKey, {
508
- value: value.slice(),
509
- expiresAt: notAfter.getTime(),
510
- });
511
- logger$h.debug("certificate_cache_stored", {
512
- cache_key: cacheKey,
513
- expires_at: notAfter.toISOString(),
514
- cache_size: trustCache.size,
561
+ const callId = generateCallId();
562
+ const enforceNameConstraints = options.enforceNameConstraints ?? true;
563
+ const trustStorePem = normalizeTrustStoreOption(options.trustStorePem ?? null);
564
+ const returnCertificate = options.returnCertificate ?? false;
565
+ const { parsed, chainBytes } = parseCertificateChain(x5c);
566
+ logger$g.debug("public_key_from_x5c_called", {
567
+ call_id: callId,
568
+ x5c_count: parsed.length,
569
+ enforce_name_constraints: enforceNameConstraints,
570
+ has_trust_store: Boolean(trustStorePem),
571
+ return_cert: returnCertificate,
515
572
  });
516
- }
517
- function normalizeTrustStoreOption(value) {
518
- if (!value) {
519
- return null;
573
+ let cacheKey = null;
574
+ if (!returnCertificate) {
575
+ cacheKey = buildCacheKey(chainBytes, trustStorePem, enforceNameConstraints);
576
+ const cached = getCachedPublicKey(cacheKey);
577
+ if (cached) {
578
+ logger$g.debug("certificate_cache_hit", {
579
+ call_id: callId,
580
+ cache_key: cacheKey,
581
+ });
582
+ return cached;
583
+ }
584
+ logger$g.debug("certificate_cache_miss", {
585
+ call_id: callId,
586
+ cache_key: cacheKey,
587
+ });
520
588
  }
521
- const trimmed = value.trim();
522
- if (trimmed.length === 0) {
523
- return null;
589
+ const validation = validateCertificateChain(parsed, enforceNameConstraints, trustStorePem);
590
+ if (cacheKey) {
591
+ setCachedPublicKey(cacheKey, validation.publicKey, validation.notAfter);
524
592
  }
525
- if (!trimmed.includes("-----BEGIN CERTIFICATE-----")) {
526
- throw new Error("trustStorePem must contain PEM-encoded certificates when provided");
593
+ if (returnCertificate) {
594
+ return {
595
+ publicKey: validation.publicKey.slice(),
596
+ certificate: validation.certificate,
597
+ };
527
598
  }
528
- return normalizePem$2(trimmed);
529
- }
530
- function normalizePem$2(pem) {
531
- return pem.replace(/\r/gu, "").trim();
532
- }
533
- function generateCallId() {
534
- return Math.random().toString(36).slice(2, 10);
599
+ return validation.publicKey.slice();
535
600
  }
536
-
537
- const GRANT_PURPOSE_CA_SIGN = "ca_sign";
538
-
539
- const ED25519_OID$2 = "1.3.101.112";
540
- const OID_COMMON_NAME$2 = "2.5.4.3";
541
- const LOGICAL_URI_PREFIX$1 = "naylence://";
542
- function ensureSubtleCrypto() {
543
- const instance = globalThis.crypto?.subtle;
544
- if (!instance) {
545
- throw new Error("WebCrypto subtle API is required to create a CSR");
601
+ function validateJwkX5cCertificate(options) {
602
+ const { jwk, trustStorePem = null, enforceNameConstraints = true, strict = true, } = options;
603
+ if (!jwk || typeof jwk !== "object") {
604
+ const error = "Invalid JWK object";
605
+ if (strict) {
606
+ throw new Error(error);
607
+ }
608
+ return { isValid: false, error };
546
609
  }
547
- return instance;
548
- }
549
- function buildSubject(commonName) {
550
- if (!commonName || typeof commonName !== "string") {
551
- throw new Error("commonName must be a non-empty string");
610
+ const x5c = jwk.x5c;
611
+ if (x5c === undefined) {
612
+ return { isValid: true };
552
613
  }
553
- return new asn1X509.Name([
554
- new asn1X509.RelativeDistinguishedName([
555
- new asn1X509.AttributeTypeAndValue({
556
- type: OID_COMMON_NAME$2,
557
- value: new asn1X509.AttributeValue({ utf8String: commonName }),
558
- }),
559
- ]),
560
- ]);
561
- }
562
- function arrayBufferToBase64(buffer) {
563
- const bytes = new Uint8Array(buffer);
564
- if (typeof globalThis.Buffer?.from === "function") {
565
- return globalThis.Buffer.from(bytes).toString("base64");
614
+ if (!Array.isArray(x5c) ||
615
+ x5c.length === 0 ||
616
+ x5c.some((entry) => typeof entry !== "string")) {
617
+ const error = "Invalid x5c field in JWK";
618
+ if (strict) {
619
+ throw new Error(error);
620
+ }
621
+ return { isValid: false, error };
566
622
  }
567
- let binary = "";
568
- const chunkSize = 0x8000;
569
- for (let offset = 0; offset < bytes.length; offset += chunkSize) {
570
- const slice = bytes.subarray(offset, offset + chunkSize);
571
- binary += String.fromCharCode(...slice);
623
+ try {
624
+ publicKeyFromX5c(x5c, {
625
+ trustStorePem,
626
+ enforceNameConstraints,
627
+ });
628
+ return { isValid: true };
572
629
  }
573
- if (typeof globalThis.btoa !== "function") {
574
- throw new Error("Base64 encoding not available in this environment");
630
+ catch (error) {
631
+ const message = error instanceof Error ? error.message : String(error ?? "unknown");
632
+ const normalized = `Certificate validation failed: ${message}`;
633
+ if (strict) {
634
+ throw new Error(normalized);
635
+ }
636
+ return { isValid: false, error: normalized };
575
637
  }
576
- return globalThis.btoa(binary);
577
638
  }
578
- function derToPem$1(der, label) {
579
- const base64 = arrayBufferToBase64(der);
580
- const lines = [];
581
- for (let index = 0; index < base64.length; index += 64) {
582
- lines.push(base64.slice(index, index + 64));
639
+ function validateCertificateChain(parsed, enforceNameConstraints, trustStorePem) {
640
+ const leaf = parsed[0];
641
+ const nowMs = Date.now();
642
+ const notBefore = leaf.certificate.tbsCertificate.validity.notBefore.getTime();
643
+ const notAfter = leaf.certificate.tbsCertificate.validity.notAfter.getTime();
644
+ const notBeforeMs = notBefore.getTime();
645
+ const notAfterMs = notAfter.getTime();
646
+ if (nowMs < notBeforeMs || nowMs > notAfterMs) {
647
+ throw new Error(`Certificate is not currently valid (notBefore: ${notBefore.toISOString()}, notAfter: ${notAfter.toISOString()}, now: ${new Date(nowMs).toISOString()})`);
583
648
  }
584
- return `-----BEGIN ${label}-----\n${lines.join("\n")}\n-----END ${label}-----\n`;
585
- }
586
- async function createEd25519Csr(options) {
587
- const subtle = ensureSubtleCrypto();
588
- const { privateKey, publicKey, commonName } = options;
589
- if (!(privateKey instanceof CryptoKey) || privateKey.type !== "private") {
590
- throw new Error("privateKey must be a CryptoKey of type 'private'");
649
+ const issuers = parsed.slice(1);
650
+ if (enforceNameConstraints && issuers.length > 0) {
651
+ const leafUris = extractUrisFromCert(leaf.certificate);
652
+ validateNameConstraints(issuers, leafUris);
591
653
  }
592
- if (!(publicKey instanceof CryptoKey) || publicKey.type !== "public") {
593
- throw new Error("publicKey must be a CryptoKey of type 'public'");
654
+ if (trustStorePem) {
655
+ validateTrustAnchor(parsed, trustStorePem);
594
656
  }
595
- const subject = buildSubject(commonName);
596
- const spkiDer = await subtle.exportKey("spki", publicKey);
597
- const subjectPublicKeyInfo = asn1Schema.AsnConvert.parse(spkiDer, asn1X509.SubjectPublicKeyInfo);
598
- const attributes = new asn1Csr.Attributes();
599
- const sanitizedLogicals = Array.isArray(options.logicals)
600
- ? options.logicals
601
- .map((logical) => logical.trim())
602
- .filter((logical) => logical.length > 0)
603
- : [];
604
- if (sanitizedLogicals.length > 0) {
605
- const san = new asn1X509.SubjectAlternativeName(sanitizedLogicals.map((logical) => new asn1X509.GeneralName({
606
- uniformResourceIdentifier: `${LOGICAL_URI_PREFIX$1}${logical}`,
607
- })));
608
- const extensions = new asn1X509.Extensions([
609
- new asn1X509.Extension({
610
- extnID: asn1X509.id_ce_subjectAltName,
611
- critical: false,
657
+ validateChainContinuity(parsed);
658
+ const publicKey = leaf.subjectPublicKey.slice();
659
+ return {
660
+ publicKey,
661
+ certificate: leaf.certificate,
662
+ notAfter,
663
+ };
664
+ }
665
+ function parseCertificateChain(x5c) {
666
+ const parsed = [];
667
+ const derChunks = [];
668
+ for (let index = 0; index < x5c.length; index += 1) {
669
+ const entry = x5c[index];
670
+ if (typeof entry !== "string" || entry.trim().length === 0) {
671
+ throw new Error(`Invalid certificate at index ${index}`);
672
+ }
673
+ let der;
674
+ try {
675
+ der = decodeBase64$2(entry);
676
+ }
677
+ catch (error) {
678
+ const reason = error instanceof Error ? error.message : String(error);
679
+ throw new Error(`Failed to decode certificate at index ${index}: ${reason}`);
680
+ }
681
+ let certificate;
682
+ try {
683
+ certificate = asn1Schema.AsnConvert.parse(der, asn1X509.Certificate);
684
+ }
685
+ catch (error) {
686
+ const reason = error instanceof Error ? error.message : String(error);
687
+ throw new Error(`Failed to parse certificate at index ${index}: ${reason}`);
688
+ }
689
+ parsed.push(createParsedCertificate(certificate, der));
690
+ derChunks.push(der);
691
+ }
692
+ return { parsed, chainBytes: concatBytes(derChunks) };
693
+ }
694
+ function createParsedCertificate(certificate, raw) {
695
+ return {
696
+ raw,
697
+ certificate,
698
+ serialNumber: toHex(new Uint8Array(certificate.tbsCertificate.serialNumber)).toUpperCase(),
699
+ subjectName: serializeName(certificate.tbsCertificate.subject),
700
+ issuerName: serializeName(certificate.tbsCertificate.issuer),
701
+ subjectPublicKey: new Uint8Array(certificate.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey).slice(),
702
+ };
703
+ }
704
+ function extractUrisFromCert(cert) {
705
+ const extension = findExtension(cert, asn1X509.id_ce_subjectAltName);
706
+ if (!extension) {
707
+ return [];
708
+ }
709
+ const subjectAlternativeName = asn1Schema.AsnConvert.parse(extension.extnValue.buffer, asn1X509.SubjectAlternativeName);
710
+ const uris = [];
711
+ for (const generalName of subjectAlternativeName) {
712
+ if (generalName.uniformResourceIdentifier) {
713
+ uris.push(generalName.uniformResourceIdentifier);
714
+ }
715
+ }
716
+ return uris;
717
+ }
718
+ function validateNameConstraints(issuers, leafUris) {
719
+ for (const issuer of issuers) {
720
+ const extension = findExtension(issuer.certificate, asn1X509.id_ce_nameConstraints);
721
+ if (!extension) {
722
+ continue;
723
+ }
724
+ const constraints = asn1Schema.AsnConvert.parse(extension.extnValue.buffer, asn1X509.NameConstraints);
725
+ if (!constraints.permittedSubtrees) {
726
+ continue;
727
+ }
728
+ const permittedUris = collectPermittedUris(Array.from(constraints.permittedSubtrees));
729
+ if (permittedUris.length === 0) {
730
+ continue;
731
+ }
732
+ for (const uri of leafUris) {
733
+ const allowed = permittedUris.some((prefix) => uri.startsWith(prefix));
734
+ if (!allowed) {
735
+ throw new Error(`URI '${uri}' violates name constraints - not in permitted subtrees: ${permittedUris.join(", ")}`);
736
+ }
737
+ }
738
+ }
739
+ }
740
+ function collectPermittedUris(subtrees) {
741
+ const uris = [];
742
+ for (const subtree of subtrees) {
743
+ if (subtree.base.uniformResourceIdentifier &&
744
+ subtree.base.uniformResourceIdentifier.length > 0) {
745
+ uris.push(subtree.base.uniformResourceIdentifier);
746
+ }
747
+ }
748
+ return uris;
749
+ }
750
+ function validateTrustAnchor(chain, trustStorePem) {
751
+ const trustedCerts = parseTrustStore(trustStorePem);
752
+ if (trustedCerts.length === 0) {
753
+ throw new Error("No valid certificates found in trust store");
754
+ }
755
+ logger$g.debug("trust_anchor_validation_start", {
756
+ chain_length: chain.length,
757
+ trust_store_cert_count: trustedCerts.length,
758
+ });
759
+ const chainInfo = chain.map((cert, index) => `[${index}] ${cert.subjectName} (Serial: ${cert.serialNumber})`);
760
+ const trustedInfo = trustedCerts.map((cert, index) => `[${index}] ${cert.subjectName} (Serial: ${cert.serialNumber})`);
761
+ logger$g.debug("certificate_chain_validation", {
762
+ chain_certificates: chainInfo,
763
+ trust_store_certificates: trustedInfo,
764
+ });
765
+ // Strategy 1: direct trust (exact certificate match)
766
+ for (let i = 0; i < chain.length; i += 1) {
767
+ const cert = chain[i];
768
+ const match = trustedCerts.find((trusted) => trusted.serialNumber === cert.serialNumber &&
769
+ namesEqual(trusted.certificate.tbsCertificate.subject, cert.certificate.tbsCertificate.subject));
770
+ if (match) {
771
+ logger$g.debug("certificate_chain_trust_validation_passed", {
772
+ matching_serial: match.serialNumber,
773
+ validation_strategy: `direct_trust_cert_${i}`,
774
+ });
775
+ return;
776
+ }
777
+ }
778
+ const leaf = chain[0];
779
+ // Strategy 2: leaf issuer in trust store
780
+ for (const trusted of trustedCerts) {
781
+ if (namesEqual(trusted.certificate.tbsCertificate.subject, leaf.certificate.tbsCertificate.issuer) &&
782
+ trusted.serialNumber !== leaf.serialNumber) {
783
+ verifyCertificateSignature(leaf.certificate, trusted.certificate);
784
+ logger$g.debug("certificate_chain_trust_validation_passed", {
785
+ matching_serial: trusted.serialNumber,
786
+ validation_strategy: "leaf_issuer_trust",
787
+ });
788
+ return;
789
+ }
790
+ }
791
+ // Strategy 3: any intermediate issuer in trust store
792
+ for (let index = 1; index < chain.length; index += 1) {
793
+ const intermediate = chain[index];
794
+ for (const trusted of trustedCerts) {
795
+ if (namesEqual(trusted.certificate.tbsCertificate.subject, intermediate.certificate.tbsCertificate.issuer) &&
796
+ trusted.serialNumber !== intermediate.serialNumber) {
797
+ verifyCertificateSignature(intermediate.certificate, trusted.certificate);
798
+ logger$g.debug("certificate_chain_trust_validation_passed", {
799
+ matching_serial: trusted.serialNumber,
800
+ validation_strategy: `intermediate_issuer_trust_cert_${index}`,
801
+ });
802
+ return;
803
+ }
804
+ }
805
+ }
806
+ logger$g.warning("certificate_chain_trust_validation_failed", {
807
+ leaf_subject: leaf.subjectName,
808
+ leaf_issuer: leaf.issuerName,
809
+ leaf_serial: leaf.serialNumber,
810
+ trusted_certificates: trustedInfo,
811
+ chain_certificates: chainInfo,
812
+ reason: "no_matching_trust_anchor",
813
+ });
814
+ throw new Error("Certificate chain is not rooted in a trusted anchor");
815
+ }
816
+ function parseTrustStore(trustStorePem) {
817
+ const normalized = normalizePem$2(trustStorePem);
818
+ const blocks = extractPemBlocks$1(normalized);
819
+ const parsed = [];
820
+ for (const block of blocks) {
821
+ try {
822
+ const der = decodeBase64$2(block);
823
+ const certificate = asn1Schema.AsnConvert.parse(der, asn1X509.Certificate);
824
+ parsed.push(createParsedCertificate(certificate, der));
825
+ }
826
+ catch (error) {
827
+ const reason = error instanceof Error ? error.message : String(error);
828
+ logger$g.debug("trust_store_certificate_parse_failed", { reason });
829
+ }
830
+ }
831
+ return parsed;
832
+ }
833
+ function extractPemBlocks$1(pem) {
834
+ const blocks = [];
835
+ const regex = /-----BEGIN CERTIFICATE-----([\s\S]*?)-----END CERTIFICATE-----/gu;
836
+ let match;
837
+ // eslint-disable-next-line no-cond-assign
838
+ while ((match = regex.exec(pem)) !== null) {
839
+ const body = match[1] ?? "";
840
+ blocks.push(body.replace(/\s+/gu, ""));
841
+ }
842
+ return blocks;
843
+ }
844
+ function validateChainContinuity(chain) {
845
+ if (chain.length <= 1) {
846
+ return;
847
+ }
848
+ logger$g.debug("validating_chain_continuity", { chain_length: chain.length });
849
+ for (let index = 0; index < chain.length - 1; index += 1) {
850
+ const cert = chain[index];
851
+ const issuer = chain[index + 1];
852
+ if (!namesEqual(cert.certificate.tbsCertificate.issuer, issuer.certificate.tbsCertificate.subject)) {
853
+ logger$g.warning("certificate_chain_continuity_failed", {
854
+ cert_index: index,
855
+ cert_subject: cert.subjectName,
856
+ cert_issuer: cert.issuerName,
857
+ expected_issuer_subject: issuer.subjectName,
858
+ reason: "issuer_name_mismatch",
859
+ });
860
+ throw new Error(`Certificate chain continuity broken: certificate at index ${index} issuer does not match next certificate subject`);
861
+ }
862
+ try {
863
+ verifyCertificateSignature(cert.certificate, issuer.certificate);
864
+ logger$g.debug("chain_continuity_verification_success", {
865
+ cert_index: index,
866
+ cert_serial: cert.serialNumber,
867
+ issuer_serial: issuer.serialNumber,
868
+ });
869
+ }
870
+ catch (error) {
871
+ const reason = error instanceof Error ? error.message : String(error);
872
+ logger$g.warning("certificate_chain_continuity_failed", {
873
+ cert_index: index,
874
+ cert_subject: cert.subjectName,
875
+ issuer_subject: issuer.subjectName,
876
+ cert_serial: cert.serialNumber,
877
+ issuer_serial: issuer.serialNumber,
878
+ error: reason,
879
+ reason: "signature_verification_failed",
880
+ });
881
+ throw new Error(`Certificate chain continuity broken: certificate at index ${index} was not signed by certificate at index ${index + 1}: ${reason}`);
882
+ }
883
+ }
884
+ logger$g.debug("chain_continuity_validation_passed", {
885
+ chain_length: chain.length,
886
+ });
887
+ }
888
+ function verifyCertificateSignature(certificate, issuer) {
889
+ ensureEd25519Support();
890
+ const signatureAlgorithm = certificate.signatureAlgorithm.algorithm;
891
+ const issuerAlgorithm = issuer.tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm;
892
+ if (signatureAlgorithm !== OID_ED25519 || issuerAlgorithm !== OID_ED25519) {
893
+ throw new Error(`Unsupported signature algorithm (certificate: ${signatureAlgorithm}, issuer: ${issuerAlgorithm})`);
894
+ }
895
+ const signatureBytes = new Uint8Array(certificate.signatureValue);
896
+ const tbsBytes = new Uint8Array(asn1Schema.AsnConvert.serialize(certificate.tbsCertificate));
897
+ const issuerKey = new Uint8Array(issuer.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey);
898
+ if (issuerKey.length !== 32) {
899
+ throw new Error("Issuer Ed25519 public key must be 32 bytes");
900
+ }
901
+ const valid = ed25519.verify(signatureBytes, tbsBytes, issuerKey);
902
+ if (!valid) {
903
+ throw new Error("Certificate signature verification failed");
904
+ }
905
+ }
906
+ function ensureEd25519Support() {
907
+ const etcPatch = ed25519.etc;
908
+ if (!etcPatch.sha512) {
909
+ etcPatch.sha512 = (message) => sha2_js.sha512(message);
910
+ }
911
+ if (!etcPatch.sha512Sync) {
912
+ etcPatch.sha512Sync = (...messages) => {
913
+ if (messages.length === 1) {
914
+ return sha2_js.sha512(messages[0]);
915
+ }
916
+ const combined = ed25519.etc.concatBytes(...messages);
917
+ return sha2_js.sha512(combined);
918
+ };
919
+ }
920
+ }
921
+ function findExtension(certificate, oid) {
922
+ const extensions = certificate.tbsCertificate.extensions;
923
+ if (!extensions) {
924
+ return null;
925
+ }
926
+ for (const extension of extensions) {
927
+ if (extension.extnID === oid) {
928
+ return extension;
929
+ }
930
+ }
931
+ return null;
932
+ }
933
+ function namesEqual(a, b) {
934
+ const left = new Uint8Array(asn1Schema.AsnConvert.serialize(a));
935
+ const right = new Uint8Array(asn1Schema.AsnConvert.serialize(b));
936
+ if (left.length !== right.length) {
937
+ return false;
938
+ }
939
+ for (let i = 0; i < left.length; i += 1) {
940
+ if (left[i] !== right[i]) {
941
+ return false;
942
+ }
943
+ }
944
+ return true;
945
+ }
946
+ function serializeName(name) {
947
+ const rdns = Array.from(name);
948
+ return rdns
949
+ .map((rdn) => Array.from(rdn)
950
+ .map((attr) => `${oidToLabel$1(attr.type)}=${attr.value.toString()}`)
951
+ .join("+"))
952
+ .join(",");
953
+ }
954
+ function oidToLabel$1(oid) {
955
+ switch (oid) {
956
+ case "2.5.4.3":
957
+ return "CN";
958
+ case "2.5.4.6":
959
+ return "C";
960
+ case "2.5.4.7":
961
+ return "L";
962
+ case "2.5.4.8":
963
+ return "ST";
964
+ case "2.5.4.10":
965
+ return "O";
966
+ case "2.5.4.11":
967
+ return "OU";
968
+ default:
969
+ return oid;
970
+ }
971
+ }
972
+ function concatBytes(chunks) {
973
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
974
+ const result = new Uint8Array(totalLength);
975
+ let offset = 0;
976
+ for (const chunk of chunks) {
977
+ result.set(chunk, offset);
978
+ offset += chunk.length;
979
+ }
980
+ return result;
981
+ }
982
+ function decodeBase64$2(input) {
983
+ if (typeof Buffer !== "undefined") {
984
+ const normalized = input.replace(/\s+/gu, "");
985
+ return new Uint8Array(Buffer.from(normalized, "base64"));
986
+ }
987
+ if (typeof atob === "function") {
988
+ const normalized = input.replace(/\s+/gu, "");
989
+ const binary = atob(normalized);
990
+ const bytes = new Uint8Array(binary.length);
991
+ for (let i = 0; i < binary.length; i += 1) {
992
+ bytes[i] = binary.charCodeAt(i);
993
+ }
994
+ return bytes;
995
+ }
996
+ throw new Error("No base64 decoder available in this environment");
997
+ }
998
+ function toHex(data) {
999
+ return Array.from(data)
1000
+ .map((byte) => byte.toString(16).padStart(2, "0"))
1001
+ .join("");
1002
+ }
1003
+ function buildCacheKey(chainBytes, trustStorePem, enforceNameConstraints) {
1004
+ const chainHash = toHex(sha2_js.sha256(chainBytes));
1005
+ const trustHash = trustStorePem
1006
+ ? toHex(sha2_js.sha256(textEncoder.encode(trustStorePem)))
1007
+ : "no-trust";
1008
+ const constraintFlag = enforceNameConstraints ? "nc1" : "nc0";
1009
+ return `${chainHash}|${trustHash}|${constraintFlag}`;
1010
+ }
1011
+ function getCachedPublicKey(cacheKey) {
1012
+ const entry = trustCache.get(cacheKey);
1013
+ if (!entry) {
1014
+ return null;
1015
+ }
1016
+ if (Date.now() > entry.expiresAt) {
1017
+ trustCache.delete(cacheKey);
1018
+ logger$g.debug("certificate_cache_expired", { cache_key: cacheKey });
1019
+ return null;
1020
+ }
1021
+ return entry.value.slice();
1022
+ }
1023
+ function setCachedPublicKey(cacheKey, value, notAfter) {
1024
+ while (trustCache.size >= CACHE_LIMIT) {
1025
+ const firstKey = trustCache.keys().next().value;
1026
+ if (firstKey === undefined) {
1027
+ break;
1028
+ }
1029
+ trustCache.delete(firstKey);
1030
+ logger$g.debug("certificate_cache_evicted", { cache_key: firstKey });
1031
+ }
1032
+ trustCache.set(cacheKey, {
1033
+ value: value.slice(),
1034
+ expiresAt: notAfter.getTime(),
1035
+ });
1036
+ logger$g.debug("certificate_cache_stored", {
1037
+ cache_key: cacheKey,
1038
+ expires_at: notAfter.toISOString(),
1039
+ cache_size: trustCache.size,
1040
+ });
1041
+ }
1042
+ function normalizeTrustStoreOption(value) {
1043
+ if (!value) {
1044
+ return null;
1045
+ }
1046
+ const trimmed = value.trim();
1047
+ if (trimmed.length === 0) {
1048
+ return null;
1049
+ }
1050
+ if (!trimmed.includes("-----BEGIN CERTIFICATE-----")) {
1051
+ throw new Error("trustStorePem must contain PEM-encoded certificates when provided");
1052
+ }
1053
+ return normalizePem$2(trimmed);
1054
+ }
1055
+ function normalizePem$2(pem) {
1056
+ return pem.replace(/\r/gu, "").trim();
1057
+ }
1058
+ function generateCallId() {
1059
+ return Math.random().toString(36).slice(2, 10);
1060
+ }
1061
+
1062
+ const GRANT_PURPOSE_CA_SIGN = "ca_sign";
1063
+
1064
+ const ED25519_OID$2 = "1.3.101.112";
1065
+ const OID_COMMON_NAME$2 = "2.5.4.3";
1066
+ const LOGICAL_URI_PREFIX$1 = "naylence://";
1067
+ function ensureSubtleCrypto() {
1068
+ const instance = globalThis.crypto?.subtle;
1069
+ if (!instance) {
1070
+ throw new Error("WebCrypto subtle API is required to create a CSR");
1071
+ }
1072
+ return instance;
1073
+ }
1074
+ function buildSubject(commonName) {
1075
+ if (!commonName || typeof commonName !== "string") {
1076
+ throw new Error("commonName must be a non-empty string");
1077
+ }
1078
+ return new asn1X509.Name([
1079
+ new asn1X509.RelativeDistinguishedName([
1080
+ new asn1X509.AttributeTypeAndValue({
1081
+ type: OID_COMMON_NAME$2,
1082
+ value: new asn1X509.AttributeValue({ utf8String: commonName }),
1083
+ }),
1084
+ ]),
1085
+ ]);
1086
+ }
1087
+ function arrayBufferToBase64(buffer) {
1088
+ const bytes = new Uint8Array(buffer);
1089
+ if (typeof globalThis.Buffer?.from === "function") {
1090
+ return globalThis.Buffer.from(bytes).toString("base64");
1091
+ }
1092
+ let binary = "";
1093
+ const chunkSize = 0x8000;
1094
+ for (let offset = 0; offset < bytes.length; offset += chunkSize) {
1095
+ const slice = bytes.subarray(offset, offset + chunkSize);
1096
+ binary += String.fromCharCode(...slice);
1097
+ }
1098
+ if (typeof globalThis.btoa !== "function") {
1099
+ throw new Error("Base64 encoding not available in this environment");
1100
+ }
1101
+ return globalThis.btoa(binary);
1102
+ }
1103
+ function derToPem$1(der, label) {
1104
+ const base64 = arrayBufferToBase64(der);
1105
+ const lines = [];
1106
+ for (let index = 0; index < base64.length; index += 64) {
1107
+ lines.push(base64.slice(index, index + 64));
1108
+ }
1109
+ return `-----BEGIN ${label}-----\n${lines.join("\n")}\n-----END ${label}-----\n`;
1110
+ }
1111
+ async function createEd25519Csr(options) {
1112
+ const subtle = ensureSubtleCrypto();
1113
+ const { privateKey, publicKey, commonName } = options;
1114
+ if (!(privateKey instanceof CryptoKey) || privateKey.type !== "private") {
1115
+ throw new Error("privateKey must be a CryptoKey of type 'private'");
1116
+ }
1117
+ if (!(publicKey instanceof CryptoKey) || publicKey.type !== "public") {
1118
+ throw new Error("publicKey must be a CryptoKey of type 'public'");
1119
+ }
1120
+ const subject = buildSubject(commonName);
1121
+ const spkiDer = await subtle.exportKey("spki", publicKey);
1122
+ const subjectPublicKeyInfo = asn1Schema.AsnConvert.parse(spkiDer, asn1X509.SubjectPublicKeyInfo);
1123
+ const attributes = new asn1Csr.Attributes();
1124
+ const sanitizedLogicals = Array.isArray(options.logicals)
1125
+ ? options.logicals
1126
+ .map((logical) => logical.trim())
1127
+ .filter((logical) => logical.length > 0)
1128
+ : [];
1129
+ if (sanitizedLogicals.length > 0) {
1130
+ const san = new asn1X509.SubjectAlternativeName(sanitizedLogicals.map((logical) => new asn1X509.GeneralName({
1131
+ uniformResourceIdentifier: `${LOGICAL_URI_PREFIX$1}${logical}`,
1132
+ })));
1133
+ const extensions = new asn1X509.Extensions([
1134
+ new asn1X509.Extension({
1135
+ extnID: asn1X509.id_ce_subjectAltName,
1136
+ critical: false,
612
1137
  extnValue: new asn1Schema.OctetString(asn1Schema.AsnConvert.serialize(san)),
613
1138
  }),
614
1139
  ]);
@@ -688,7 +1213,7 @@ const NODE_ID_OID = "1.3.6.1.4.1.58530.4";
688
1213
  * Provides async HTTP client to request certificates from the CA signing service.
689
1214
  */
690
1215
  // Simple logger for now - TODO: integrate with runtime logging
691
- const logger$g = {
1216
+ const logger$f = {
692
1217
  debug: (_event, _meta) => {
693
1218
  // console.log(`[DEBUG] ${event}`, meta);
694
1219
  },
@@ -1160,13 +1685,13 @@ class CAServiceClient {
1160
1685
  const result = await response.json();
1161
1686
  const certificatePem = result.certificate_pem;
1162
1687
  const certificateChainPem = result.certificate_chain_pem || certificatePem;
1163
- logger$g.debug("certificate_request_successful", {
1688
+ logger$f.debug("certificate_request_successful", {
1164
1689
  requester_id: requesterId,
1165
1690
  expires_at: result.expires_at,
1166
1691
  });
1167
1692
  // Extract and log certificate information with structured logging
1168
1693
  const certInfo = extractCertificateInfo(certificatePem);
1169
- logger$g.debug("certificate_details", {
1694
+ logger$f.debug("certificate_details", {
1170
1695
  requester_id: requesterId,
1171
1696
  certificate_type: "issued_certificate",
1172
1697
  ...certInfo,
@@ -1185,7 +1710,7 @@ class CAServiceClient {
1185
1710
  // First cert in chain is usually the issued certificate
1186
1711
  if (certPemBlock.trim() !== certificatePem.trim()) {
1187
1712
  const chainCertInfo = extractCertificateInfo(certPemBlock);
1188
- logger$g.debug("certificate_chain_details", {
1713
+ logger$f.debug("certificate_chain_details", {
1189
1714
  requester_id: requesterId,
1190
1715
  certificate_type: "certificate_chain",
1191
1716
  chain_index: i,
@@ -1196,7 +1721,7 @@ class CAServiceClient {
1196
1721
  else {
1197
1722
  // Subsequent certs are intermediate/root CAs
1198
1723
  const caCertInfo = extractCertificateInfo(certPemBlock);
1199
- logger$g.debug("certificate_chain_details", {
1724
+ logger$f.debug("certificate_chain_details", {
1200
1725
  requester_id: requesterId,
1201
1726
  certificate_type: "ca_certificate",
1202
1727
  chain_index: i,
@@ -1224,7 +1749,7 @@ class CAServiceClient {
1224
1749
  // Body read failed entirely
1225
1750
  errorDetail = `HTTP ${response.status}`;
1226
1751
  }
1227
- logger$g.error("certificate_request_failed", {
1752
+ logger$f.error("certificate_request_failed", {
1228
1753
  requester_id: requesterId,
1229
1754
  status_code: response.status,
1230
1755
  error: errorDetail,
@@ -1241,13 +1766,13 @@ class CAServiceClient {
1241
1766
  throw error;
1242
1767
  }
1243
1768
  if (error instanceof Error && error.name === "AbortError") {
1244
- logger$g.error("certificate_request_timeout", {
1769
+ logger$f.error("certificate_request_timeout", {
1245
1770
  requester_id: requesterId,
1246
1771
  timeout_seconds: this.timeoutSeconds,
1247
1772
  });
1248
1773
  throw new CertificateRequestError(`Certificate request timed out after ${this.timeoutSeconds} seconds`);
1249
1774
  }
1250
- logger$g.error("certificate_request_network_error", {
1775
+ logger$f.error("certificate_request_network_error", {
1251
1776
  requester_id: requesterId,
1252
1777
  error: String(error),
1253
1778
  });
@@ -1256,7 +1781,7 @@ class CAServiceClient {
1256
1781
  }
1257
1782
  }
1258
1783
 
1259
- const logger$f = runtime.getLogger("naylence.fame.security.encryption.sealed.x25519_encryption_manager");
1784
+ const logger$e = runtime.getLogger("naylence.fame.security.encryption.sealed.x25519_encryption_manager");
1260
1785
  class X25519EncryptionManager {
1261
1786
  constructor({ keyProvider, nodeLike = null, cryptoProvider = null, }) {
1262
1787
  this.pendingEnvelopes = new Map();
@@ -1273,7 +1798,7 @@ class X25519EncryptionManager {
1273
1798
  // KeyManagementHandler will queue the envelope and send KeyRequest.
1274
1799
  // X25519 should NOT queue here to avoid dual queueing.
1275
1800
  if (opts?.requestAddress) {
1276
- logger$f.debug("key_not_found_delegating_to_key_management", {
1801
+ logger$e.debug("key_not_found_delegating_to_key_management", {
1277
1802
  envelope_id: envelope.id,
1278
1803
  request_address: String(opts.requestAddress),
1279
1804
  });
@@ -1289,7 +1814,7 @@ class X25519EncryptionManager {
1289
1814
  return await this.encryptWithKey(envelope, recipPub, recipKid);
1290
1815
  }
1291
1816
  catch (error) {
1292
- logger$f.error("x25519_encryption_failed", {
1817
+ logger$e.error("x25519_encryption_failed", {
1293
1818
  error: error instanceof Error ? error.message : String(error),
1294
1819
  });
1295
1820
  return runtime.EncryptionResult.skipped(envelope);
@@ -1327,20 +1852,20 @@ class X25519EncryptionManager {
1327
1852
  return envelope;
1328
1853
  }
1329
1854
  catch (error) {
1330
- logger$f.error("x25519_decryption_failed", {
1855
+ logger$e.error("x25519_decryption_failed", {
1331
1856
  error: error instanceof Error ? error.message : String(error),
1332
1857
  });
1333
1858
  return envelope;
1334
1859
  }
1335
1860
  }
1336
1861
  async notifyKeyAvailable(keyId) {
1337
- logger$f.debug("x25519_notify_key_available_called", {
1862
+ logger$e.debug("x25519_notify_key_available_called", {
1338
1863
  key_id: keyId,
1339
1864
  pending_keys: Array.from(this.pendingEnvelopes.keys()),
1340
1865
  });
1341
1866
  const queued = this.pendingEnvelopes.get(keyId);
1342
1867
  if (!queued || queued.length === 0) {
1343
- logger$f.debug("no_queued_envelopes_for_key", {
1868
+ logger$e.debug("no_queued_envelopes_for_key", {
1344
1869
  key_id: keyId,
1345
1870
  has_queue: this.pendingEnvelopes.has(keyId),
1346
1871
  queue_length: queued?.length ?? 0,
@@ -1352,13 +1877,13 @@ class X25519EncryptionManager {
1352
1877
  this.keyRequestsInProgress.delete(keyId);
1353
1878
  const node = this.nodeLike;
1354
1879
  if (!node) {
1355
- logger$f.debug("discarding_queued_envelopes_no_node", {
1880
+ logger$e.debug("discarding_queued_envelopes_no_node", {
1356
1881
  key_id: keyId,
1357
1882
  count: queued.length,
1358
1883
  });
1359
1884
  return;
1360
1885
  }
1361
- logger$f.debug("replaying_envelopes_for_key", {
1886
+ logger$e.debug("replaying_envelopes_for_key", {
1362
1887
  key_id: keyId,
1363
1888
  count: queued.length,
1364
1889
  });
@@ -1367,7 +1892,7 @@ class X25519EncryptionManager {
1367
1892
  await node.deliver(envelope);
1368
1893
  }
1369
1894
  catch (error) {
1370
- logger$f.error("failed_to_replay_envelope", {
1895
+ logger$e.error("failed_to_replay_envelope", {
1371
1896
  key_id: keyId,
1372
1897
  envelope_id: envelope.id,
1373
1898
  error: error instanceof Error ? error.message : String(error),
@@ -1468,7 +1993,7 @@ class X25519EncryptionManager {
1468
1993
  ? this.extractPrivateKeyFromRecord(providerRecord)
1469
1994
  : null;
1470
1995
  if (providerRecordKey) {
1471
- logger$f.debug("using_provider_key_record_private_key", {
1996
+ logger$e.debug("using_provider_key_record_private_key", {
1472
1997
  kid,
1473
1998
  provider_key_id: providerKeyId,
1474
1999
  mismatched_kid: kid && providerKeyId !== kid ? kid : null,
@@ -1478,7 +2003,7 @@ class X25519EncryptionManager {
1478
2003
  }
1479
2004
  if (!providerPem) {
1480
2005
  if (kid && providerKeyId && providerKeyId !== kid) {
1481
- logger$f.debug("crypto_provider_key_id_mismatch_no_private_key", {
2006
+ logger$e.debug("crypto_provider_key_id_mismatch_no_private_key", {
1482
2007
  kid,
1483
2008
  provider_key_id: providerKeyId,
1484
2009
  });
@@ -1490,13 +2015,13 @@ class X25519EncryptionManager {
1490
2015
  return null;
1491
2016
  }
1492
2017
  if (!kid || providerKeyId === kid) {
1493
- logger$f.debug("using_crypto_provider_private_key_fallback", {
2018
+ logger$e.debug("using_crypto_provider_private_key_fallback", {
1494
2019
  kid: kid ?? null,
1495
2020
  provider_key_id: providerKeyId,
1496
2021
  });
1497
2022
  }
1498
2023
  else {
1499
- logger$f.warning("crypto_provider_key_id_mismatch_using_private_key", {
2024
+ logger$e.warning("crypto_provider_key_id_mismatch_using_private_key", {
1500
2025
  kid,
1501
2026
  provider_key_id: providerKeyId,
1502
2027
  key_record_present: Boolean(record),
@@ -1505,7 +2030,7 @@ class X25519EncryptionManager {
1505
2030
  return fallbackKey;
1506
2031
  }
1507
2032
  async queueEnvelopeForKey(envelope, opts, recipientKeyId) {
1508
- logger$f.debug("queueing_envelope_for_sealed_encryption", {
2033
+ logger$e.debug("queueing_envelope_for_sealed_encryption", {
1509
2034
  envelope_id: envelope.id,
1510
2035
  recipient_key_id: recipientKeyId,
1511
2036
  request_address: opts?.requestAddress
@@ -1553,7 +2078,7 @@ class X25519EncryptionManager {
1553
2078
  await node.deliver(keyRequestEnvelope, context);
1554
2079
  }
1555
2080
  catch (error) {
1556
- logger$f.error("failed_to_request_recipient_key", {
2081
+ logger$e.error("failed_to_request_recipient_key", {
1557
2082
  recipient_key_id: recipientKeyId,
1558
2083
  error: error instanceof Error ? error.message : String(error),
1559
2084
  });
@@ -1566,7 +2091,7 @@ class X25519EncryptionManager {
1566
2091
  return this.extractPublicKeyFromRecord(record);
1567
2092
  }
1568
2093
  catch (error) {
1569
- logger$f.debug("recipient_key_lookup_failed", {
2094
+ logger$e.debug("recipient_key_lookup_failed", {
1570
2095
  kid,
1571
2096
  error: error instanceof Error ? error.message : String(error),
1572
2097
  });
@@ -1581,7 +2106,7 @@ class X25519EncryptionManager {
1581
2106
  return await this.keyProvider.getKey(kid);
1582
2107
  }
1583
2108
  catch (error) {
1584
- logger$f.debug("private_key_lookup_failed", {
2109
+ logger$e.debug("private_key_lookup_failed", {
1585
2110
  kid,
1586
2111
  error: error instanceof Error ? error.message : String(error),
1587
2112
  });
@@ -1652,7 +2177,7 @@ class X25519EncryptionManager {
1652
2177
  const base64 = base64Lines.join("");
1653
2178
  const der = this.decodeBase64Flexible(base64);
1654
2179
  if (!der) {
1655
- logger$f.debug("pem_decode_failed", {
2180
+ logger$e.debug("pem_decode_failed", {
1656
2181
  key_type: keyType,
1657
2182
  });
1658
2183
  return null;
@@ -1885,7 +2410,7 @@ var index$1 = /*#__PURE__*/Object.freeze({
1885
2410
  X25519EncryptionManagerFactory: X25519EncryptionManagerFactory
1886
2411
  });
1887
2412
 
1888
- const logger$e = runtime.getLogger("naylence.fame.security.encryption.channel.channel_encryption_manager");
2413
+ const logger$d = runtime.getLogger("naylence.fame.security.encryption.channel.channel_encryption_manager");
1889
2414
  const SUPPORTED_CHANNEL_ALGORITHMS = ["chacha20-poly1305-channel"];
1890
2415
  const CHANNEL_ENCRYPTION_ALGORITHM = "chacha20-poly1305-channel";
1891
2416
  const HANDSHAKE_ALGORITHM = "CHACHA20P1305";
@@ -2036,13 +2561,13 @@ class ChannelEncryptionManager {
2036
2561
  const destination = opts?.destination ?? envelope.to ?? null;
2037
2562
  const destinationStr = toDestinationString(destination);
2038
2563
  if (!destinationStr) {
2039
- logger$e.warning("no_destination_for_channel_encryption", {
2564
+ logger$d.warning("no_destination_for_channel_encryption", {
2040
2565
  envelope_id: envelope.id,
2041
2566
  });
2042
2567
  return runtime.EncryptionResult.skipped(envelope);
2043
2568
  }
2044
2569
  if (!this.secureChannelManager) {
2045
- logger$e.warning("no_secure_channel_manager_available", {
2570
+ logger$d.warning("no_secure_channel_manager_available", {
2046
2571
  envelope_id: envelope.id,
2047
2572
  });
2048
2573
  return runtime.EncryptionResult.skipped(envelope);
@@ -2053,7 +2578,7 @@ class ChannelEncryptionManager {
2053
2578
  return this.encryptWithChannel(envelope, existingChannelId);
2054
2579
  }
2055
2580
  catch (error) {
2056
- logger$e.error("channel_encryption_failed", {
2581
+ logger$d.error("channel_encryption_failed", {
2057
2582
  error: error instanceof Error ? error.message : String(error),
2058
2583
  channel_id: existingChannelId,
2059
2584
  });
@@ -2080,35 +2605,35 @@ class ChannelEncryptionManager {
2080
2605
  }
2081
2606
  const channelId = encHeader.kid;
2082
2607
  if (!channelId) {
2083
- logger$e.error("missing_channel_id_in_encryption_header", {
2608
+ logger$d.error("missing_channel_id_in_encryption_header", {
2084
2609
  envelope_id: envelope.id,
2085
2610
  });
2086
2611
  return envelope;
2087
2612
  }
2088
2613
  const nonce = this.decodeNonceValue(encHeader.val ?? "");
2089
2614
  if (!nonce) {
2090
- logger$e.error("invalid_nonce_in_encryption_header", {
2615
+ logger$d.error("invalid_nonce_in_encryption_header", {
2091
2616
  envelope_id: envelope.id,
2092
2617
  value_present: Boolean(encHeader.val),
2093
2618
  });
2094
2619
  return envelope;
2095
2620
  }
2096
2621
  if (!this.secureChannelManager) {
2097
- logger$e.warning("no_secure_channel_manager_for_decryption", {
2622
+ logger$d.warning("no_secure_channel_manager_for_decryption", {
2098
2623
  envelope_id: envelope.id,
2099
2624
  });
2100
2625
  return envelope;
2101
2626
  }
2102
2627
  const channelState = this.getChannelState(channelId);
2103
2628
  if (!channelState) {
2104
- logger$e.error("channel_not_available_for_decryption", {
2629
+ logger$d.error("channel_not_available_for_decryption", {
2105
2630
  channel_id: channelId,
2106
2631
  });
2107
2632
  return envelope;
2108
2633
  }
2109
2634
  const ciphertext = this.extractCiphertext(frame.payload);
2110
2635
  if (!ciphertext) {
2111
- logger$e.error("invalid_ciphertext_payload", { envelope_id: envelope.id });
2636
+ logger$d.error("invalid_ciphertext_payload", { envelope_id: envelope.id });
2112
2637
  return envelope;
2113
2638
  }
2114
2639
  try {
@@ -2133,7 +2658,7 @@ class ChannelEncryptionManager {
2133
2658
  return envelope;
2134
2659
  }
2135
2660
  catch (error) {
2136
- logger$e.error("channel_decryption_failed", {
2661
+ logger$d.error("channel_decryption_failed", {
2137
2662
  channel_id: channelId,
2138
2663
  error: error instanceof Error ? error.message : String(error),
2139
2664
  });
@@ -2141,24 +2666,24 @@ class ChannelEncryptionManager {
2141
2666
  }
2142
2667
  }
2143
2668
  async notifyChannelEstablished(channelId) {
2144
- logger$e.debug("channel_encryption_manager_notified", {
2669
+ logger$d.debug("channel_encryption_manager_notified", {
2145
2670
  channel_id: channelId,
2146
2671
  manager_type: "channel",
2147
2672
  });
2148
2673
  if (!channelId.startsWith("auto-")) {
2149
- logger$e.warning("unexpected_channel_id_format", { channel_id: channelId });
2674
+ logger$d.warning("unexpected_channel_id_format", { channel_id: channelId });
2150
2675
  return;
2151
2676
  }
2152
2677
  const destinationStr = this.extractDestinationFromChannelId(channelId);
2153
2678
  if (!destinationStr) {
2154
- logger$e.warning("cannot_parse_destination_from_channel_id", {
2679
+ logger$d.warning("cannot_parse_destination_from_channel_id", {
2155
2680
  channel_id: channelId,
2156
2681
  });
2157
2682
  return;
2158
2683
  }
2159
2684
  this.handshakeInProgress.delete(destinationStr);
2160
2685
  if (!this.pendingEnvelopes.has(destinationStr)) {
2161
- logger$e.debug("no_pending_queue_for_destination", {
2686
+ logger$d.debug("no_pending_queue_for_destination", {
2162
2687
  destination: destinationStr,
2163
2688
  });
2164
2689
  return;
@@ -2166,7 +2691,7 @@ class ChannelEncryptionManager {
2166
2691
  const queuedEnvelopes = this.pendingEnvelopes.get(destinationStr) ?? [];
2167
2692
  this.pendingEnvelopes.delete(destinationStr);
2168
2693
  if (!this.secureChannelManager) {
2169
- logger$e.error("no_secure_channel_manager_for_queue_drain", {
2694
+ logger$d.error("no_secure_channel_manager_for_queue_drain", {
2170
2695
  channel_id: channelId,
2171
2696
  });
2172
2697
  return;
@@ -2175,7 +2700,7 @@ class ChannelEncryptionManager {
2175
2700
  try {
2176
2701
  const result = this.encryptWithChannel(envelope, channelId);
2177
2702
  if (!result.envelope) {
2178
- logger$e.warning("failed_to_encrypt_queued_envelope", {
2703
+ logger$d.warning("failed_to_encrypt_queued_envelope", {
2179
2704
  envelope_id: envelope.id,
2180
2705
  channel_id: channelId,
2181
2706
  });
@@ -2185,7 +2710,7 @@ class ChannelEncryptionManager {
2185
2710
  this.runAsyncTask(() => this.deliverEnvelope(encryptedEnvelope), `deliver-queued-${envelope.id}`);
2186
2711
  }
2187
2712
  catch (error) {
2188
- logger$e.error("failed_to_encrypt_queued_envelope", {
2713
+ logger$d.error("failed_to_encrypt_queued_envelope", {
2189
2714
  envelope_id: envelope.id,
2190
2715
  error: error instanceof Error ? error.message : String(error),
2191
2716
  });
@@ -2193,19 +2718,19 @@ class ChannelEncryptionManager {
2193
2718
  }
2194
2719
  }
2195
2720
  async notifyChannelFailed(channelId, reason = "handshake_failed") {
2196
- logger$e.debug("channel_encryption_manager_notified_failure", {
2721
+ logger$d.debug("channel_encryption_manager_notified_failure", {
2197
2722
  channel_id: channelId,
2198
2723
  reason,
2199
2724
  });
2200
2725
  if (!channelId.startsWith("auto-")) {
2201
- logger$e.warning("unexpected_channel_id_format_on_failure", {
2726
+ logger$d.warning("unexpected_channel_id_format_on_failure", {
2202
2727
  channel_id: channelId,
2203
2728
  });
2204
2729
  return;
2205
2730
  }
2206
2731
  const destinationStr = this.extractDestinationFromChannelId(channelId);
2207
2732
  if (!destinationStr) {
2208
- logger$e.warning("cannot_parse_destination_from_channel_id_on_failure", {
2733
+ logger$d.warning("cannot_parse_destination_from_channel_id_on_failure", {
2209
2734
  channel_id: channelId,
2210
2735
  });
2211
2736
  return;
@@ -2215,14 +2740,14 @@ class ChannelEncryptionManager {
2215
2740
  const cachedChannelId = this.addrChannelMap.get(destinationStr);
2216
2741
  if (cachedChannelId === channelId) {
2217
2742
  this.addrChannelMap.delete(destinationStr);
2218
- logger$e.debug("cleared_channel_cache_for_failed_channel", {
2743
+ logger$d.debug("cleared_channel_cache_for_failed_channel", {
2219
2744
  destination: destinationStr,
2220
2745
  channel_id: channelId,
2221
2746
  });
2222
2747
  }
2223
2748
  const queuedEnvelopes = this.pendingEnvelopes.get(destinationStr);
2224
2749
  if (!queuedEnvelopes || queuedEnvelopes.length === 0) {
2225
- logger$e.debug("no_pending_queue_for_failed_destination", {
2750
+ logger$d.debug("no_pending_queue_for_failed_destination", {
2226
2751
  destination: destinationStr,
2227
2752
  });
2228
2753
  return;
@@ -2241,7 +2766,7 @@ class ChannelEncryptionManager {
2241
2766
  const cached = this.addrChannelMap.get(destination);
2242
2767
  if (cached) {
2243
2768
  this.addrChannelMap.delete(destination);
2244
- logger$e.debug("cleared_channel_cache_for_destination", {
2769
+ logger$d.debug("cleared_channel_cache_for_destination", {
2245
2770
  destination,
2246
2771
  cached_channel_id: cached,
2247
2772
  });
@@ -2259,14 +2784,14 @@ class ChannelEncryptionManager {
2259
2784
  }
2260
2785
  const cached = this.addrChannelMap.get(destination);
2261
2786
  if (cached && this.getChannelState(cached)) {
2262
- logger$e.debug("using_cached_channel", { destination, channel_id: cached });
2787
+ logger$d.debug("using_cached_channel", { destination, channel_id: cached });
2263
2788
  return cached;
2264
2789
  }
2265
2790
  const channels = this.secureChannelManager.channels;
2266
2791
  for (const channelId of Object.keys(channels)) {
2267
2792
  if (channelId.startsWith(`auto-${destination}-`)) {
2268
2793
  this.addrChannelMap.set(destination, channelId);
2269
- logger$e.debug("using_existing_channel", {
2794
+ logger$d.debug("using_existing_channel", {
2270
2795
  destination,
2271
2796
  channel_id: channelId,
2272
2797
  });
@@ -2279,12 +2804,12 @@ class ChannelEncryptionManager {
2279
2804
  const queue = this.pendingEnvelopes.get(destinationStr) ?? [];
2280
2805
  queue.push(envelope);
2281
2806
  this.pendingEnvelopes.set(destinationStr, queue);
2282
- logger$e.debug("queued_envelope_for_channel_handshake", {
2807
+ logger$d.debug("queued_envelope_for_channel_handshake", {
2283
2808
  envelope_id: envelope.id,
2284
2809
  destination: destinationStr,
2285
2810
  });
2286
2811
  if (this.handshakeInProgress.has(destinationStr)) {
2287
- logger$e.debug("handshake_already_in_progress", {
2812
+ logger$d.debug("handshake_already_in_progress", {
2288
2813
  destination: destinationStr,
2289
2814
  });
2290
2815
  return;
@@ -2302,7 +2827,7 @@ class ChannelEncryptionManager {
2302
2827
  }
2303
2828
  async initiateChannelHandshakeAsync(destination, destinationStr, opts) {
2304
2829
  if (!this.secureChannelManager) {
2305
- logger$e.error("no_secure_channel_manager_for_async_handshake_initiation");
2830
+ logger$d.error("no_secure_channel_manager_for_async_handshake_initiation");
2306
2831
  return;
2307
2832
  }
2308
2833
  const channelId = this.generateChannelId(destinationStr);
@@ -2310,19 +2835,19 @@ class ChannelEncryptionManager {
2310
2835
  const openFrame = this.secureChannelManager.generateOpenFrame(channelId, HANDSHAKE_ALGORITHM);
2311
2836
  const success = await this.sendSecureOpenFrameAsync(openFrame, destination);
2312
2837
  if (success) {
2313
- logger$e.debug("sent_secure_open_frame_async", {
2838
+ logger$d.debug("sent_secure_open_frame_async", {
2314
2839
  channel_id: channelId,
2315
2840
  destination: destinationStr,
2316
2841
  });
2317
2842
  }
2318
2843
  else {
2319
- logger$e.warning("failed_to_send_secure_open_frame_async", {
2844
+ logger$d.warning("failed_to_send_secure_open_frame_async", {
2320
2845
  channel_id: channelId,
2321
2846
  });
2322
2847
  }
2323
2848
  }
2324
2849
  catch (error) {
2325
- logger$e.error("async_channel_handshake_initiation_failed", {
2850
+ logger$d.error("async_channel_handshake_initiation_failed", {
2326
2851
  destination: destinationStr,
2327
2852
  error: error instanceof Error ? error.message : String(error),
2328
2853
  });
@@ -2331,22 +2856,22 @@ class ChannelEncryptionManager {
2331
2856
  async sendSecureOpenFrameAsync(openFrame, destination) {
2332
2857
  const node = this.nodeLike;
2333
2858
  if (!node) {
2334
- logger$e.error("no_node_available_for_sending_secure_open_async");
2859
+ logger$d.error("no_node_available_for_sending_secure_open_async");
2335
2860
  return false;
2336
2861
  }
2337
2862
  const envelopeFactory = node.envelopeFactory;
2338
2863
  if (!envelopeFactory) {
2339
- logger$e.error("no_envelope_factory_available_for_secure_open_async");
2864
+ logger$d.error("no_envelope_factory_available_for_secure_open_async");
2340
2865
  return false;
2341
2866
  }
2342
2867
  const replyTo = this.buildSystemReplyTo();
2343
2868
  if (!replyTo) {
2344
- logger$e.error("no_physical_path_available_for_reply_to_async");
2869
+ logger$d.error("no_physical_path_available_for_reply_to_async");
2345
2870
  return false;
2346
2871
  }
2347
2872
  const toAddress = toFameAddress(destination);
2348
2873
  if (!toAddress) {
2349
- logger$e.error("invalid_destination_for_secure_open", {
2874
+ logger$d.error("invalid_destination_for_secure_open", {
2350
2875
  destination: String(destination),
2351
2876
  });
2352
2877
  return false;
@@ -2358,7 +2883,7 @@ class ChannelEncryptionManager {
2358
2883
  corrId: core.generateId(),
2359
2884
  });
2360
2885
  await this.deliverEnvelope(envelope);
2361
- logger$e.debug("delivered_secure_open_frame_async", {
2886
+ logger$d.debug("delivered_secure_open_frame_async", {
2362
2887
  channel_id: openFrame.cid,
2363
2888
  });
2364
2889
  return true;
@@ -2366,7 +2891,7 @@ class ChannelEncryptionManager {
2366
2891
  async deliverEnvelope(envelope) {
2367
2892
  const node = this.nodeLike;
2368
2893
  if (!node) {
2369
- logger$e.error("no_node_available_for_delivery", {
2894
+ logger$d.error("no_node_available_for_delivery", {
2370
2895
  envelope_id: envelope.id,
2371
2896
  });
2372
2897
  return;
@@ -2376,19 +2901,19 @@ class ChannelEncryptionManager {
2376
2901
  }
2377
2902
  encryptWithChannel(envelope, channelId) {
2378
2903
  if (!this.secureChannelManager) {
2379
- logger$e.error("no_secure_channel_manager_for_encryption");
2904
+ logger$d.error("no_secure_channel_manager_for_encryption");
2380
2905
  return runtime.EncryptionResult.skipped(envelope);
2381
2906
  }
2382
2907
  const frame = envelope.frame;
2383
2908
  if (!this.isDataFrame(frame)) {
2384
- logger$e.error("attempted_to_encrypt_non_dataframe", {
2909
+ logger$d.error("attempted_to_encrypt_non_dataframe", {
2385
2910
  frame_type: frame.type ?? typeof frame,
2386
2911
  });
2387
2912
  return runtime.EncryptionResult.skipped(envelope);
2388
2913
  }
2389
2914
  const channelState = this.getChannelState(channelId);
2390
2915
  if (!channelState) {
2391
- logger$e.error("channel_not_in_channels", { channel_id: channelId });
2916
+ logger$d.error("channel_not_in_channels", { channel_id: channelId });
2392
2917
  return runtime.EncryptionResult.skipped(envelope);
2393
2918
  }
2394
2919
  const payloadBytes = this.serializePayload(frame.payload);
@@ -2447,7 +2972,7 @@ class ChannelEncryptionManager {
2447
2972
  return decodeBase64$1(payload);
2448
2973
  }
2449
2974
  catch (error) {
2450
- logger$e.error("failed_to_decode_base64_ciphertext", {
2975
+ logger$d.error("failed_to_decode_base64_ciphertext", {
2451
2976
  error: error instanceof Error ? error.message : String(error),
2452
2977
  });
2453
2978
  return null;
@@ -2477,7 +3002,7 @@ class ChannelEncryptionManager {
2477
3002
  return parts.slice(1, -1).join("-");
2478
3003
  }
2479
3004
  async handleFailedEnvelope(envelope, destinationStr, channelId, reason) {
2480
- logger$e.warning("envelope_failed_due_to_channel_handshake_failure", {
3005
+ logger$d.warning("envelope_failed_due_to_channel_handshake_failure", {
2481
3006
  envelope_id: envelope.id,
2482
3007
  destination: destinationStr,
2483
3008
  channel_id: channelId,
@@ -2485,14 +3010,14 @@ class ChannelEncryptionManager {
2485
3010
  });
2486
3011
  const frame = envelope.frame;
2487
3012
  if (!this.isDataFrame(frame)) {
2488
- logger$e.debug("skipping_nack_for_non_dataframe", {
3013
+ logger$d.debug("skipping_nack_for_non_dataframe", {
2489
3014
  envelope_id: envelope.id,
2490
3015
  frame_type: frame.type ?? typeof frame,
2491
3016
  });
2492
3017
  return;
2493
3018
  }
2494
3019
  if (!envelope.replyTo) {
2495
- logger$e.debug("skipping_nack_no_reply_to", { envelope_id: envelope.id });
3020
+ logger$d.debug("skipping_nack_no_reply_to", { envelope_id: envelope.id });
2496
3021
  return;
2497
3022
  }
2498
3023
  await this.sendDeliveryNack(envelope, `channel_handshake_failed: ${reason}`);
@@ -2500,17 +3025,17 @@ class ChannelEncryptionManager {
2500
3025
  async sendDeliveryNack(envelope, failureReason) {
2501
3026
  const node = this.nodeLike;
2502
3027
  if (!node) {
2503
- logger$e.error("no_node_available_for_sending_delivery_nack");
3028
+ logger$d.error("no_node_available_for_sending_delivery_nack");
2504
3029
  return;
2505
3030
  }
2506
3031
  const envelopeFactory = node.envelopeFactory;
2507
3032
  if (!envelopeFactory) {
2508
- logger$e.error("no_envelope_factory_available_for_delivery_nack");
3033
+ logger$d.error("no_envelope_factory_available_for_delivery_nack");
2509
3034
  return;
2510
3035
  }
2511
3036
  const replyTo = toFameAddress(envelope.replyTo ?? null);
2512
3037
  if (!replyTo) {
2513
- logger$e.error("invalid_reply_to_for_delivery_nack", {
3038
+ logger$d.error("invalid_reply_to_for_delivery_nack", {
2514
3039
  reply_to: envelope.replyTo,
2515
3040
  });
2516
3041
  return;
@@ -2527,7 +3052,7 @@ class ChannelEncryptionManager {
2527
3052
  corrId: envelope.corrId ?? core.generateId(),
2528
3053
  });
2529
3054
  await this.deliverEnvelope(nackEnvelope);
2530
- logger$e.debug("delivered_delivery_nack", {
3055
+ logger$d.debug("delivered_delivery_nack", {
2531
3056
  original_envelope_id: envelope.id,
2532
3057
  nack_envelope_id: nackEnvelope.id,
2533
3058
  });
@@ -2565,7 +3090,7 @@ class ChannelEncryptionManager {
2565
3090
  await task();
2566
3091
  }
2567
3092
  catch (error) {
2568
- logger$e.error("async_task_failed", {
3093
+ logger$d.error("async_task_failed", {
2569
3094
  task_name: name,
2570
3095
  error: error instanceof Error ? error.message : String(error),
2571
3096
  });
@@ -2619,7 +3144,7 @@ class ChannelEncryptionManager {
2619
3144
  }
2620
3145
  }
2621
3146
 
2622
- const logger$d = runtime.getLogger("naylence.fame.security.encryption.channel.channel_encryption_manager_factory");
3147
+ const logger$c = runtime.getLogger("naylence.fame.security.encryption.channel.channel_encryption_manager_factory");
2623
3148
  const DEFAULT_SUPPORTED_ALGORITHMS = ["chacha20-poly1305-channel"];
2624
3149
  const FACTORY_META$c = {
2625
3150
  base: runtime.ENCRYPTION_MANAGER_FACTORY_BASE_TYPE,
@@ -2651,7 +3176,7 @@ class ChannelEncryptionManagerFactory extends runtime.EncryptionManagerFactory {
2651
3176
  async create(_config, ...factoryArgs) {
2652
3177
  const [dependencies] = factoryArgs;
2653
3178
  const resolvedDependencies = this.resolveDependencies(dependencies);
2654
- logger$d.debug("creating_channel_encryption_manager", {
3179
+ logger$c.debug("creating_channel_encryption_manager", {
2655
3180
  has_secure_channel_manager: Boolean(resolvedDependencies.secureChannelManager),
2656
3181
  has_node_like: Boolean(resolvedDependencies.nodeLike),
2657
3182
  has_task_spawner: Boolean(resolvedDependencies.taskSpawner),
@@ -2713,7 +3238,7 @@ var index = /*#__PURE__*/Object.freeze({
2713
3238
  ChannelEncryptionManagerFactory: ChannelEncryptionManagerFactory
2714
3239
  });
2715
3240
 
2716
- const logger$c = runtime.getLogger("naylence.fame.security.encryption.default_secure_channel_manager");
3241
+ const logger$b = runtime.getLogger("naylence.fame.security.encryption.default_secure_channel_manager");
2717
3242
  const DEFAULT_ALGORITHM = "CHACHA20P1305";
2718
3243
  const CHANNEL_KEY_LENGTH = 32;
2719
3244
  const NONCE_PREFIX_LENGTH = 4;
@@ -2760,7 +3285,7 @@ class DefaultSecureChannelManager {
2760
3285
  const privateKey = ed25519_js.x25519.utils.randomSecretKey();
2761
3286
  const publicKey = ed25519_js.x25519.scalarMultBase(privateKey);
2762
3287
  this.ephemeralKeys.set(channelId, privateKey);
2763
- logger$c.debug("generated_channel_open", { cid: channelId, algorithm });
3288
+ logger$b.debug("generated_channel_open", { cid: channelId, algorithm });
2764
3289
  return {
2765
3290
  type: "SecureOpen",
2766
3291
  cid: channelId,
@@ -2773,7 +3298,7 @@ class DefaultSecureChannelManager {
2773
3298
  runtime.requireCryptoSupport();
2774
3299
  const algorithm = frame.alg || DEFAULT_ALGORITHM;
2775
3300
  if (!this.isSupportedAlgorithm(algorithm)) {
2776
- logger$c.warning("unsupported_channel_algorithm", {
3301
+ logger$b.warning("unsupported_channel_algorithm", {
2777
3302
  cid: frame.cid,
2778
3303
  alg: algorithm,
2779
3304
  });
@@ -2791,7 +3316,7 @@ class DefaultSecureChannelManager {
2791
3316
  peerPublicKey = decodeBase64(frame.ephPub);
2792
3317
  }
2793
3318
  catch (error) {
2794
- logger$c.warning("invalid_peer_public_key", {
3319
+ logger$b.warning("invalid_peer_public_key", {
2795
3320
  cid: frame.cid,
2796
3321
  error: error instanceof Error ? error.message : String(error),
2797
3322
  });
@@ -2813,7 +3338,7 @@ class DefaultSecureChannelManager {
2813
3338
  algorithm,
2814
3339
  });
2815
3340
  this.channelsMap.set(frame.cid, channelState);
2816
- logger$c.debug("channel_established", { cid: frame.cid, algorithm });
3341
+ logger$b.debug("channel_established", { cid: frame.cid, algorithm });
2817
3342
  myPrivateKey.fill(0);
2818
3343
  sharedSecret.fill(0);
2819
3344
  return {
@@ -2827,7 +3352,7 @@ class DefaultSecureChannelManager {
2827
3352
  async handleAcceptFrame(frame) {
2828
3353
  runtime.requireCryptoSupport();
2829
3354
  if (frame.ok === false) {
2830
- logger$c.warning("channel_rejected", {
3355
+ logger$b.warning("channel_rejected", {
2831
3356
  cid: frame.cid,
2832
3357
  error: frame.reason,
2833
3358
  });
@@ -2836,7 +3361,7 @@ class DefaultSecureChannelManager {
2836
3361
  }
2837
3362
  const privateKey = this.ephemeralKeys.get(frame.cid);
2838
3363
  if (!privateKey) {
2839
- logger$c.error("no_ephemeral_key", { cid: frame.cid });
3364
+ logger$b.error("no_ephemeral_key", { cid: frame.cid });
2840
3365
  return false;
2841
3366
  }
2842
3367
  let peerPublicKey;
@@ -2844,7 +3369,7 @@ class DefaultSecureChannelManager {
2844
3369
  peerPublicKey = decodeBase64(frame.ephPub);
2845
3370
  }
2846
3371
  catch (error) {
2847
- logger$c.warning("invalid_accept_public_key", {
3372
+ logger$b.warning("invalid_accept_public_key", {
2848
3373
  cid: frame.cid,
2849
3374
  error: error instanceof Error ? error.message : String(error),
2850
3375
  });
@@ -2859,17 +3384,17 @@ class DefaultSecureChannelManager {
2859
3384
  algorithm,
2860
3385
  });
2861
3386
  this.channelsMap.set(frame.cid, channelState);
2862
- logger$c.debug("channel_completed", { cid: frame.cid, algorithm });
3387
+ logger$b.debug("channel_completed", { cid: frame.cid, algorithm });
2863
3388
  sharedSecret.fill(0);
2864
3389
  this.cleanupEphemeralKey(frame.cid);
2865
3390
  return true;
2866
3391
  }
2867
3392
  handleCloseFrame(frame) {
2868
3393
  if (this.channelsMap.delete(frame.cid)) {
2869
- logger$c.debug("channel_closed", { cid: frame.cid, reason: frame.reason });
3394
+ logger$b.debug("channel_closed", { cid: frame.cid, reason: frame.reason });
2870
3395
  }
2871
3396
  else {
2872
- logger$c.warning("close_unknown_channel", { cid: frame.cid });
3397
+ logger$b.warning("close_unknown_channel", { cid: frame.cid });
2873
3398
  }
2874
3399
  this.cleanupEphemeralKey(frame.cid);
2875
3400
  }
@@ -2896,7 +3421,7 @@ class DefaultSecureChannelManager {
2896
3421
  }
2897
3422
  closeChannel(channelId, reason = "User requested") {
2898
3423
  if (this.channelsMap.delete(channelId)) {
2899
- logger$c.debug("channel_closed_by_user", { cid: channelId, reason });
3424
+ logger$b.debug("channel_closed_by_user", { cid: channelId, reason });
2900
3425
  }
2901
3426
  this.cleanupEphemeralKey(channelId);
2902
3427
  return {
@@ -2913,7 +3438,7 @@ class DefaultSecureChannelManager {
2913
3438
  this.channelsMap.delete(channelId);
2914
3439
  this.cleanupEphemeralKey(channelId);
2915
3440
  removed += 1;
2916
- logger$c.debug("channel_expired_cleanup", { cid: channelId });
3441
+ logger$b.debug("channel_expired_cleanup", { cid: channelId });
2917
3442
  }
2918
3443
  }
2919
3444
  return removed;
@@ -2942,7 +3467,7 @@ class DefaultSecureChannelManager {
2942
3467
  if (channelId.startsWith(prefix)) {
2943
3468
  if (this.removeChannel(channelId)) {
2944
3469
  removed += 1;
2945
- logger$c.debug("removed_channel_for_destination", {
3470
+ logger$b.debug("removed_channel_for_destination", {
2946
3471
  channel_id: channelId,
2947
3472
  destination,
2948
3473
  });
@@ -2950,7 +3475,7 @@ class DefaultSecureChannelManager {
2950
3475
  }
2951
3476
  }
2952
3477
  if (removed > 0) {
2953
- logger$c.info("cleanup_channels_for_destination", {
3478
+ logger$b.info("cleanup_channels_for_destination", {
2954
3479
  destination,
2955
3480
  channels_removed: removed,
2956
3481
  });
@@ -3022,187 +3547,26 @@ class DefaultSecureChannelManagerFactory extends runtime.SecureChannelManagerFac
3022
3547
  }
3023
3548
  return undefined;
3024
3549
  }
3025
- toPositiveNumber(value) {
3026
- if (typeof value === "number" && Number.isFinite(value) && value > 0) {
3027
- return value;
3028
- }
3029
- if (typeof value === "string" && value.trim() !== "") {
3030
- const parsed = Number(value);
3031
- if (Number.isFinite(parsed) && parsed > 0) {
3032
- return parsed;
3033
- }
3034
- }
3035
- return undefined;
3036
- }
3037
- }
3038
-
3039
- var defaultSecureChannelManagerFactory = /*#__PURE__*/Object.freeze({
3040
- __proto__: null,
3041
- DefaultSecureChannelManagerFactory: DefaultSecureChannelManagerFactory,
3042
- FACTORY_META: FACTORY_META$b,
3043
- default: DefaultSecureChannelManagerFactory
3044
- });
3045
-
3046
- const logger$b = runtime.getLogger("naylence.fame.security.encryption.encryption_manager_registry");
3047
- class EncryptionManagerFactoryRegistry {
3048
- constructor(autoDiscover = true) {
3049
- this.factories = [];
3050
- this.algorithmToFactory = new Map();
3051
- this.typeToFactories = new Map();
3052
- this.factorySet = new Set();
3053
- this.autoDiscoveredFactories = new Set();
3054
- this.autoDiscovered = false;
3055
- if (autoDiscover) {
3056
- this.autoDiscoverFactories();
3057
- }
3058
- }
3059
- autoDiscoverFactories() {
3060
- if (this.autoDiscovered) {
3061
- return;
3062
- }
3063
- try {
3064
- const extensionInfos = factory.ExtensionManager.getExtensionsByType(runtime.ENCRYPTION_MANAGER_FACTORY_BASE_TYPE);
3065
- let registeredCount = 0;
3066
- for (const [factoryName, info] of extensionInfos) {
3067
- if (factoryName === "CompositeEncryptionManager") {
3068
- logger$b.debug("skipping_composite_factory_to_avoid_circular_dependency", {
3069
- factory_name: factoryName,
3070
- });
3071
- continue;
3072
- }
3073
- try {
3074
- const factoryInstance = (info.instance ??
3075
- factory.ExtensionManager.getGlobalFactory(runtime.ENCRYPTION_MANAGER_FACTORY_BASE_TYPE, factoryName));
3076
- this.registerFactory(factoryInstance, { autoDiscovered: true });
3077
- registeredCount += 1;
3078
- logger$b.debug("auto_discovered_factory", {
3079
- factory_name: factoryName,
3080
- factory_class: factoryInstance.constructor.name,
3081
- algorithms: factoryInstance.getSupportedAlgorithms(),
3082
- encryption_type: factoryInstance.getEncryptionType(),
3083
- priority: factoryInstance.getPriority(),
3084
- });
3085
- }
3086
- catch (error) {
3087
- logger$b.warning("failed_to_auto_register_factory", {
3088
- factory_name: factoryName,
3089
- error: error instanceof Error ? error.message : String(error),
3090
- });
3091
- }
3092
- }
3093
- this.autoDiscovered = true;
3094
- logger$b.debug("completed_auto_discovery", {
3095
- registered_factories: registeredCount,
3096
- total_discovered: extensionInfos.size,
3097
- skipped_composite: true,
3098
- });
3099
- }
3100
- catch (error) {
3101
- logger$b.warning("failed_auto_discovery_of_factories", {
3102
- error: error instanceof Error ? error.message : String(error),
3103
- });
3104
- }
3105
- }
3106
- registerFactory(factory, options = {}) {
3107
- if (this.factorySet.has(factory)) {
3108
- return;
3109
- }
3110
- this.factorySet.add(factory);
3111
- this.factories.push(factory);
3112
- if (options.autoDiscovered) {
3113
- this.autoDiscoveredFactories.add(factory);
3114
- }
3115
- for (const algorithm of factory.getSupportedAlgorithms()) {
3116
- const existing = this.algorithmToFactory.get(algorithm);
3117
- if (!existing || factory.getPriority() > existing.getPriority()) {
3118
- this.algorithmToFactory.set(algorithm, factory);
3119
- logger$b.debug("registered_algorithm_mapping", {
3120
- algorithm,
3121
- factory: factory.constructor.name,
3122
- priority: factory.getPriority(),
3123
- });
3124
- }
3125
- }
3126
- const encryptionType = factory.getEncryptionType();
3127
- const typeFactories = this.typeToFactories.get(encryptionType) ?? [];
3128
- typeFactories.push(factory);
3129
- typeFactories.sort((a, b) => b.getPriority() - a.getPriority());
3130
- this.typeToFactories.set(encryptionType, typeFactories);
3131
- logger$b.debug("registered_encryption_manager_factory", {
3132
- factory: factory.constructor.name,
3133
- encryption_type: encryptionType,
3134
- algorithms: factory.getSupportedAlgorithms(),
3135
- priority: factory.getPriority(),
3136
- auto_discovered: options.autoDiscovered ?? false,
3137
- });
3138
- }
3139
- getFactoryForAlgorithm(algorithm) {
3140
- this.ensureAutoDiscovery();
3141
- return this.algorithmToFactory.get(algorithm);
3142
- }
3143
- getFactoryForOptions(opts) {
3144
- this.ensureAutoDiscovery();
3145
- for (const factory of this.factories) {
3146
- if (factory.supportsOptions(opts ?? undefined)) {
3147
- logger$b.debug("found_factory_for_options", {
3148
- factory: factory.constructor.name,
3149
- encryption_type: factory.getEncryptionType(),
3150
- });
3151
- return factory;
3152
- }
3153
- }
3154
- logger$b.debug("no_factory_found_for_options", { opts });
3155
- return undefined;
3156
- }
3157
- getFactoriesByType(encryptionType) {
3158
- this.ensureAutoDiscovery();
3159
- return this.typeToFactories.get(encryptionType) ?? [];
3160
- }
3161
- getAllSupportedAlgorithms() {
3162
- this.ensureAutoDiscovery();
3163
- return Array.from(this.algorithmToFactory.keys());
3164
- }
3165
- getRegistryInfo() {
3166
- return {
3167
- totalFactories: this.factories.length,
3168
- autoDiscovered: this.autoDiscovered,
3169
- algorithmMappings: Object.fromEntries(Array.from(this.algorithmToFactory.entries()).map(([algorithm, factory]) => [algorithm, factory.constructor.name])),
3170
- typeMappings: Object.fromEntries(Array.from(this.typeToFactories.entries()).map(([encType, factories]) => [
3171
- encType,
3172
- factories.map((factory) => factory.constructor.name),
3173
- ])),
3174
- };
3175
- }
3176
- forceRediscovery() {
3177
- const manualFactories = this.factories.filter((factory) => !this.autoDiscoveredFactories.has(factory));
3178
- this.autoDiscovered = false;
3179
- this.algorithmToFactory.clear();
3180
- this.typeToFactories.clear();
3181
- this.factories.length = 0;
3182
- this.factorySet.clear();
3183
- this.autoDiscoveredFactories.clear();
3184
- for (const factory of manualFactories) {
3185
- this.registerFactory(factory);
3550
+ toPositiveNumber(value) {
3551
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) {
3552
+ return value;
3186
3553
  }
3187
- this.autoDiscoverFactories();
3188
- }
3189
- isAutoDiscovered() {
3190
- return this.autoDiscovered;
3191
- }
3192
- ensureInitialized() {
3193
- this.ensureAutoDiscovery();
3194
- }
3195
- ensureAutoDiscovery() {
3196
- if (!this.autoDiscovered) {
3197
- this.autoDiscoverFactories();
3554
+ if (typeof value === "string" && value.trim() !== "") {
3555
+ const parsed = Number(value);
3556
+ if (Number.isFinite(parsed) && parsed > 0) {
3557
+ return parsed;
3558
+ }
3198
3559
  }
3560
+ return undefined;
3199
3561
  }
3200
3562
  }
3201
- const globalRegistry = new EncryptionManagerFactoryRegistry(true);
3202
- function getEncryptionManagerFactoryRegistry() {
3203
- globalRegistry.ensureInitialized();
3204
- return globalRegistry;
3205
- }
3563
+
3564
+ var defaultSecureChannelManagerFactory = /*#__PURE__*/Object.freeze({
3565
+ __proto__: null,
3566
+ DefaultSecureChannelManagerFactory: DefaultSecureChannelManagerFactory,
3567
+ FACTORY_META: FACTORY_META$b,
3568
+ default: DefaultSecureChannelManagerFactory
3569
+ });
3206
3570
 
3207
3571
  const logger$a = runtime.getLogger("naylence.fame.security.encryption.composite_encryption_manager");
3208
3572
  const DEFAULT_SEALED_ALGORITHMS = [
@@ -5117,1275 +5481,953 @@ class AFTLoadBalancerStickinessManager extends runtime.BaseNodeEventListener {
5117
5481
  }
5118
5482
  const verification = await this.verifier.verify(aftToken, envelope.sid ?? undefined);
5119
5483
  if (!verification.valid) {
5120
- this.metrics.verifyFailures += 1;
5121
- logger$4.warning("aft_verification_failed", {
5122
- envelope_id: envelope.id,
5123
- replica_id: replicaId,
5124
- error: verification.error,
5125
- });
5126
- return null;
5127
- }
5128
- this.storeAssociation(aftToken, {
5129
- replicaId,
5130
- token: aftToken,
5131
- sid: verification.sid ?? "",
5132
- exp: verification.exp ?? Math.floor(Date.now() / 1000) + this.defaultTtlSec,
5133
- trustLevel: verification.trustLevel,
5134
- scope: verification.scope ?? null,
5135
- clientSid: verification.clientSid ?? null,
5136
- });
5137
- if (verification.clientSid) {
5138
- this.sidCache.set(verification.clientSid, replicaId);
5139
- logger$4.debug("sid_cache_updated", {
5140
- envelope_id: envelope.id,
5141
- client_sid: verification.clientSid,
5142
- replica_id: replicaId,
5143
- });
5144
- }
5145
- this.metrics.associationsCreated += 1;
5146
- logger$4.debug("aft_association_created", {
5147
- envelope_id: envelope.id,
5148
- replica_id: replicaId,
5149
- sid: verification.sid,
5150
- exp: verification.exp,
5151
- trust_level: verification.trustLevel,
5152
- scope: verification.scope,
5153
- });
5154
- return this.config.clientEcho ? aftToken : null;
5155
- }
5156
- getStickyReplicaSegment(envelope, segments) {
5157
- if (!this.config.enabled) {
5158
- logger$4.debug("stickiness_disabled", { envelope_id: envelope.id });
5159
- return null;
5160
- }
5161
- if (envelope.aft) {
5162
- const replicaId = this.routeByAft(envelope.aft, envelope);
5163
- if (replicaId) {
5164
- this.metrics.cacheHits += 1;
5165
- logger$4.debug("aft_routed_envelope", {
5166
- envelope_id: envelope.id,
5167
- replica_id: replicaId,
5168
- routing_type: "aft_direct",
5169
- });
5170
- return replicaId;
5171
- }
5172
- }
5173
- if (envelope.sid) {
5174
- const cachedReplica = this.sidCache.get(envelope.sid);
5175
- if (cachedReplica) {
5176
- if (this.config.securityLevel === exports.StickinessMode.SID_ONLY) {
5177
- this.metrics.cacheHits += 1;
5178
- logger$4.debug("sid_cache_routed_envelope", {
5179
- envelope_id: envelope.id,
5180
- replica_id: cachedReplica,
5181
- sid: envelope.sid,
5182
- routing_type: "sid_only",
5183
- });
5184
- return cachedReplica;
5185
- }
5186
- for (const [token, association] of this.aftAssociations.entries()) {
5187
- if (association.replicaId === cachedReplica &&
5188
- !association.isExpired()) {
5189
- envelope.aft = token;
5190
- this.metrics.cacheHits += 1;
5191
- logger$4.debug("sid_cache_routed_envelope", {
5192
- envelope_id: envelope.id,
5193
- replica_id: cachedReplica,
5194
- sid: envelope.sid,
5195
- routing_type: "sid_cache_with_aft",
5196
- });
5197
- return cachedReplica;
5198
- }
5199
- }
5200
- this.metrics.cacheHits += 1;
5201
- logger$4.debug("sid_cache_routed_envelope", {
5202
- envelope_id: envelope.id,
5203
- replica_id: cachedReplica,
5204
- sid: envelope.sid,
5205
- routing_type: "sid_cache_direct",
5206
- });
5207
- return cachedReplica;
5208
- }
5209
- logger$4.debug("no_cached_replica_for_sid", {
5210
- envelope_id: envelope.id,
5211
- sid: envelope.sid,
5212
- });
5213
- }
5214
- if (envelope.sid && Array.isArray(segments) && segments.length > 0) {
5215
- const index = computeDeterministicIndex(envelope.sid, segments.length);
5216
- const chosen = segments[index];
5217
- this.metrics.cacheHits += 1;
5218
- logger$4.debug("sid_based_deterministic_choice", {
5219
- envelope_id: envelope.id,
5220
- sid: envelope.sid,
5221
- chosen,
5222
- routing_type: "sid_deterministic",
5223
- });
5224
- return chosen;
5225
- }
5226
- this.metrics.cacheMisses += 1;
5227
- logger$4.debug("no_stickiness_routing", {
5228
- envelope_id: envelope.id,
5229
- has_aft: Boolean(envelope.aft),
5230
- has_sid: Boolean(envelope.sid),
5231
- });
5232
- return null;
5233
- }
5234
- cleanupExpiredAssociations() {
5235
- const now = Math.floor(Date.now() / 1000);
5236
- const expiredTokens = [];
5237
- for (const [token, association] of this.aftAssociations.entries()) {
5238
- if (association.isExpired(now)) {
5239
- expiredTokens.push(token);
5240
- }
5241
- }
5242
- for (const token of expiredTokens) {
5243
- this.removeAssociation(token);
5244
- }
5245
- if (expiredTokens.length > 0) {
5246
- this.metrics.associationsExpired += expiredTokens.length;
5247
- logger$4.debug("cleaned_expired_associations", {
5248
- count: expiredTokens.length,
5249
- });
5250
- }
5251
- }
5252
- replicaLeft(replicaId) {
5253
- const tokensToRemove = [];
5254
- for (const [token, association] of this.aftAssociations.entries()) {
5255
- if (association.replicaId === replicaId) {
5256
- tokensToRemove.push(token);
5257
- }
5258
- }
5259
- for (const token of tokensToRemove) {
5260
- this.removeAssociation(token);
5261
- }
5262
- if (tokensToRemove.length > 0) {
5263
- logger$4.debug("removed_associations_for_departed_replica", {
5264
- replica_id: replicaId,
5265
- count: tokensToRemove.length,
5266
- });
5267
- }
5268
- }
5269
- handleReplicaLeft(replicaId) {
5270
- this.replicaLeft(replicaId);
5271
- logger$4.debug("stickiness_replica_cleanup", { replica_id: replicaId });
5272
- }
5273
- getMetrics() {
5274
- return {
5275
- ...this.metrics,
5276
- cacheSize: this.aftAssociations.size,
5277
- sidCacheSize: this.sidCache.size,
5278
- };
5279
- }
5280
- getAssociations() {
5281
- const result = {};
5282
- for (const [token, association] of this.aftAssociations.entries()) {
5283
- result[token] = {
5284
- replica_id: association.replicaId,
5285
- sid: association.sid,
5286
- client_sid: association.clientSid,
5287
- exp: association.exp,
5288
- trust_level: association.trustLevel,
5289
- scope: association.scope,
5290
- created_at: association.createdAt,
5291
- expired: association.isExpired(),
5292
- };
5293
- }
5294
- return result;
5295
- }
5296
- getStickinessMetrics() {
5297
- return this.getMetrics();
5298
- }
5299
- logMetrics() {
5300
- const hits = this.metrics.cacheHits;
5301
- const misses = this.metrics.cacheMisses;
5302
- const total = hits + misses;
5303
- const hitRate = total > 0 ? Math.round((hits / total) * 10000) / 100 : 0;
5304
- logger$4.info("stickiness_metrics_report", {
5305
- enabled: this.config.enabled,
5306
- security_level: this.config.securityLevel,
5307
- cache_hits: hits,
5308
- cache_misses: misses,
5309
- verify_failures: this.metrics.verifyFailures,
5310
- associations_created: this.metrics.associationsCreated,
5311
- associations_expired: this.metrics.associationsExpired,
5312
- active_associations: this.aftAssociations.size,
5313
- sid_cache_entries: this.sidCache.size,
5314
- hit_rate: hitRate,
5484
+ this.metrics.verifyFailures += 1;
5485
+ logger$4.warning("aft_verification_failed", {
5486
+ envelope_id: envelope.id,
5487
+ replica_id: replicaId,
5488
+ error: verification.error,
5489
+ });
5490
+ return null;
5491
+ }
5492
+ this.storeAssociation(aftToken, {
5493
+ replicaId,
5494
+ token: aftToken,
5495
+ sid: verification.sid ?? "",
5496
+ exp: verification.exp ?? Math.floor(Date.now() / 1000) + this.defaultTtlSec,
5497
+ trustLevel: verification.trustLevel,
5498
+ scope: verification.scope ?? null,
5499
+ clientSid: verification.clientSid ?? null,
5315
5500
  });
5316
- }
5317
- async onDeliver(_node, envelope, context) {
5318
- logger$4.debug("stickiness_manager_on_deliver", {
5501
+ if (verification.clientSid) {
5502
+ this.sidCache.set(verification.clientSid, replicaId);
5503
+ logger$4.debug("sid_cache_updated", {
5504
+ envelope_id: envelope.id,
5505
+ client_sid: verification.clientSid,
5506
+ replica_id: replicaId,
5507
+ });
5508
+ }
5509
+ this.metrics.associationsCreated += 1;
5510
+ logger$4.debug("aft_association_created", {
5319
5511
  envelope_id: envelope.id,
5320
- origin_type: context?.originType ?? "unknown",
5321
- from_system_id: context?.fromSystemId ?? null,
5512
+ replica_id: replicaId,
5513
+ sid: verification.sid,
5514
+ exp: verification.exp,
5515
+ trust_level: verification.trustLevel,
5516
+ scope: verification.scope,
5322
5517
  });
5323
- if (context?.originType === core.DeliveryOriginType.DOWNSTREAM) {
5324
- const sourceRoute = context.fromSystemId;
5325
- if (sourceRoute) {
5326
- logger$4.debug("processing_downstream_envelope", {
5518
+ return this.config.clientEcho ? aftToken : null;
5519
+ }
5520
+ getStickyReplicaSegment(envelope, segments) {
5521
+ if (!this.config.enabled) {
5522
+ logger$4.debug("stickiness_disabled", { envelope_id: envelope.id });
5523
+ return null;
5524
+ }
5525
+ if (envelope.aft) {
5526
+ const replicaId = this.routeByAft(envelope.aft, envelope);
5527
+ if (replicaId) {
5528
+ this.metrics.cacheHits += 1;
5529
+ logger$4.debug("aft_routed_envelope", {
5327
5530
  envelope_id: envelope.id,
5328
- source_route: sourceRoute,
5531
+ replica_id: replicaId,
5532
+ routing_type: "aft_direct",
5329
5533
  });
5330
- if (this.config.securityLevel === exports.StickinessMode.SID_ONLY &&
5331
- envelope.sid &&
5332
- !this.sidCache.has(envelope.sid)) {
5333
- this.sidCache.set(envelope.sid, sourceRoute);
5334
- logger$4.debug("sid_only_association_recorded", {
5534
+ return replicaId;
5535
+ }
5536
+ }
5537
+ if (envelope.sid) {
5538
+ const cachedReplica = this.sidCache.get(envelope.sid);
5539
+ if (cachedReplica) {
5540
+ if (this.config.securityLevel === exports.StickinessMode.SID_ONLY) {
5541
+ this.metrics.cacheHits += 1;
5542
+ logger$4.debug("sid_cache_routed_envelope", {
5335
5543
  envelope_id: envelope.id,
5544
+ replica_id: cachedReplica,
5336
5545
  sid: envelope.sid,
5337
- replica_id: sourceRoute,
5338
- });
5339
- }
5340
- const hadInstruction = Boolean(extractAftInstruction(envelope));
5341
- const token = await this.handleOutboundEnvelope(envelope, sourceRoute);
5342
- if (hadInstruction) {
5343
- logger$4.debug("processed_aft_setter_instruction", {
5344
- envelope_id: envelope.id,
5345
- source_route: sourceRoute,
5346
- client_echo: Boolean(token),
5546
+ routing_type: "sid_only",
5347
5547
  });
5548
+ return cachedReplica;
5348
5549
  }
5349
- else {
5350
- logger$4.debug("no_aft_setter_instruction", {
5351
- envelope_id: envelope.id,
5352
- source_route: sourceRoute,
5353
- });
5550
+ for (const [token, association] of this.aftAssociations.entries()) {
5551
+ if (association.replicaId === cachedReplica &&
5552
+ !association.isExpired()) {
5553
+ envelope.aft = token;
5554
+ this.metrics.cacheHits += 1;
5555
+ logger$4.debug("sid_cache_routed_envelope", {
5556
+ envelope_id: envelope.id,
5557
+ replica_id: cachedReplica,
5558
+ sid: envelope.sid,
5559
+ routing_type: "sid_cache_with_aft",
5560
+ });
5561
+ return cachedReplica;
5562
+ }
5354
5563
  }
5355
- }
5356
- else {
5357
- logger$4.debug("downstream_envelope_without_source_route", {
5564
+ this.metrics.cacheHits += 1;
5565
+ logger$4.debug("sid_cache_routed_envelope", {
5358
5566
  envelope_id: envelope.id,
5567
+ replica_id: cachedReplica,
5568
+ sid: envelope.sid,
5569
+ routing_type: "sid_cache_direct",
5359
5570
  });
5571
+ return cachedReplica;
5360
5572
  }
5361
- }
5362
- else {
5363
- logger$4.debug("envelope_not_from_downstream", {
5573
+ logger$4.debug("no_cached_replica_for_sid", {
5364
5574
  envelope_id: envelope.id,
5575
+ sid: envelope.sid,
5365
5576
  });
5366
5577
  }
5367
- return envelope;
5368
- }
5369
- storeAssociation(token, data) {
5370
- if (this.aftAssociations.has(token)) {
5371
- this.aftAssociations.delete(token);
5372
- }
5373
- const association = new AFTAssociation(data);
5374
- this.aftAssociations.set(token, association);
5375
- while (this.aftAssociations.size > this.cacheMax) {
5376
- const oldest = this.aftAssociations.keys().next();
5377
- if (oldest.done) {
5378
- break;
5379
- }
5380
- const oldestToken = oldest.value;
5381
- this.removeAssociation(oldestToken);
5382
- }
5383
- }
5384
- removeAssociation(token) {
5385
- this.aftAssociations.delete(token);
5386
- for (const [sid, cachedToken] of this.sidCache.entries()) {
5387
- if (cachedToken === token) {
5388
- this.sidCache.delete(sid);
5389
- }
5390
- }
5391
- }
5392
- routeByAft(token, envelope) {
5393
- const association = this.aftAssociations.get(token);
5394
- if (!association) {
5395
- return null;
5396
- }
5397
- if (association.isExpired()) {
5398
- this.metrics.associationsExpired += 1;
5399
- this.removeAssociation(token);
5400
- return null;
5401
- }
5402
- if (this.verifier.securityLevel === exports.StickinessMode.STRICT &&
5403
- association.isLowTrust()) {
5404
- logger$4.warning("rejecting_low_trust_association", {
5578
+ if (envelope.sid && Array.isArray(segments) && segments.length > 0) {
5579
+ const index = computeDeterministicIndex(envelope.sid, segments.length);
5580
+ const chosen = segments[index];
5581
+ this.metrics.cacheHits += 1;
5582
+ logger$4.debug("sid_based_deterministic_choice", {
5405
5583
  envelope_id: envelope.id,
5406
- replica_id: association.replicaId,
5407
- reason: "strict mode rejects low-trust associations",
5584
+ sid: envelope.sid,
5585
+ chosen,
5586
+ routing_type: "sid_deterministic",
5408
5587
  });
5409
- return null;
5588
+ return chosen;
5410
5589
  }
5411
- this.aftAssociations.delete(token);
5412
- this.aftAssociations.set(token, association);
5413
- return association.replicaId;
5414
- }
5415
- }
5416
- function extractAftInstruction(envelope) {
5417
- if (!envelope.meta) {
5590
+ this.metrics.cacheMisses += 1;
5591
+ logger$4.debug("no_stickiness_routing", {
5592
+ envelope_id: envelope.id,
5593
+ has_aft: Boolean(envelope.aft),
5594
+ has_sid: Boolean(envelope.sid),
5595
+ });
5418
5596
  return null;
5419
5597
  }
5420
- const meta = envelope.meta;
5421
- const nested = meta.set;
5422
- if (nested && typeof nested === "object" && !Array.isArray(nested)) {
5423
- const aftValue = nested.aft;
5424
- if (aftValue !== undefined) {
5425
- return aftValue;
5426
- }
5427
- }
5428
- if (meta["set.aft"] !== undefined) {
5429
- return meta["set.aft"];
5430
- }
5431
- return null;
5432
- }
5433
- function computeDeterministicIndex(key, modulo) {
5434
- if (modulo <= 0) {
5435
- return 0;
5436
- }
5437
- let hash = 0;
5438
- for (let i = 0; i < key.length; i += 1) {
5439
- hash = (hash * 31 + key.charCodeAt(i)) >>> 0;
5440
- }
5441
- return hash % modulo;
5442
- }
5443
-
5444
- const FACTORY_META$6 = {
5445
- base: runtime.LOAD_BALANCER_STICKINESS_MANAGER_FACTORY_BASE_TYPE,
5446
- key: "AFTLoadBalancerStickinessManager",
5447
- };
5448
- const DEFAULT_VALUES$1 = {
5449
- enabled: true,
5450
- clientEcho: false,
5451
- defaultTtlSec: 30,
5452
- cacheMax: 100000,
5453
- securityLevel: exports.StickinessMode.SIGNED_OPTIONAL,
5454
- maxTtlSec: 7200,
5455
- };
5456
- function toBoolean(value, fallback) {
5457
- return typeof value === "boolean" ? value : fallback;
5458
- }
5459
- function toNumber(value, fallback) {
5460
- if (typeof value === "number" && Number.isFinite(value)) {
5461
- return value;
5462
- }
5463
- return fallback;
5464
- }
5465
- function normalizeConfig$4(config) {
5466
- const record = (config ?? {});
5467
- const normalizedSecurity = record.securityLevel
5468
- ? normalizeStickinessMode(record.securityLevel)
5469
- : DEFAULT_VALUES$1.securityLevel;
5470
- return {
5471
- ...record,
5472
- type: "AFTLoadBalancerStickinessManager",
5473
- enabled: toBoolean(record.enabled, DEFAULT_VALUES$1.enabled),
5474
- clientEcho: toBoolean(record.clientEcho, DEFAULT_VALUES$1.clientEcho),
5475
- defaultTtlSec: toNumber(record.defaultTtlSec, DEFAULT_VALUES$1.defaultTtlSec),
5476
- cacheMax: toNumber(record.cacheMax, DEFAULT_VALUES$1.cacheMax),
5477
- securityLevel: normalizedSecurity,
5478
- maxTtlSec: toNumber(record.maxTtlSec, DEFAULT_VALUES$1.maxTtlSec),
5479
- };
5480
- }
5481
- class AFTLoadBalancerStickinessManagerFactory extends runtime.LoadBalancerStickinessManagerFactory {
5482
- constructor() {
5483
- super(...arguments);
5484
- this.type = "AFTLoadBalancerStickinessManager";
5485
- this.isDefault = false;
5486
- }
5487
- async create(config, keyProvider, verifier) {
5488
- const resolvedConfig = normalizeConfig$4(config);
5489
- let effectiveVerifier = verifier ?? null;
5490
- if (!effectiveVerifier && keyProvider) {
5491
- effectiveVerifier = createAftVerifier({
5492
- securityLevel: resolvedConfig.securityLevel ?? DEFAULT_VALUES$1.securityLevel,
5493
- keyProvider,
5494
- defaultTtlSec: resolvedConfig.defaultTtlSec ?? DEFAULT_VALUES$1.defaultTtlSec,
5598
+ cleanupExpiredAssociations() {
5599
+ const now = Math.floor(Date.now() / 1000);
5600
+ const expiredTokens = [];
5601
+ for (const [token, association] of this.aftAssociations.entries()) {
5602
+ if (association.isExpired(now)) {
5603
+ expiredTokens.push(token);
5604
+ }
5605
+ }
5606
+ for (const token of expiredTokens) {
5607
+ this.removeAssociation(token);
5608
+ }
5609
+ if (expiredTokens.length > 0) {
5610
+ this.metrics.associationsExpired += expiredTokens.length;
5611
+ logger$4.debug("cleaned_expired_associations", {
5612
+ count: expiredTokens.length,
5495
5613
  });
5496
5614
  }
5497
- if (!effectiveVerifier) {
5498
- throw new Error("AFTLoadBalancerStickinessManagerFactory requires an AFT verifier or key provider");
5615
+ }
5616
+ replicaLeft(replicaId) {
5617
+ const tokensToRemove = [];
5618
+ for (const [token, association] of this.aftAssociations.entries()) {
5619
+ if (association.replicaId === replicaId) {
5620
+ tokensToRemove.push(token);
5621
+ }
5622
+ }
5623
+ for (const token of tokensToRemove) {
5624
+ this.removeAssociation(token);
5625
+ }
5626
+ if (tokensToRemove.length > 0) {
5627
+ logger$4.debug("removed_associations_for_departed_replica", {
5628
+ replica_id: replicaId,
5629
+ count: tokensToRemove.length,
5630
+ });
5499
5631
  }
5500
- return new AFTLoadBalancerStickinessManager(resolvedConfig, effectiveVerifier);
5501
5632
  }
5502
- }
5503
-
5504
- var aftLoadBalancerStickinessManagerFactory = /*#__PURE__*/Object.freeze({
5505
- __proto__: null,
5506
- AFTLoadBalancerStickinessManagerFactory: AFTLoadBalancerStickinessManagerFactory,
5507
- FACTORY_META: FACTORY_META$6,
5508
- default: AFTLoadBalancerStickinessManagerFactory
5509
- });
5510
-
5511
- const logger$3 = runtime.getLogger("naylence.fame.stickiness.aft_replica_stickiness_manager");
5512
- function isStickinessRequired(context) {
5513
- if (typeof context.stickinessRequired === "boolean") {
5514
- return context.stickinessRequired;
5633
+ handleReplicaLeft(replicaId) {
5634
+ this.replicaLeft(replicaId);
5635
+ logger$4.debug("stickiness_replica_cleanup", { replica_id: replicaId });
5515
5636
  }
5516
- if (typeof context.stickiness_required === "boolean") {
5517
- return context.stickiness_required;
5637
+ getMetrics() {
5638
+ return {
5639
+ ...this.metrics,
5640
+ cacheSize: this.aftAssociations.size,
5641
+ sidCacheSize: this.sidCache.size,
5642
+ };
5518
5643
  }
5519
- return false;
5520
- }
5521
- class AFTReplicaStickinessManager extends runtime.BaseNodeEventListener {
5522
- constructor(options = {}) {
5523
- super();
5524
- this.securityLevel =
5525
- normalizeStickinessMode(options.securityLevel ?? DEFAULT_STICKINESS_SECURITY_LEVEL) ?? DEFAULT_STICKINESS_SECURITY_LEVEL;
5526
- this.aftHelper = options.aftHelper ?? null;
5527
- this.maxTtlSec = options.maxTtlSec ?? 7200;
5528
- this.isInitialized = this.aftHelper !== null;
5529
- this.negotiatedStickiness = null;
5530
- if (this.aftHelper) {
5531
- logger$3.debug("aft_replica_stickiness_manager_initialized", {
5532
- helper_type: this.aftHelper.signer.constructor.name,
5533
- security_level: this.aftHelper.signer.securityLevel,
5534
- max_ttl_sec: this.aftHelper.maxTtlSec,
5535
- });
5536
- }
5537
- else {
5538
- logger$3.debug("aft_replica_stickiness_manager_created", {
5539
- security_level: this.securityLevel,
5540
- max_ttl_sec: this.maxTtlSec,
5541
- });
5644
+ getAssociations() {
5645
+ const result = {};
5646
+ for (const [token, association] of this.aftAssociations.entries()) {
5647
+ result[token] = {
5648
+ replica_id: association.replicaId,
5649
+ sid: association.sid,
5650
+ client_sid: association.clientSid,
5651
+ exp: association.exp,
5652
+ trust_level: association.trustLevel,
5653
+ scope: association.scope,
5654
+ created_at: association.createdAt,
5655
+ expired: association.isExpired(),
5656
+ };
5542
5657
  }
5658
+ return result;
5543
5659
  }
5544
- offer() {
5545
- return { mode: "aft", supportedModes: ["aft", "attr"], version: 1 };
5660
+ getStickinessMetrics() {
5661
+ return this.getMetrics();
5546
5662
  }
5547
- accept(stickiness) {
5548
- this.negotiatedStickiness = stickiness ?? null;
5549
- logger$3.debug("replica_stickiness_policy_set", {
5550
- enabled: stickiness?.enabled ?? null,
5551
- mode: stickiness?.mode ?? null,
5552
- ttl: stickiness?.ttlSec ?? null,
5663
+ logMetrics() {
5664
+ const hits = this.metrics.cacheHits;
5665
+ const misses = this.metrics.cacheMisses;
5666
+ const total = hits + misses;
5667
+ const hitRate = total > 0 ? Math.round((hits / total) * 10000) / 100 : 0;
5668
+ logger$4.info("stickiness_metrics_report", {
5669
+ enabled: this.config.enabled,
5670
+ security_level: this.config.securityLevel,
5671
+ cache_hits: hits,
5672
+ cache_misses: misses,
5673
+ verify_failures: this.metrics.verifyFailures,
5674
+ associations_created: this.metrics.associationsCreated,
5675
+ associations_expired: this.metrics.associationsExpired,
5676
+ active_associations: this.aftAssociations.size,
5677
+ sid_cache_entries: this.sidCache.size,
5678
+ hit_rate: hitRate,
5553
5679
  });
5554
5680
  }
5555
- async onForwardUpstream(_node, envelope, context) {
5556
- if (!context) {
5557
- return envelope;
5558
- }
5559
- const helper = this.aftHelper;
5560
- if (!helper) {
5561
- logger$3.debug("aft_helper_not_ready_skip_injection", {
5562
- envelope_id: envelope.id,
5563
- delivery_origin: context.originType ?? null,
5564
- reason: "not_initialized",
5565
- });
5566
- return envelope;
5567
- }
5568
- const stickinessContext = context;
5569
- if (isStickinessRequired(stickinessContext) &&
5570
- context.originType === core.DeliveryOriginType.LOCAL) {
5571
- if (this.negotiatedStickiness) {
5572
- const negotiated = this.negotiatedStickiness;
5573
- if (negotiated.enabled === false ||
5574
- (negotiated.mode !== null &&
5575
- negotiated.mode !== undefined &&
5576
- negotiated.mode !== "aft")) {
5577
- logger$3.debug("aft_injection_skipped_due_to_policy", {
5681
+ async onDeliver(_node, envelope, context) {
5682
+ logger$4.debug("stickiness_manager_on_deliver", {
5683
+ envelope_id: envelope.id,
5684
+ origin_type: context?.originType ?? "unknown",
5685
+ from_system_id: context?.fromSystemId ?? null,
5686
+ });
5687
+ if (context?.originType === core.DeliveryOriginType.DOWNSTREAM) {
5688
+ const sourceRoute = context.fromSystemId;
5689
+ if (sourceRoute) {
5690
+ logger$4.debug("processing_downstream_envelope", {
5691
+ envelope_id: envelope.id,
5692
+ source_route: sourceRoute,
5693
+ });
5694
+ if (this.config.securityLevel === exports.StickinessMode.SID_ONLY &&
5695
+ envelope.sid &&
5696
+ !this.sidCache.has(envelope.sid)) {
5697
+ this.sidCache.set(envelope.sid, sourceRoute);
5698
+ logger$4.debug("sid_only_association_recorded", {
5578
5699
  envelope_id: envelope.id,
5579
- policy_mode: negotiated.mode ?? null,
5580
- policy_enabled: negotiated.enabled ?? null,
5700
+ sid: envelope.sid,
5701
+ replica_id: sourceRoute,
5702
+ });
5703
+ }
5704
+ const hadInstruction = Boolean(extractAftInstruction(envelope));
5705
+ const token = await this.handleOutboundEnvelope(envelope, sourceRoute);
5706
+ if (hadInstruction) {
5707
+ logger$4.debug("processed_aft_setter_instruction", {
5708
+ envelope_id: envelope.id,
5709
+ source_route: sourceRoute,
5710
+ client_echo: Boolean(token),
5711
+ });
5712
+ }
5713
+ else {
5714
+ logger$4.debug("no_aft_setter_instruction", {
5715
+ envelope_id: envelope.id,
5716
+ source_route: sourceRoute,
5581
5717
  });
5582
- return envelope;
5583
5718
  }
5584
- }
5585
- logger$3.debug("applying_aft_for_upstream_stickiness_required", {
5586
- envelope_id: envelope.id,
5587
- from_system_id: context.fromSystemId ?? null,
5588
- delivery_origin: context.originType ?? null,
5589
- });
5590
- const success = await helper.requestStickiness(envelope, {
5591
- ttlSec: null,
5592
- scope: "node",
5593
- context: stickinessContext,
5594
- });
5595
- if (success) {
5596
- logger$3.debug("aft_token_applied_via_context_flag_upstream", {
5597
- envelope_id: envelope.id,
5598
- from_system_id: context.fromSystemId ?? null,
5599
- delivery_origin: context.originType ?? null,
5600
- });
5601
5719
  }
5602
5720
  else {
5603
- logger$3.debug("aft_token_not_applied_upstream", {
5721
+ logger$4.debug("downstream_envelope_without_source_route", {
5604
5722
  envelope_id: envelope.id,
5605
- delivery_origin: context.originType ?? null,
5606
- reason: "helper_returned_false",
5607
5723
  });
5608
5724
  }
5609
5725
  }
5610
- return envelope;
5611
- }
5612
- async onNodeStarted(node) {
5613
- if (!this.isInitialized) {
5614
- await this.initializeAftHelper(node);
5615
- return;
5616
- }
5617
- if (this.aftHelper && node.sid) {
5618
- this.updateNodeSid(node.sid);
5619
- logger$3.debug("aft_replica_stickiness_manager_sid_updated", {
5620
- node_id: node.id ?? "unknown",
5621
- node_sid: node.sid,
5622
- security_level: this.aftHelper.signer.securityLevel,
5623
- });
5624
- }
5625
- else if (!node.sid) {
5626
- logger$3.warning("aft_replica_stickiness_manager_no_sid_available", {
5627
- node_id: node.id ?? "unknown",
5628
- });
5629
- }
5630
5726
  else {
5631
- logger$3.error("aft_replica_stickiness_manager_node_missing_sid", {
5632
- node_type: node.constructor?.name ?? typeof node,
5727
+ logger$4.debug("envelope_not_from_downstream", {
5728
+ envelope_id: envelope.id,
5633
5729
  });
5634
5730
  }
5731
+ return envelope;
5635
5732
  }
5636
- updateNodeSid(nodeSid) {
5637
- if (this.aftHelper) {
5638
- this.aftHelper.nodeSid = nodeSid;
5639
- logger$3.debug("aft_replica_stickiness_manager_sid_updated", {
5640
- new_sid: nodeSid,
5641
- });
5733
+ storeAssociation(token, data) {
5734
+ if (this.aftAssociations.has(token)) {
5735
+ this.aftAssociations.delete(token);
5642
5736
  }
5643
- }
5644
- async initializeAftHelper(node) {
5645
- const nodeSid = node.sid;
5646
- if (!nodeSid) {
5647
- logger$3.error("aft_replica_stickiness_manager_cannot_initialize_no_sid", {
5648
- node_id: node.id ?? "unknown",
5649
- });
5650
- return;
5737
+ const association = new AFTAssociation(data);
5738
+ this.aftAssociations.set(token, association);
5739
+ while (this.aftAssociations.size > this.cacheMax) {
5740
+ const oldest = this.aftAssociations.keys().next();
5741
+ if (oldest.done) {
5742
+ break;
5743
+ }
5744
+ const oldestToken = oldest.value;
5745
+ this.removeAssociation(oldestToken);
5651
5746
  }
5652
- const cryptoProvider = node.cryptoProvider ?? null;
5653
- if (!cryptoProvider) {
5654
- logger$3.error("aft_replica_stickiness_manager_cannot_initialize_no_crypto_provider", {
5655
- node_id: node.id ?? "unknown",
5656
- });
5657
- return;
5747
+ }
5748
+ removeAssociation(token) {
5749
+ this.aftAssociations.delete(token);
5750
+ for (const [sid, cachedToken] of this.sidCache.entries()) {
5751
+ if (cachedToken === token) {
5752
+ this.sidCache.delete(sid);
5753
+ }
5658
5754
  }
5659
- const keyId = typeof cryptoProvider.signatureKeyId === "string" &&
5660
- cryptoProvider.signatureKeyId.length > 0
5661
- ? cryptoProvider.signatureKeyId
5662
- : "default-key-id";
5663
- const privateKeyPem = typeof cryptoProvider.signingPrivatePem === "string"
5664
- ? cryptoProvider.signingPrivatePem
5665
- : null;
5666
- if (this.securityLevel === exports.StickinessMode.STRICT && !privateKeyPem) {
5667
- logger$3.error("aft_replica_stickiness_manager_initialization_failed", {
5668
- node_id: node.id ?? "unknown",
5669
- error: "Missing signing private key for strict security level",
5670
- });
5671
- return;
5755
+ }
5756
+ routeByAft(token, envelope) {
5757
+ const association = this.aftAssociations.get(token);
5758
+ if (!association) {
5759
+ return null;
5672
5760
  }
5673
- try {
5674
- const helper = createAftHelper({
5675
- securityLevel: this.securityLevel,
5676
- nodeSid,
5677
- kid: keyId,
5678
- privateKeyPem,
5679
- maxTtlSec: this.maxTtlSec,
5680
- });
5681
- this.aftHelper = helper;
5682
- this.isInitialized = true;
5683
- logger$3.debug("aft_replica_stickiness_manager_initialized", {
5684
- node_id: node.id ?? "unknown",
5685
- node_sid: nodeSid,
5686
- key_id: keyId,
5687
- security_level: helper.signer.securityLevel,
5688
- });
5761
+ if (association.isExpired()) {
5762
+ this.metrics.associationsExpired += 1;
5763
+ this.removeAssociation(token);
5764
+ return null;
5689
5765
  }
5690
- catch (error) {
5691
- logger$3.error("aft_replica_stickiness_manager_initialization_failed", {
5692
- node_id: node.id ?? "unknown",
5693
- error: error instanceof Error ? error.message : String(error),
5766
+ if (this.verifier.securityLevel === exports.StickinessMode.STRICT &&
5767
+ association.isLowTrust()) {
5768
+ logger$4.warning("rejecting_low_trust_association", {
5769
+ envelope_id: envelope.id,
5770
+ replica_id: association.replicaId,
5771
+ reason: "strict mode rejects low-trust associations",
5694
5772
  });
5773
+ return null;
5695
5774
  }
5775
+ this.aftAssociations.delete(token);
5776
+ this.aftAssociations.set(token, association);
5777
+ return association.replicaId;
5696
5778
  }
5697
- get signer() {
5698
- return this.aftHelper?.signer ?? null;
5779
+ }
5780
+ function extractAftInstruction(envelope) {
5781
+ if (!envelope.meta) {
5782
+ return null;
5699
5783
  }
5700
- getHelper() {
5701
- return this.aftHelper;
5784
+ const meta = envelope.meta;
5785
+ const nested = meta.set;
5786
+ if (nested && typeof nested === "object" && !Array.isArray(nested)) {
5787
+ const aftValue = nested.aft;
5788
+ if (aftValue !== undefined) {
5789
+ return aftValue;
5790
+ }
5791
+ }
5792
+ if (meta["set.aft"] !== undefined) {
5793
+ return meta["set.aft"];
5702
5794
  }
5795
+ return null;
5703
5796
  }
5704
- function createAftReplicaStickinessManager(aftHelper) {
5705
- return new AFTReplicaStickinessManager({ aftHelper });
5797
+ function computeDeterministicIndex(key, modulo) {
5798
+ if (modulo <= 0) {
5799
+ return 0;
5800
+ }
5801
+ let hash = 0;
5802
+ for (let i = 0; i < key.length; i += 1) {
5803
+ hash = (hash * 31 + key.charCodeAt(i)) >>> 0;
5804
+ }
5805
+ return hash % modulo;
5706
5806
  }
5707
5807
 
5708
- const FACTORY_META$5 = {
5709
- base: runtime.REPLICA_STICKINESS_MANAGER_FACTORY_BASE_TYPE,
5710
- key: "AFTReplicaStickinessManager",
5808
+ const FACTORY_META$6 = {
5809
+ base: runtime.LOAD_BALANCER_STICKINESS_MANAGER_FACTORY_BASE_TYPE,
5810
+ key: "AFTLoadBalancerStickinessManager",
5711
5811
  };
5712
- const DEFAULT_VALUES = {
5812
+ const DEFAULT_VALUES$1 = {
5813
+ enabled: true,
5814
+ clientEcho: false,
5815
+ defaultTtlSec: 30,
5816
+ cacheMax: 100000,
5713
5817
  securityLevel: exports.StickinessMode.SIGNED_OPTIONAL,
5714
5818
  maxTtlSec: 7200,
5715
5819
  };
5716
- function normalizeConfig$3(config) {
5820
+ function toBoolean(value, fallback) {
5821
+ return typeof value === "boolean" ? value : fallback;
5822
+ }
5823
+ function toNumber(value, fallback) {
5824
+ if (typeof value === "number" && Number.isFinite(value)) {
5825
+ return value;
5826
+ }
5827
+ return fallback;
5828
+ }
5829
+ function normalizeConfig$4(config) {
5717
5830
  const record = (config ?? {});
5718
5831
  const normalizedSecurity = record.securityLevel
5719
5832
  ? normalizeStickinessMode(record.securityLevel)
5720
- : DEFAULT_VALUES.securityLevel;
5721
- const securityLevel = normalizedSecurity ?? DEFAULT_VALUES.securityLevel;
5722
- const maxTtlSecValue = typeof record.maxTtlSec === "number" && Number.isFinite(record.maxTtlSec)
5723
- ? Math.max(0, Math.floor(record.maxTtlSec))
5724
- : DEFAULT_VALUES.maxTtlSec;
5833
+ : DEFAULT_VALUES$1.securityLevel;
5725
5834
  return {
5726
5835
  ...record,
5727
- type: "AFTReplicaStickinessManager",
5728
- securityLevel,
5729
- maxTtlSec: maxTtlSecValue,
5836
+ type: "AFTLoadBalancerStickinessManager",
5837
+ enabled: toBoolean(record.enabled, DEFAULT_VALUES$1.enabled),
5838
+ clientEcho: toBoolean(record.clientEcho, DEFAULT_VALUES$1.clientEcho),
5839
+ defaultTtlSec: toNumber(record.defaultTtlSec, DEFAULT_VALUES$1.defaultTtlSec),
5840
+ cacheMax: toNumber(record.cacheMax, DEFAULT_VALUES$1.cacheMax),
5841
+ securityLevel: normalizedSecurity,
5842
+ maxTtlSec: toNumber(record.maxTtlSec, DEFAULT_VALUES$1.maxTtlSec),
5730
5843
  };
5731
5844
  }
5732
- class AFTReplicaStickinessManagerFactory extends runtime.ReplicaStickinessManagerFactory {
5845
+ class AFTLoadBalancerStickinessManagerFactory extends runtime.LoadBalancerStickinessManagerFactory {
5733
5846
  constructor() {
5734
5847
  super(...arguments);
5735
- this.type = FACTORY_META$5.key;
5736
- this.isDefault = true;
5848
+ this.type = "AFTLoadBalancerStickinessManager";
5849
+ this.isDefault = false;
5737
5850
  }
5738
- async create(config, dependencies) {
5739
- const resolvedConfig = normalizeConfig$3(config);
5740
- const helper = dependencies?.aftHelper ?? null;
5741
- const securityLevel = normalizeStickinessMode(resolvedConfig.securityLevel ?? DEFAULT_VALUES.securityLevel) ?? DEFAULT_VALUES.securityLevel;
5742
- const maxTtlSec = typeof resolvedConfig.maxTtlSec === "number" &&
5743
- Number.isFinite(resolvedConfig.maxTtlSec)
5744
- ? Math.max(0, Math.floor(resolvedConfig.maxTtlSec))
5745
- : DEFAULT_VALUES.maxTtlSec;
5746
- return new AFTReplicaStickinessManager({
5747
- securityLevel,
5748
- maxTtlSec,
5749
- aftHelper: helper,
5750
- });
5851
+ async create(config, keyProvider, verifier) {
5852
+ const resolvedConfig = normalizeConfig$4(config);
5853
+ let effectiveVerifier = verifier ?? null;
5854
+ if (!effectiveVerifier && keyProvider) {
5855
+ effectiveVerifier = createAftVerifier({
5856
+ securityLevel: resolvedConfig.securityLevel ?? DEFAULT_VALUES$1.securityLevel,
5857
+ keyProvider,
5858
+ defaultTtlSec: resolvedConfig.defaultTtlSec ?? DEFAULT_VALUES$1.defaultTtlSec,
5859
+ });
5860
+ }
5861
+ if (!effectiveVerifier) {
5862
+ throw new Error("AFTLoadBalancerStickinessManagerFactory requires an AFT verifier or key provider");
5863
+ }
5864
+ return new AFTLoadBalancerStickinessManager(resolvedConfig, effectiveVerifier);
5751
5865
  }
5752
5866
  }
5753
5867
 
5754
- var aftReplicaStickinessManagerFactory = /*#__PURE__*/Object.freeze({
5868
+ var aftLoadBalancerStickinessManagerFactory = /*#__PURE__*/Object.freeze({
5755
5869
  __proto__: null,
5756
- AFTReplicaStickinessManagerFactory: AFTReplicaStickinessManagerFactory,
5757
- FACTORY_META: FACTORY_META$5,
5758
- default: AFTReplicaStickinessManagerFactory
5870
+ AFTLoadBalancerStickinessManagerFactory: AFTLoadBalancerStickinessManagerFactory,
5871
+ FACTORY_META: FACTORY_META$6,
5872
+ default: AFTLoadBalancerStickinessManagerFactory
5759
5873
  });
5760
5874
 
5761
- const logger$2 = runtime.getLogger("naylence.fame.welcome.advanced_welcome_service");
5762
- const ENV_VAR_SHOW_ENVELOPES = "FAME_SHOW_ENVELOPES";
5763
- const DEFAULT_TTL_SEC = 3600;
5764
- const showEnvelopes = typeof process !== "undefined" &&
5765
- process.env?.[ENV_VAR_SHOW_ENVELOPES] === "true";
5766
- function nowUtc() {
5767
- return new Date();
5768
- }
5769
- function formatTimestampForConsole() {
5770
- return runtime.color(runtime.formatTimestamp(), runtime.AnsiColor.GRAY);
5771
- }
5772
- function prettyModel(value) {
5773
- try {
5774
- return runtime.jsonDumps(value);
5775
- }
5776
- catch (error) {
5777
- return String(error);
5778
- }
5779
- }
5780
- function coercePlacementMetadataValue(metadata, camelCaseKey, snakeCaseKey) {
5781
- if (!metadata) {
5782
- return undefined;
5783
- }
5784
- const record = metadata;
5785
- if (record[camelCaseKey] !== undefined) {
5786
- return record[camelCaseKey];
5875
+ const logger$3 = runtime.getLogger("naylence.fame.stickiness.aft_replica_stickiness_manager");
5876
+ function isStickinessRequired(context) {
5877
+ if (typeof context.stickinessRequired === "boolean") {
5878
+ return context.stickinessRequired;
5787
5879
  }
5788
- if (record[snakeCaseKey] !== undefined) {
5789
- return record[snakeCaseKey];
5880
+ if (typeof context.stickiness_required === "boolean") {
5881
+ return context.stickiness_required;
5790
5882
  }
5791
- return undefined;
5883
+ return false;
5792
5884
  }
5793
- class AdvancedWelcomeService {
5794
- constructor(options) {
5795
- this.placementStrategy = options.placementStrategy;
5796
- this.transportProvisioner = options.transportProvisioner;
5797
- this.tokenIssuer = options.tokenIssuer;
5798
- this.authorizer = options.authorizer ?? null;
5799
- this.caServiceUrl = options.caServiceUrl;
5800
- this.ttlSec =
5801
- typeof options.ttlSec === "number" && Number.isFinite(options.ttlSec)
5802
- ? Math.max(0, options.ttlSec)
5803
- : DEFAULT_TTL_SEC;
5804
- logger$2.debug("initialized_advanced_welcome_service", {
5805
- ca_service_url: this.caServiceUrl,
5806
- ttl_sec: this.ttlSec,
5807
- });
5808
- }
5809
- async handleHello(hello, metadata) {
5810
- const fullMetadata = metadata
5811
- ? { ...metadata }
5812
- : {};
5813
- const trimmedSystemId = typeof hello.systemId === "string" ? hello.systemId.trim() : "";
5814
- const systemId = trimmedSystemId.length > 0 ? trimmedSystemId : core.generateId();
5815
- const wasAssigned = trimmedSystemId.length === 0;
5816
- const normalizedHello = {
5817
- ...hello,
5818
- systemId,
5819
- };
5820
- if (showEnvelopes) {
5821
- // eslint-disable-next-line no-console
5822
- console.log(`\n${formatTimestampForConsole()} - ${runtime.color("Received envelope 📨", runtime.AnsiColor.BLUE)}\n${prettyModel(normalizedHello)}`);
5885
+ class AFTReplicaStickinessManager extends runtime.BaseNodeEventListener {
5886
+ constructor(options = {}) {
5887
+ super();
5888
+ this.securityLevel =
5889
+ normalizeStickinessMode(options.securityLevel ?? DEFAULT_STICKINESS_SECURITY_LEVEL) ?? DEFAULT_STICKINESS_SECURITY_LEVEL;
5890
+ this.aftHelper = options.aftHelper ?? null;
5891
+ this.maxTtlSec = options.maxTtlSec ?? 7200;
5892
+ this.isInitialized = this.aftHelper !== null;
5893
+ this.negotiatedStickiness = null;
5894
+ if (this.aftHelper) {
5895
+ logger$3.debug("aft_replica_stickiness_manager_initialized", {
5896
+ helper_type: this.aftHelper.signer.constructor.name,
5897
+ security_level: this.aftHelper.signer.securityLevel,
5898
+ max_ttl_sec: this.aftHelper.maxTtlSec,
5899
+ });
5900
+ }
5901
+ else {
5902
+ logger$3.debug("aft_replica_stickiness_manager_created", {
5903
+ security_level: this.securityLevel,
5904
+ max_ttl_sec: this.maxTtlSec,
5905
+ });
5823
5906
  }
5824
- logger$2.debug("starting_hello_frame_processing", {
5825
- instanceId: normalizedHello.instanceId,
5826
- systemId,
5827
- logicals: normalizedHello.logicals,
5828
- capabilities: normalizedHello.capabilities,
5829
- ttlSec: this.ttlSec,
5907
+ }
5908
+ offer() {
5909
+ return { mode: "aft", supportedModes: ["aft", "attr"], version: 1 };
5910
+ }
5911
+ accept(stickiness) {
5912
+ this.negotiatedStickiness = stickiness ?? null;
5913
+ logger$3.debug("replica_stickiness_policy_set", {
5914
+ enabled: stickiness?.enabled ?? null,
5915
+ mode: stickiness?.mode ?? null,
5916
+ ttl: stickiness?.ttlSec ?? null,
5830
5917
  });
5831
- const now = nowUtc();
5832
- const expiry = new Date(now.getTime() + this.ttlSec * 1000);
5833
- if (normalizedHello.instanceId) {
5834
- if (fullMetadata.instanceId === undefined) {
5835
- fullMetadata.instanceId = normalizedHello.instanceId;
5836
- }
5837
- if (fullMetadata.instance_id === undefined) {
5838
- fullMetadata.instance_id = normalizedHello.instanceId;
5839
- }
5918
+ }
5919
+ async onForwardUpstream(_node, envelope, context) {
5920
+ if (!context) {
5921
+ return envelope;
5840
5922
  }
5841
- logger$2.debug("system_id_assignment_completed", {
5842
- systemId,
5843
- wasAssigned,
5844
- });
5845
- if (normalizedHello.logicals?.length) {
5846
- logger$2.debug("validating_logicals_for_dns_compatibility", {
5847
- logicals: normalizedHello.logicals,
5923
+ const helper = this.aftHelper;
5924
+ if (!helper) {
5925
+ logger$3.debug("aft_helper_not_ready_skip_injection", {
5926
+ envelope_id: envelope.id,
5927
+ delivery_origin: context.originType ?? null,
5928
+ reason: "not_initialized",
5848
5929
  });
5849
- const [pathsValid, pathError] = runtime.validateHostLogicals(normalizedHello.logicals);
5850
- if (!pathsValid) {
5851
- logger$2.error("logical_validation_failed", {
5852
- error: pathError,
5853
- logicals: normalizedHello.logicals,
5930
+ return envelope;
5931
+ }
5932
+ const stickinessContext = context;
5933
+ if (isStickinessRequired(stickinessContext) &&
5934
+ context.originType === core.DeliveryOriginType.LOCAL) {
5935
+ if (this.negotiatedStickiness) {
5936
+ const negotiated = this.negotiatedStickiness;
5937
+ if (negotiated.enabled === false ||
5938
+ (negotiated.mode !== null &&
5939
+ negotiated.mode !== undefined &&
5940
+ negotiated.mode !== "aft")) {
5941
+ logger$3.debug("aft_injection_skipped_due_to_policy", {
5942
+ envelope_id: envelope.id,
5943
+ policy_mode: negotiated.mode ?? null,
5944
+ policy_enabled: negotiated.enabled ?? null,
5945
+ });
5946
+ return envelope;
5947
+ }
5948
+ }
5949
+ logger$3.debug("applying_aft_for_upstream_stickiness_required", {
5950
+ envelope_id: envelope.id,
5951
+ from_system_id: context.fromSystemId ?? null,
5952
+ delivery_origin: context.originType ?? null,
5953
+ });
5954
+ const success = await helper.requestStickiness(envelope, {
5955
+ ttlSec: null,
5956
+ scope: "node",
5957
+ context: stickinessContext,
5958
+ });
5959
+ if (success) {
5960
+ logger$3.debug("aft_token_applied_via_context_flag_upstream", {
5961
+ envelope_id: envelope.id,
5962
+ from_system_id: context.fromSystemId ?? null,
5963
+ delivery_origin: context.originType ?? null,
5964
+ });
5965
+ }
5966
+ else {
5967
+ logger$3.debug("aft_token_not_applied_upstream", {
5968
+ envelope_id: envelope.id,
5969
+ delivery_origin: context.originType ?? null,
5970
+ reason: "helper_returned_false",
5854
5971
  });
5855
- throw new Error(`Invalid logical format: ${pathError}`);
5856
5972
  }
5857
- logger$2.debug("logicals_validation_successful");
5858
5973
  }
5859
- logger$2.debug("requesting_node_placement", { systemId });
5860
- const placementResult = await this.placementStrategy.place(normalizedHello);
5861
- if (!placementResult.accept) {
5862
- logger$2.error("node_placement_rejected", {
5863
- systemId,
5864
- reason: placementResult.reason,
5974
+ return envelope;
5975
+ }
5976
+ async onNodeStarted(node) {
5977
+ if (!this.isInitialized) {
5978
+ await this.initializeAftHelper(node);
5979
+ return;
5980
+ }
5981
+ if (this.aftHelper && node.sid) {
5982
+ this.updateNodeSid(node.sid);
5983
+ logger$3.debug("aft_replica_stickiness_manager_sid_updated", {
5984
+ node_id: node.id ?? "unknown",
5985
+ node_sid: node.sid,
5986
+ security_level: this.aftHelper.signer.securityLevel,
5865
5987
  });
5866
- throw new Error(placementResult.reason || "Node not accepted");
5867
5988
  }
5868
- const assignedPath = placementResult.assignedPath;
5869
- logger$2.debug("node_placement_accepted", {
5870
- systemId,
5871
- assignedPath,
5872
- targetPhysicalPath: placementResult.targetPhysicalPath ?? null,
5873
- targetSystemId: placementResult.targetSystemId ?? null,
5874
- });
5875
- const acceptedCapabilities = coercePlacementMetadataValue(placementResult.metadata, "acceptedCapabilities", "accepted_capabilities") ??
5876
- normalizedHello.capabilities ??
5877
- null;
5878
- const acceptedLogicals = coercePlacementMetadataValue(placementResult.metadata, "acceptedLogicals", "accepted_logicals") ??
5879
- normalizedHello.logicals ??
5880
- null;
5881
- logger$2.debug("processing_placement_result_metadata", {
5882
- acceptedCapabilities,
5883
- acceptedLogicals,
5884
- hasPlacementMetadata: placementResult.metadata !== undefined &&
5885
- placementResult.metadata !== null,
5886
- });
5887
- const connectionGrants = [];
5888
- const metadataInstanceId = (typeof fullMetadata.instanceId === "string" &&
5889
- fullMetadata.instanceId) ||
5890
- (typeof fullMetadata.instance_id === "string" &&
5891
- fullMetadata.instance_id) ||
5892
- normalizedHello.instanceId ||
5893
- core.generateId();
5894
- if (placementResult.targetSystemId) {
5895
- logger$2.debug("issuing_node_attach_token", {
5896
- systemId,
5897
- assignedPath,
5989
+ else if (!node.sid) {
5990
+ logger$3.warning("aft_replica_stickiness_manager_no_sid_available", {
5991
+ node_id: node.id ?? "unknown",
5898
5992
  });
5899
- const nodeAttachToken = await this.tokenIssuer.issue({
5900
- aud: placementResult.targetPhysicalPath,
5901
- system_id: systemId,
5902
- parent_path: placementResult.targetPhysicalPath,
5903
- assigned_path: placementResult.assignedPath,
5904
- accepted_logicals: acceptedLogicals,
5905
- instance_id: metadataInstanceId,
5993
+ }
5994
+ else {
5995
+ logger$3.error("aft_replica_stickiness_manager_node_missing_sid", {
5996
+ node_type: node.constructor?.name ?? typeof node,
5906
5997
  });
5907
- logger$2.debug("token_issued_successfully");
5908
- logger$2.debug("provisioning_transport", { systemId });
5909
- const transportInfo = await this.transportProvisioner.provision(placementResult, normalizedHello, fullMetadata, nodeAttachToken);
5910
- logger$2.debug("transport_provisioned_successfully", {
5911
- systemId,
5912
- directiveType: transportInfo.connectionGrant &&
5913
- typeof transportInfo.connectionGrant === "object"
5914
- ? (transportInfo.connectionGrant.type ??
5915
- "Unknown")
5916
- : "Unknown",
5998
+ }
5999
+ }
6000
+ updateNodeSid(nodeSid) {
6001
+ if (this.aftHelper) {
6002
+ this.aftHelper.nodeSid = nodeSid;
6003
+ logger$3.debug("aft_replica_stickiness_manager_sid_updated", {
6004
+ new_sid: nodeSid,
5917
6005
  });
5918
- connectionGrants.push(transportInfo.connectionGrant);
5919
6006
  }
5920
- const caSignToken = await this.tokenIssuer.issue({
5921
- aud: "ca",
5922
- system_id: systemId,
5923
- assigned_path: assignedPath,
5924
- accepted_logicals: acceptedLogicals,
5925
- instance_id: metadataInstanceId,
5926
- });
5927
- const caGrant = {
5928
- type: runtime.HTTP_CONNECTION_GRANT_TYPE,
5929
- purpose: GRANT_PURPOSE_CA_SIGN,
5930
- url: this.caServiceUrl,
5931
- auth: {
5932
- type: "BearerTokenHeaderAuth",
5933
- tokenProvider: {
5934
- type: "StaticTokenProvider",
5935
- token: caSignToken,
5936
- },
5937
- },
5938
- };
5939
- connectionGrants.push(caGrant);
5940
- const welcomeFrame = {
5941
- type: "NodeWelcome",
5942
- systemId,
5943
- targetSystemId: placementResult.targetSystemId ?? undefined,
5944
- targetPhysicalPath: placementResult.targetPhysicalPath ?? undefined,
5945
- instanceId: normalizedHello.instanceId,
5946
- assignedPath,
5947
- acceptedCapabilities: acceptedCapabilities ?? undefined,
5948
- acceptedLogicals: acceptedLogicals ?? undefined,
5949
- rejectedLogicals: undefined,
5950
- connectionGrants,
5951
- metadata: Object.keys(fullMetadata).length > 0 ? fullMetadata : undefined,
5952
- expiresAt: expiry.toISOString(),
5953
- };
5954
- logger$2.debug("hello_frame_processing_completed_successfully", {
5955
- systemId,
5956
- assignedPath,
5957
- acceptedLogicals,
5958
- acceptedCapabilities,
5959
- expiresAt: welcomeFrame.expiresAt,
5960
- instanceId: normalizedHello.instanceId,
5961
- });
5962
- if (showEnvelopes) {
5963
- // eslint-disable-next-line no-console
5964
- console.log(`\n${formatTimestampForConsole()} - ${runtime.color("Sent envelope", runtime.AnsiColor.BLUE)} 🚀\n${prettyModel(welcomeFrame)}`);
6007
+ }
6008
+ async initializeAftHelper(node) {
6009
+ const nodeSid = node.sid;
6010
+ if (!nodeSid) {
6011
+ logger$3.error("aft_replica_stickiness_manager_cannot_initialize_no_sid", {
6012
+ node_id: node.id ?? "unknown",
6013
+ });
6014
+ return;
6015
+ }
6016
+ const cryptoProvider = node.cryptoProvider ?? null;
6017
+ if (!cryptoProvider) {
6018
+ logger$3.error("aft_replica_stickiness_manager_cannot_initialize_no_crypto_provider", {
6019
+ node_id: node.id ?? "unknown",
6020
+ });
6021
+ return;
6022
+ }
6023
+ const keyId = typeof cryptoProvider.signatureKeyId === "string" &&
6024
+ cryptoProvider.signatureKeyId.length > 0
6025
+ ? cryptoProvider.signatureKeyId
6026
+ : "default-key-id";
6027
+ const privateKeyPem = typeof cryptoProvider.signingPrivatePem === "string"
6028
+ ? cryptoProvider.signingPrivatePem
6029
+ : null;
6030
+ if (this.securityLevel === exports.StickinessMode.STRICT && !privateKeyPem) {
6031
+ logger$3.error("aft_replica_stickiness_manager_initialization_failed", {
6032
+ node_id: node.id ?? "unknown",
6033
+ error: "Missing signing private key for strict security level",
6034
+ });
6035
+ return;
6036
+ }
6037
+ try {
6038
+ const helper = createAftHelper({
6039
+ securityLevel: this.securityLevel,
6040
+ nodeSid,
6041
+ kid: keyId,
6042
+ privateKeyPem,
6043
+ maxTtlSec: this.maxTtlSec,
6044
+ });
6045
+ this.aftHelper = helper;
6046
+ this.isInitialized = true;
6047
+ logger$3.debug("aft_replica_stickiness_manager_initialized", {
6048
+ node_id: node.id ?? "unknown",
6049
+ node_sid: nodeSid,
6050
+ key_id: keyId,
6051
+ security_level: helper.signer.securityLevel,
6052
+ });
5965
6053
  }
5966
- return welcomeFrame;
6054
+ catch (error) {
6055
+ logger$3.error("aft_replica_stickiness_manager_initialization_failed", {
6056
+ node_id: node.id ?? "unknown",
6057
+ error: error instanceof Error ? error.message : String(error),
6058
+ });
6059
+ }
6060
+ }
6061
+ get signer() {
6062
+ return this.aftHelper?.signer ?? null;
6063
+ }
6064
+ getHelper() {
6065
+ return this.aftHelper;
5967
6066
  }
5968
6067
  }
6068
+ function createAftReplicaStickinessManager(aftHelper) {
6069
+ return new AFTReplicaStickinessManager({ aftHelper });
6070
+ }
5969
6071
 
5970
- const FACTORY_META$4 = {
5971
- base: runtime.WELCOME_SERVICE_FACTORY_BASE_TYPE,
5972
- key: "AdvancedWelcomeService",
5973
- priority: 100,
5974
- isDefault: true,
6072
+ const FACTORY_META$5 = {
6073
+ base: runtime.REPLICA_STICKINESS_MANAGER_FACTORY_BASE_TYPE,
6074
+ key: "AFTReplicaStickinessManager",
5975
6075
  };
5976
- class AdvancedWelcomeServiceFactory extends runtime.WelcomeServiceFactory {
6076
+ const DEFAULT_VALUES = {
6077
+ securityLevel: exports.StickinessMode.SIGNED_OPTIONAL,
6078
+ maxTtlSec: 7200,
6079
+ };
6080
+ function normalizeConfig$3(config) {
6081
+ const record = (config ?? {});
6082
+ const normalizedSecurity = record.securityLevel
6083
+ ? normalizeStickinessMode(record.securityLevel)
6084
+ : DEFAULT_VALUES.securityLevel;
6085
+ const securityLevel = normalizedSecurity ?? DEFAULT_VALUES.securityLevel;
6086
+ const maxTtlSecValue = typeof record.maxTtlSec === "number" && Number.isFinite(record.maxTtlSec)
6087
+ ? Math.max(0, Math.floor(record.maxTtlSec))
6088
+ : DEFAULT_VALUES.maxTtlSec;
6089
+ return {
6090
+ ...record,
6091
+ type: "AFTReplicaStickinessManager",
6092
+ securityLevel,
6093
+ maxTtlSec: maxTtlSecValue,
6094
+ };
6095
+ }
6096
+ class AFTReplicaStickinessManagerFactory extends runtime.ReplicaStickinessManagerFactory {
5977
6097
  constructor() {
5978
6098
  super(...arguments);
5979
- this.type = FACTORY_META$4.key;
5980
- this.isDefault = FACTORY_META$4.isDefault;
5981
- this.priority = FACTORY_META$4.priority;
5982
- }
5983
- async create(config, ...factoryArgs) {
5984
- const normalized = normalizeConfig$2(config);
5985
- // Crypto provider should be passed from upstream (node-welcome-server)
5986
- // Do not create it here - downstream components should use what's passed in factoryArgs
5987
- const placementStrategy = await runtime.NodePlacementStrategyFactory.createNodePlacementStrategy(normalized.placementConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
5988
- const transportProvisioner = await runtime.TransportProvisionerFactory.createTransportProvisioner(normalized.transportConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
5989
- const tokenIssuer = await runtime.TokenIssuerFactory.createTokenIssuer(normalized.tokenIssuerConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
5990
- let authorizer = null;
5991
- if (normalized.authorizerConfig) {
5992
- authorizer =
5993
- (await runtime.AuthorizerFactory.createAuthorizer(normalized.authorizerConfig, {
5994
- factoryArgs,
5995
- })) ?? null;
5996
- }
5997
- const options = {
5998
- placementStrategy,
5999
- transportProvisioner,
6000
- tokenIssuer,
6001
- authorizer,
6002
- caServiceUrl: normalized.caServiceUrl,
6003
- };
6004
- if (normalized.ttlSec !== undefined) {
6005
- options.ttlSec = normalized.ttlSec;
6006
- }
6007
- return new AdvancedWelcomeService(options);
6008
- }
6009
- }
6010
- function normalizeConfig$2(config) {
6011
- if (!config) {
6012
- throw new Error("AdvancedWelcomeService requires configuration");
6013
- }
6014
- const source = config;
6015
- const ttlCandidate = typeof source.ttlSec === "number"
6016
- ? source.ttlSec
6017
- : typeof source.ttl_sec === "number"
6018
- ? source.ttl_sec
6019
- : undefined;
6020
- const caServiceUrlCandidate = typeof source.caServiceUrl === "string" &&
6021
- source.caServiceUrl.trim().length > 0
6022
- ? source.caServiceUrl.trim()
6023
- : typeof source.ca_service_url === "string" &&
6024
- source.ca_service_url.trim().length > 0
6025
- ? source.ca_service_url.trim()
6026
- : undefined;
6027
- if (!caServiceUrlCandidate) {
6028
- throw new Error("AdvancedWelcomeService configuration requires caServiceUrl");
6029
- }
6030
- const normalized = {
6031
- caServiceUrl: caServiceUrlCandidate,
6032
- };
6033
- if (source.placement !== undefined) {
6034
- normalized.placementConfig =
6035
- source.placement ?? null;
6036
- }
6037
- if (source.transport !== undefined) {
6038
- normalized.transportConfig =
6039
- source.transport ?? null;
6040
- }
6041
- const tokenIssuerConfig = source.tokenIssuer !== undefined
6042
- ? source.tokenIssuer
6043
- : source.token_issuer !== undefined
6044
- ? source.token_issuer
6045
- : undefined;
6046
- if (tokenIssuerConfig !== undefined) {
6047
- normalized.tokenIssuerConfig =
6048
- tokenIssuerConfig ?? null;
6049
- }
6050
- if (source.authorizer !== undefined) {
6051
- normalized.authorizerConfig =
6052
- source.authorizer ?? null;
6099
+ this.type = FACTORY_META$5.key;
6100
+ this.isDefault = true;
6053
6101
  }
6054
- if (ttlCandidate !== undefined && Number.isFinite(ttlCandidate)) {
6055
- normalized.ttlSec = ttlCandidate;
6102
+ async create(config, dependencies) {
6103
+ const resolvedConfig = normalizeConfig$3(config);
6104
+ const helper = dependencies?.aftHelper ?? null;
6105
+ const securityLevel = normalizeStickinessMode(resolvedConfig.securityLevel ?? DEFAULT_VALUES.securityLevel) ?? DEFAULT_VALUES.securityLevel;
6106
+ const maxTtlSec = typeof resolvedConfig.maxTtlSec === "number" &&
6107
+ Number.isFinite(resolvedConfig.maxTtlSec)
6108
+ ? Math.max(0, Math.floor(resolvedConfig.maxTtlSec))
6109
+ : DEFAULT_VALUES.maxTtlSec;
6110
+ return new AFTReplicaStickinessManager({
6111
+ securityLevel,
6112
+ maxTtlSec,
6113
+ aftHelper: helper,
6114
+ });
6056
6115
  }
6057
- return normalized;
6058
6116
  }
6059
6117
 
6060
- var advancedWelcomeServiceFactory = /*#__PURE__*/Object.freeze({
6118
+ var aftReplicaStickinessManagerFactory = /*#__PURE__*/Object.freeze({
6061
6119
  __proto__: null,
6062
- AdvancedWelcomeServiceFactory: AdvancedWelcomeServiceFactory,
6063
- FACTORY_META: FACTORY_META$4,
6064
- default: AdvancedWelcomeServiceFactory
6120
+ AFTReplicaStickinessManagerFactory: AFTReplicaStickinessManagerFactory,
6121
+ FACTORY_META: FACTORY_META$5,
6122
+ default: AFTReplicaStickinessManagerFactory
6065
6123
  });
6066
6124
 
6067
- /**
6068
- * AUTO-GENERATED FILE. DO NOT EDIT DIRECTLY.
6069
- * Generated by scripts/generate-factory-manifest.mjs
6070
- *
6071
- * Provides the list of advanced security factory modules for registration.
6072
- */
6073
- const MODULES = [
6074
- "./security/cert/default-ca-service-factory.js",
6075
- "./security/cert/default-certificate-manager-factory.js",
6076
- "./security/cert/trust-store/browser-trust-store-provider-factory.js",
6077
- "./security/cert/trust-store/node-trust-store-provider-factory.js",
6078
- "./security/encryption/channel/channel-encryption-manager-factory.js",
6079
- "./security/encryption/composite-encryption-manager-factory.js",
6080
- "./security/encryption/default-secure-channel-manager-factory.js",
6081
- "./security/encryption/sealed/x25519-encryption-manager-factory.js",
6082
- "./security/keys/x5c-key-manager-factory.js",
6083
- "./security/signing/eddsa-envelope-signer-factory.js",
6084
- "./security/signing/eddsa-envelope-verifier-factory.js",
6085
- "./stickiness/aft-load-balancer-stickiness-manager-factory.js",
6086
- "./stickiness/aft-replica-stickiness-manager-factory.js",
6087
- "./welcome/advanced-welcome-service-factory.js"
6088
- ];
6089
- const MODULE_LOADERS = {
6090
- "./security/cert/default-ca-service-factory.js": () => Promise.resolve().then(function () { return defaultCaServiceFactory; }),
6091
- "./security/cert/default-certificate-manager-factory.js": () => Promise.resolve().then(function () { return defaultCertificateManagerFactory; }),
6092
- "./security/cert/trust-store/browser-trust-store-provider-factory.js": () => Promise.resolve().then(function () { return browserTrustStoreProviderFactory; }),
6093
- "./security/cert/trust-store/node-trust-store-provider-factory.js": () => Promise.resolve().then(function () { return nodeTrustStoreProviderFactory; }),
6094
- "./security/encryption/channel/channel-encryption-manager-factory.js": () => Promise.resolve().then(function () { return channelEncryptionManagerFactory; }),
6095
- "./security/encryption/composite-encryption-manager-factory.js": () => Promise.resolve().then(function () { return compositeEncryptionManagerFactory; }),
6096
- "./security/encryption/default-secure-channel-manager-factory.js": () => Promise.resolve().then(function () { return defaultSecureChannelManagerFactory; }),
6097
- "./security/encryption/sealed/x25519-encryption-manager-factory.js": () => Promise.resolve().then(function () { return x25519EncryptionManagerFactory; }),
6098
- "./security/keys/x5c-key-manager-factory.js": () => Promise.resolve().then(function () { return x5cKeyManagerFactory; }),
6099
- "./security/signing/eddsa-envelope-signer-factory.js": () => Promise.resolve().then(function () { return eddsaEnvelopeSignerFactory; }),
6100
- "./security/signing/eddsa-envelope-verifier-factory.js": () => Promise.resolve().then(function () { return eddsaEnvelopeVerifierFactory; }),
6101
- "./stickiness/aft-load-balancer-stickiness-manager-factory.js": () => Promise.resolve().then(function () { return aftLoadBalancerStickinessManagerFactory; }),
6102
- "./stickiness/aft-replica-stickiness-manager-factory.js": () => Promise.resolve().then(function () { return aftReplicaStickinessManagerFactory; }),
6103
- "./welcome/advanced-welcome-service-factory.js": () => Promise.resolve().then(function () { return advancedWelcomeServiceFactory; }),
6104
- };
6105
-
6106
- const SECURITY_PREFIX = "./security/";
6107
- const SECURITY_MODULES = MODULES.filter((spec) => spec.startsWith(SECURITY_PREFIX));
6108
- const EXTRA_MODULES = MODULES.filter((spec) => !spec.startsWith(SECURITY_PREFIX));
6109
- const NODE_ONLY_MODULES = new Set([
6110
- "./security/cert/default-ca-service-factory.js",
6111
- "./security/cert/trust-store/node-trust-store-provider-factory.js",
6112
- ]);
6113
- const FACTORY_MODULE_PREFIX$1 = "@naylence/advanced-security/naylence/fame/";
6114
- const BROWSER_DIST_SEGMENT = "/dist/browser/";
6115
- function detectModuleUrl() {
6116
- if (typeof __filename === "string") {
6117
- try {
6118
- return __filename.startsWith("file://")
6119
- ? __filename
6120
- : `file://${__filename}`;
6121
- }
6122
- catch {
6123
- // fall through to stack parsing
6124
- }
6125
- }
6126
- try {
6127
- throw new Error();
6128
- }
6129
- catch (error) {
6130
- const stack = typeof error === "object" && error && "stack" in error
6131
- ? String(error.stack ?? "")
6132
- : "";
6133
- const lines = stack.split("\n");
6134
- for (const line of lines) {
6135
- const match = line.match(/(https?:\/\/[^\s)]+|file:\/\/[^\s)]+\.(?:js|ts)|\/(?:[^\s)]+\.(?:js|ts)))/u);
6136
- const candidate = match?.[1];
6137
- if (!candidate) {
6138
- continue;
6139
- }
6140
- if (candidate.startsWith("http://") || candidate.startsWith("https://")) {
6141
- return candidate;
6142
- }
6143
- if (candidate.startsWith("file://")) {
6144
- return candidate;
6145
- }
6146
- return `file://${candidate}`;
6147
- }
6148
- }
6149
- return null;
6125
+ const logger$2 = runtime.getLogger("naylence.fame.welcome.advanced_welcome_service");
6126
+ const ENV_VAR_SHOW_ENVELOPES = "FAME_SHOW_ENVELOPES";
6127
+ const DEFAULT_TTL_SEC = 3600;
6128
+ const showEnvelopes = typeof process !== "undefined" &&
6129
+ process.env?.[ENV_VAR_SHOW_ENVELOPES] === "true";
6130
+ function nowUtc() {
6131
+ return new Date();
6150
6132
  }
6151
- function computeBrowserFactoryBase(rawUrl) {
6152
- if (!rawUrl) {
6153
- return null;
6154
- }
6155
- const sanitized = rawUrl.split("?")[0]?.split("#")[0] ?? rawUrl;
6156
- const esmMarker = "/dist/esm/naylence/fame/";
6157
- const distMarker = "/dist/";
6158
- if (sanitized.includes(esmMarker)) {
6159
- return sanitized.slice(0, sanitized.indexOf(esmMarker) + esmMarker.length);
6160
- }
6161
- if (rawUrl.includes(BROWSER_DIST_SEGMENT)) {
6162
- return new URL("../esm/naylence/fame/", rawUrl).href;
6133
+ function formatTimestampForConsole() {
6134
+ return runtime.color(runtime.formatTimestamp(), runtime.AnsiColor.GRAY);
6135
+ }
6136
+ function prettyModel(value) {
6137
+ try {
6138
+ return runtime.jsonDumps(value);
6163
6139
  }
6164
- if (sanitized.includes(BROWSER_DIST_SEGMENT)) {
6165
- const base = sanitized.slice(0, sanitized.indexOf(BROWSER_DIST_SEGMENT) + BROWSER_DIST_SEGMENT.length);
6166
- return `${base.replace(/browser\/?$/u, "")}esm/naylence/fame/`;
6140
+ catch (error) {
6141
+ return String(error);
6167
6142
  }
6168
- if (sanitized.includes(distMarker)) {
6169
- const index = sanitized.indexOf(distMarker);
6170
- const base = sanitized.slice(0, index + distMarker.length);
6171
- return `${base}esm/naylence/fame/`;
6143
+ }
6144
+ function coercePlacementMetadataValue(metadata, camelCaseKey, snakeCaseKey) {
6145
+ if (!metadata) {
6146
+ return undefined;
6172
6147
  }
6173
- const srcMarker = "/src/naylence/fame/";
6174
- if (sanitized.includes(srcMarker)) {
6175
- const index = sanitized.indexOf(srcMarker);
6176
- const projectRoot = sanitized.slice(0, index);
6177
- return `${projectRoot}/dist/esm/naylence/fame/`;
6148
+ const record = metadata;
6149
+ if (record[camelCaseKey] !== undefined) {
6150
+ return record[camelCaseKey];
6178
6151
  }
6179
- if (sanitized.startsWith("http://") || sanitized.startsWith("https://")) {
6180
- try {
6181
- const parsed = new URL(rawUrl);
6182
- const viteDepsSegment = "/node_modules/.vite/deps/";
6183
- if (parsed.pathname.includes(viteDepsSegment)) {
6184
- const baseOrigin = `${parsed.protocol}//${parsed.host}`;
6185
- return `${baseOrigin}/node_modules/@naylence/advanced-security/dist/esm/naylence/fame/`;
6186
- }
6187
- }
6188
- catch {
6189
- // ignore
6190
- }
6152
+ if (record[snakeCaseKey] !== undefined) {
6153
+ return record[snakeCaseKey];
6191
6154
  }
6192
- return null;
6155
+ return undefined;
6193
6156
  }
6194
- const moduleUrl = detectModuleUrl();
6195
- const browserFactoryBase = computeBrowserFactoryBase(moduleUrl);
6196
- const prefersSource = typeof moduleUrl === "string" && moduleUrl.includes("/src/");
6197
- function resolveFactoryModuleSpecifier$1(specifier) {
6198
- if (specifier.startsWith("../")) {
6199
- return `${FACTORY_MODULE_PREFIX$1}${specifier.slice("../".length)}`;
6200
- }
6201
- if (specifier.startsWith("./")) {
6202
- return `${FACTORY_MODULE_PREFIX$1}${specifier.slice("./".length)}`;
6157
+ class AdvancedWelcomeService {
6158
+ constructor(options) {
6159
+ this.placementStrategy = options.placementStrategy;
6160
+ this.transportProvisioner = options.transportProvisioner;
6161
+ this.tokenIssuer = options.tokenIssuer;
6162
+ this.authorizer = options.authorizer ?? null;
6163
+ this.caServiceUrl = options.caServiceUrl;
6164
+ this.ttlSec =
6165
+ typeof options.ttlSec === "number" && Number.isFinite(options.ttlSec)
6166
+ ? Math.max(0, options.ttlSec)
6167
+ : DEFAULT_TTL_SEC;
6168
+ logger$2.debug("initialized_advanced_welcome_service", {
6169
+ ca_service_url: this.caServiceUrl,
6170
+ ttl_sec: this.ttlSec,
6171
+ });
6203
6172
  }
6204
- return null;
6205
- }
6206
- function resolveModuleCandidates(spec) {
6207
- const candidates = [];
6208
- const seen = new Set();
6209
- const addCandidate = (candidate) => {
6210
- if (!candidate) {
6211
- return;
6212
- }
6213
- if (!seen.has(candidate)) {
6214
- seen.add(candidate);
6215
- candidates.push(candidate);
6173
+ async handleHello(hello, metadata) {
6174
+ const fullMetadata = metadata
6175
+ ? { ...metadata }
6176
+ : {};
6177
+ const trimmedSystemId = typeof hello.systemId === "string" ? hello.systemId.trim() : "";
6178
+ const systemId = trimmedSystemId.length > 0 ? trimmedSystemId : core.generateId();
6179
+ const wasAssigned = trimmedSystemId.length === 0;
6180
+ const normalizedHello = {
6181
+ ...hello,
6182
+ systemId,
6183
+ };
6184
+ if (showEnvelopes) {
6185
+ // eslint-disable-next-line no-console
6186
+ console.log(`\n${formatTimestampForConsole()} - ${runtime.color("Received envelope 📨", runtime.AnsiColor.BLUE)}\n${prettyModel(normalizedHello)}`);
6216
6187
  }
6217
- };
6218
- if (prefersSource && spec.startsWith("./")) {
6219
- const sourceCandidate = `../${spec.slice(2)}`;
6220
- addCandidate(sourceCandidate);
6221
- if (sourceCandidate.endsWith(".js")) {
6222
- addCandidate(sourceCandidate.replace(/\.js$/u, ".ts"));
6188
+ logger$2.debug("starting_hello_frame_processing", {
6189
+ instanceId: normalizedHello.instanceId,
6190
+ systemId,
6191
+ logicals: normalizedHello.logicals,
6192
+ capabilities: normalizedHello.capabilities,
6193
+ ttlSec: this.ttlSec,
6194
+ });
6195
+ const now = nowUtc();
6196
+ const expiry = new Date(now.getTime() + this.ttlSec * 1000);
6197
+ if (normalizedHello.instanceId) {
6198
+ if (fullMetadata.instanceId === undefined) {
6199
+ fullMetadata.instanceId = normalizedHello.instanceId;
6200
+ }
6201
+ if (fullMetadata.instance_id === undefined) {
6202
+ fullMetadata.instance_id = normalizedHello.instanceId;
6203
+ }
6223
6204
  }
6224
- }
6225
- if (browserFactoryBase && spec.startsWith("./")) {
6226
- try {
6227
- const browserCandidate = new URL(spec.slice("./".length), browserFactoryBase).href;
6228
- addCandidate(browserCandidate);
6229
- if (browserCandidate.endsWith(".js")) {
6230
- addCandidate(browserCandidate.replace(/\.js$/u, ".ts"));
6205
+ logger$2.debug("system_id_assignment_completed", {
6206
+ systemId,
6207
+ wasAssigned,
6208
+ });
6209
+ if (normalizedHello.logicals?.length) {
6210
+ logger$2.debug("validating_logicals_for_dns_compatibility", {
6211
+ logicals: normalizedHello.logicals,
6212
+ });
6213
+ const [pathsValid, pathError] = runtime.validateHostLogicals(normalizedHello.logicals);
6214
+ if (!pathsValid) {
6215
+ logger$2.error("logical_validation_failed", {
6216
+ error: pathError,
6217
+ logicals: normalizedHello.logicals,
6218
+ });
6219
+ throw new Error(`Invalid logical format: ${pathError}`);
6231
6220
  }
6221
+ logger$2.debug("logicals_validation_successful");
6232
6222
  }
6233
- catch {
6234
- // ignore resolution failures for browser base
6223
+ logger$2.debug("requesting_node_placement", { systemId });
6224
+ const placementResult = await this.placementStrategy.place(normalizedHello);
6225
+ if (!placementResult.accept) {
6226
+ logger$2.error("node_placement_rejected", {
6227
+ systemId,
6228
+ reason: placementResult.reason,
6229
+ });
6230
+ throw new Error(placementResult.reason || "Node not accepted");
6235
6231
  }
6232
+ const assignedPath = placementResult.assignedPath;
6233
+ logger$2.debug("node_placement_accepted", {
6234
+ systemId,
6235
+ assignedPath,
6236
+ targetPhysicalPath: placementResult.targetPhysicalPath ?? null,
6237
+ targetSystemId: placementResult.targetSystemId ?? null,
6238
+ });
6239
+ const acceptedCapabilities = coercePlacementMetadataValue(placementResult.metadata, "acceptedCapabilities", "accepted_capabilities") ??
6240
+ normalizedHello.capabilities ??
6241
+ null;
6242
+ const acceptedLogicals = coercePlacementMetadataValue(placementResult.metadata, "acceptedLogicals", "accepted_logicals") ??
6243
+ normalizedHello.logicals ??
6244
+ null;
6245
+ logger$2.debug("processing_placement_result_metadata", {
6246
+ acceptedCapabilities,
6247
+ acceptedLogicals,
6248
+ hasPlacementMetadata: placementResult.metadata !== undefined &&
6249
+ placementResult.metadata !== null,
6250
+ });
6251
+ const connectionGrants = [];
6252
+ const metadataInstanceId = (typeof fullMetadata.instanceId === "string" &&
6253
+ fullMetadata.instanceId) ||
6254
+ (typeof fullMetadata.instance_id === "string" &&
6255
+ fullMetadata.instance_id) ||
6256
+ normalizedHello.instanceId ||
6257
+ core.generateId();
6258
+ if (placementResult.targetSystemId) {
6259
+ logger$2.debug("issuing_node_attach_token", {
6260
+ systemId,
6261
+ assignedPath,
6262
+ });
6263
+ const nodeAttachToken = await this.tokenIssuer.issue({
6264
+ aud: placementResult.targetPhysicalPath,
6265
+ system_id: systemId,
6266
+ parent_path: placementResult.targetPhysicalPath,
6267
+ assigned_path: placementResult.assignedPath,
6268
+ accepted_logicals: acceptedLogicals,
6269
+ instance_id: metadataInstanceId,
6270
+ });
6271
+ logger$2.debug("token_issued_successfully");
6272
+ logger$2.debug("provisioning_transport", { systemId });
6273
+ const transportInfo = await this.transportProvisioner.provision(placementResult, normalizedHello, fullMetadata, nodeAttachToken);
6274
+ logger$2.debug("transport_provisioned_successfully", {
6275
+ systemId,
6276
+ directiveType: transportInfo.connectionGrant &&
6277
+ typeof transportInfo.connectionGrant === "object"
6278
+ ? (transportInfo.connectionGrant.type ??
6279
+ "Unknown")
6280
+ : "Unknown",
6281
+ });
6282
+ connectionGrants.push(transportInfo.connectionGrant);
6283
+ }
6284
+ const caSignToken = await this.tokenIssuer.issue({
6285
+ aud: "ca",
6286
+ system_id: systemId,
6287
+ assigned_path: assignedPath,
6288
+ accepted_logicals: acceptedLogicals,
6289
+ instance_id: metadataInstanceId,
6290
+ });
6291
+ const caGrant = {
6292
+ type: runtime.HTTP_CONNECTION_GRANT_TYPE,
6293
+ purpose: GRANT_PURPOSE_CA_SIGN,
6294
+ url: this.caServiceUrl,
6295
+ auth: {
6296
+ type: "BearerTokenHeaderAuth",
6297
+ tokenProvider: {
6298
+ type: "StaticTokenProvider",
6299
+ token: caSignToken,
6300
+ },
6301
+ },
6302
+ };
6303
+ connectionGrants.push(caGrant);
6304
+ const welcomeFrame = {
6305
+ type: "NodeWelcome",
6306
+ systemId,
6307
+ targetSystemId: placementResult.targetSystemId ?? undefined,
6308
+ targetPhysicalPath: placementResult.targetPhysicalPath ?? undefined,
6309
+ instanceId: normalizedHello.instanceId,
6310
+ assignedPath,
6311
+ acceptedCapabilities: acceptedCapabilities ?? undefined,
6312
+ acceptedLogicals: acceptedLogicals ?? undefined,
6313
+ rejectedLogicals: undefined,
6314
+ connectionGrants,
6315
+ metadata: Object.keys(fullMetadata).length > 0 ? fullMetadata : undefined,
6316
+ expiresAt: expiry.toISOString(),
6317
+ };
6318
+ logger$2.debug("hello_frame_processing_completed_successfully", {
6319
+ systemId,
6320
+ assignedPath,
6321
+ acceptedLogicals,
6322
+ acceptedCapabilities,
6323
+ expiresAt: welcomeFrame.expiresAt,
6324
+ instanceId: normalizedHello.instanceId,
6325
+ });
6326
+ if (showEnvelopes) {
6327
+ // eslint-disable-next-line no-console
6328
+ console.log(`\n${formatTimestampForConsole()} - ${runtime.color("Sent envelope", runtime.AnsiColor.BLUE)} 🚀\n${prettyModel(welcomeFrame)}`);
6329
+ }
6330
+ return welcomeFrame;
6236
6331
  }
6237
- const packageCandidate = resolveFactoryModuleSpecifier$1(spec);
6238
- addCandidate(packageCandidate);
6239
- if (packageCandidate?.endsWith(".js")) {
6240
- addCandidate(packageCandidate.replace(/\.js$/u, ".ts"));
6241
- }
6242
- const fallback = spec.startsWith("./") ? `../${spec.slice(2)}` : spec;
6243
- addCandidate(fallback);
6244
- if (fallback.endsWith(".js")) {
6245
- addCandidate(fallback.replace(/\.js$/u, ".ts"));
6246
- }
6247
- addCandidate(spec);
6248
- if (spec.endsWith(".js")) {
6249
- addCandidate(spec.replace(/\.js$/u, ".ts"));
6250
- }
6251
- return candidates;
6252
- }
6253
- const registeredModules = new Set();
6254
- const inflightModules = new Map();
6255
- const browserSkippedModules = new Set();
6256
- function isNodeEnvironment$5() {
6257
- return (typeof process !== "undefined" &&
6258
- typeof process.release !== "undefined" &&
6259
- process.release?.name === "node");
6260
- }
6261
- function shouldSkipModule(spec) {
6262
- if (isNodeEnvironment$5()) {
6263
- return false;
6264
- }
6265
- if (!NODE_ONLY_MODULES.has(spec)) {
6266
- return false;
6267
- }
6268
- if (!browserSkippedModules.has(spec)) {
6269
- // console.warn(
6270
- // "[advanced-security:factory-manifest] skipped browser-incompatible module",
6271
- // spec,
6272
- // );
6273
- browserSkippedModules.add(spec);
6274
- }
6275
- return true;
6276
- }
6277
- function getDynamicImporter() {
6278
- if (typeof globalThis === "undefined") {
6279
- return null;
6280
- }
6281
- const candidate = globalThis.__naylenceFactoryDynamicImporter;
6282
- if (typeof candidate === "function") {
6283
- return candidate;
6284
- }
6285
- return null;
6286
6332
  }
6287
- async function registerModule(spec, registrar) {
6288
- const candidates = resolveModuleCandidates(spec);
6289
- const dynamicImporter = getDynamicImporter();
6290
- const loader = dynamicImporter
6291
- ? (specifier) => dynamicImporter(specifier)
6292
- : (specifier) => import(/* @vite-ignore */ specifier);
6293
- const attempts = [];
6294
- const staticLoader = MODULE_LOADERS?.[spec];
6295
- if (staticLoader) {
6296
- attempts.push({ load: () => staticLoader(), candidate: spec });
6297
- }
6298
- for (const candidate of candidates) {
6299
- attempts.push({ load: () => loader(candidate), candidate });
6333
+
6334
+ const FACTORY_META$4 = {
6335
+ base: runtime.WELCOME_SERVICE_FACTORY_BASE_TYPE,
6336
+ key: "AdvancedWelcomeService",
6337
+ priority: 100,
6338
+ isDefault: true,
6339
+ };
6340
+ class AdvancedWelcomeServiceFactory extends runtime.WelcomeServiceFactory {
6341
+ constructor() {
6342
+ super(...arguments);
6343
+ this.type = FACTORY_META$4.key;
6344
+ this.isDefault = FACTORY_META$4.isDefault;
6345
+ this.priority = FACTORY_META$4.priority;
6300
6346
  }
6301
- const registerFromModule = (mod) => {
6302
- const meta = mod.FACTORY_META;
6303
- const Ctor = mod.default;
6304
- if (!meta?.base || !meta?.key || typeof Ctor !== "function") {
6305
- console.warn("[debug] invalid factory module", spec, {
6306
- meta,
6307
- hasCtor: typeof Ctor === "function",
6308
- });
6309
- console.warn("[advanced-security:factory-manifest] skipped", spec, "— missing FACTORY_META or default export ctor");
6310
- return false;
6311
- }
6312
- const { base, key, ...metadata } = meta;
6313
- const extraMetadata = Object.keys(metadata).length > 0 ? metadata : undefined;
6314
- // console.log("[debug] registering module", { spec, base, key, metadata: extraMetadata });
6315
- registrar.registerFactory(base, key, Ctor, extraMetadata);
6316
- return true;
6317
- };
6318
- for (const [index, { candidate, load }] of attempts.entries()) {
6319
- try {
6320
- const mod = await load();
6321
- return registerFromModule(mod);
6347
+ async create(config, ...factoryArgs) {
6348
+ const normalized = normalizeConfig$2(config);
6349
+ // Crypto provider should be passed from upstream (node-welcome-server)
6350
+ // Do not create it here - downstream components should use what's passed in factoryArgs
6351
+ const placementStrategy = await runtime.NodePlacementStrategyFactory.createNodePlacementStrategy(normalized.placementConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
6352
+ const transportProvisioner = await runtime.TransportProvisionerFactory.createTransportProvisioner(normalized.transportConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
6353
+ const tokenIssuer = await runtime.TokenIssuerFactory.createTokenIssuer(normalized.tokenIssuerConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
6354
+ let authorizer = null;
6355
+ if (normalized.authorizerConfig) {
6356
+ authorizer =
6357
+ (await runtime.AuthorizerFactory.createAuthorizer(normalized.authorizerConfig, {
6358
+ factoryArgs,
6359
+ })) ?? null;
6322
6360
  }
6323
- catch (error) {
6324
- const message = error instanceof Error ? error.message : String(error);
6325
- const moduleNotFound = message.includes("Cannot find module") ||
6326
- message.includes("ERR_MODULE_NOT_FOUND") ||
6327
- message.includes("Unknown file extension") ||
6328
- message.includes("Failed to fetch dynamically imported module") ||
6329
- message.includes("Failed to resolve module specifier") ||
6330
- message.includes("Importing a module script failed");
6331
- const isLastAttempt = index === attempts.length - 1;
6332
- if (!moduleNotFound || isLastAttempt) {
6333
- console.warn("[debug] failed to import candidate", {
6334
- spec,
6335
- candidate,
6336
- message,
6337
- });
6338
- console.warn("[advanced-security:factory-manifest] skipped", spec, "-", message);
6339
- return false;
6340
- }
6361
+ const options = {
6362
+ placementStrategy,
6363
+ transportProvisioner,
6364
+ tokenIssuer,
6365
+ authorizer,
6366
+ caServiceUrl: normalized.caServiceUrl,
6367
+ };
6368
+ if (normalized.ttlSec !== undefined) {
6369
+ options.ttlSec = normalized.ttlSec;
6341
6370
  }
6371
+ return new AdvancedWelcomeService(options);
6342
6372
  }
6343
- return false;
6344
6373
  }
6345
- async function registerModuleOnce(spec, registrar) {
6346
- if (registeredModules.has(spec)) {
6347
- return false;
6348
- }
6349
- const inflight = inflightModules.get(spec);
6350
- if (inflight) {
6351
- return inflight;
6374
+ function normalizeConfig$2(config) {
6375
+ if (!config) {
6376
+ throw new Error("AdvancedWelcomeService requires configuration");
6352
6377
  }
6353
- const registration = (async () => {
6354
- const registered = await registerModule(spec, registrar);
6355
- if (registered) {
6356
- registeredModules.add(spec);
6357
- }
6358
- return registered;
6359
- })();
6360
- inflightModules.set(spec, registration);
6361
- try {
6362
- return await registration;
6378
+ const source = config;
6379
+ const ttlCandidate = typeof source.ttlSec === "number"
6380
+ ? source.ttlSec
6381
+ : typeof source.ttl_sec === "number"
6382
+ ? source.ttl_sec
6383
+ : undefined;
6384
+ const caServiceUrlCandidate = typeof source.caServiceUrl === "string" &&
6385
+ source.caServiceUrl.trim().length > 0
6386
+ ? source.caServiceUrl.trim()
6387
+ : typeof source.ca_service_url === "string" &&
6388
+ source.ca_service_url.trim().length > 0
6389
+ ? source.ca_service_url.trim()
6390
+ : undefined;
6391
+ if (!caServiceUrlCandidate) {
6392
+ throw new Error("AdvancedWelcomeService configuration requires caServiceUrl");
6363
6393
  }
6364
- finally {
6365
- inflightModules.delete(spec);
6394
+ const normalized = {
6395
+ caServiceUrl: caServiceUrlCandidate,
6396
+ };
6397
+ if (source.placement !== undefined) {
6398
+ normalized.placementConfig =
6399
+ source.placement ?? null;
6366
6400
  }
6367
- }
6368
- async function registerModules(modules, registrar) {
6369
- if (modules.length === 0) {
6370
- return 0;
6401
+ if (source.transport !== undefined) {
6402
+ normalized.transportConfig =
6403
+ source.transport ?? null;
6371
6404
  }
6372
- const eligibleModules = modules.filter((spec) => !shouldSkipModule(spec));
6373
- if (eligibleModules.length === 0) {
6374
- return 0;
6405
+ const tokenIssuerConfig = source.tokenIssuer !== undefined
6406
+ ? source.tokenIssuer
6407
+ : source.token_issuer !== undefined
6408
+ ? source.token_issuer
6409
+ : undefined;
6410
+ if (tokenIssuerConfig !== undefined) {
6411
+ normalized.tokenIssuerConfig =
6412
+ tokenIssuerConfig ?? null;
6375
6413
  }
6376
- const results = await Promise.all(eligibleModules.map((spec) => registerModuleOnce(spec, registrar)));
6377
- return results.reduce((count, registered) => (registered ? count + 1 : count), 0);
6378
- }
6379
- async function registerAdvancedSecurityFactories(registrar = factory.Registry, options) {
6380
- const newlyRegisteredSecurity = await registerModules(SECURITY_MODULES, registrar);
6381
- if (newlyRegisteredSecurity > 0) {
6382
- getEncryptionManagerFactoryRegistry().forceRediscovery();
6414
+ if (source.authorizer !== undefined) {
6415
+ normalized.authorizerConfig =
6416
+ source.authorizer ?? null;
6383
6417
  }
6384
- {
6385
- await registerModules(EXTRA_MODULES, registrar);
6418
+ if (ttlCandidate !== undefined && Number.isFinite(ttlCandidate)) {
6419
+ normalized.ttlSec = ttlCandidate;
6386
6420
  }
6421
+ return normalized;
6387
6422
  }
6388
6423
 
6424
+ var advancedWelcomeServiceFactory = /*#__PURE__*/Object.freeze({
6425
+ __proto__: null,
6426
+ AdvancedWelcomeServiceFactory: AdvancedWelcomeServiceFactory,
6427
+ FACTORY_META: FACTORY_META$4,
6428
+ default: AdvancedWelcomeServiceFactory
6429
+ });
6430
+
6389
6431
  /**
6390
6432
  * Isomorphic entry point for Naylence Advanced Security.
6391
6433
  *
@@ -6460,7 +6502,16 @@ const __advancedSecurityPluginLoader = ensureAdvancedSecurityPluginLoader();
6460
6502
  * runtimes lacking Node.js built-ins. Node-specific certificate authority
6461
6503
  * helpers and Fastify bindings are intentionally excluded.
6462
6504
  */
6463
- // Import and use the loader to ensure bundlers don't tree-shake it away
6505
+ // Always register the plugin directly. This ensures it is initialized even if
6506
+ // the dynamic import mechanism fails.
6507
+ (async () => {
6508
+ try {
6509
+ await advancedSecurityPlugin.register();
6510
+ }
6511
+ catch (err) {
6512
+ console.error('[naylence:advanced-security] Failed to auto-register plugin:', err);
6513
+ }
6514
+ })();
6464
6515
  // Mark as used so bundlers keep the import
6465
6516
  if (typeof __advancedSecurityPluginLoader === "undefined") {
6466
6517
  throw new Error("Advanced security plugin loader not initialized");
@@ -9827,48 +9878,6 @@ var nodeTrustStoreProviderFactory = /*#__PURE__*/Object.freeze({
9827
9878
  default: EnvTrustStoreProviderFactory
9828
9879
  });
9829
9880
 
9830
- async function registerAdvancedSecurityPluginFactories(registrar = factory.Registry) {
9831
- await registerAdvancedSecurityFactories(registrar);
9832
- }
9833
- let initialized = false;
9834
- let initializing = null;
9835
- const advancedSecurityPlugin = {
9836
- name: "naylence:advanced-security",
9837
- version: VERSION,
9838
- async register() {
9839
- // console.log('[naylence:advanced-security] register() called, initialized=', initialized);
9840
- if (initialized) {
9841
- // console.log('[naylence:advanced-security] already initialized, skipping');
9842
- return;
9843
- }
9844
- if (initializing) {
9845
- console.log("[naylence:advanced-security] already initializing, awaiting...");
9846
- await initializing;
9847
- return;
9848
- }
9849
- initializing = (async () => {
9850
- try {
9851
- // console.log('[naylence:advanced-security] registering advanced security factories...');
9852
- await registerAdvancedSecurityPluginFactories();
9853
- // console.log('[naylence:advanced-security] advanced security factories registered');
9854
- initialized = true;
9855
- }
9856
- finally {
9857
- initializing = null;
9858
- }
9859
- })();
9860
- await initializing;
9861
- },
9862
- };
9863
- const ADVANCED_SECURITY_PLUGIN_SPECIFIER = advancedSecurityPlugin.name;
9864
-
9865
- var plugin = /*#__PURE__*/Object.freeze({
9866
- __proto__: null,
9867
- ADVANCED_SECURITY_PLUGIN_SPECIFIER: ADVANCED_SECURITY_PLUGIN_SPECIFIER,
9868
- default: advancedSecurityPlugin,
9869
- registerAdvancedSecurityPluginFactories: registerAdvancedSecurityPluginFactories
9870
- });
9871
-
9872
9881
  exports.ADVANCED_EDDSA_ENVELOPE_SIGNER_FACTORY_META = FACTORY_META$9;
9873
9882
  exports.ADVANCED_EDDSA_ENVELOPE_VERIFIER_FACTORY_META = FACTORY_META$8;
9874
9883
  exports.ADVANCED_WELCOME_FACTORY_META = FACTORY_META$4;