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