@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,8 +1,9 @@
1
+ import { ExtensionManager, Registry, AbstractResourceFactory, createResource, createDefaultResource } from '@naylence/factory';
2
+ import { getLogger, ENCRYPTION_MANAGER_FACTORY_BASE_TYPE, 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 as TrustStoreProviderFactory$1, 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, formatTimestamp, AnsiColor, jsonDumps, validateHostLogicals, HTTP_CONNECTION_GRANT_TYPE, WELCOME_SERVICE_FACTORY_BASE_TYPE, WelcomeServiceFactory, NodePlacementStrategyFactory, TransportProvisionerFactory, TokenIssuerFactory, AuthorizerFactory, AuthInjectionStrategyFactory, CERTIFICATE_MANAGER_FACTORY_BASE_TYPE, CertificateManagerFactory, TRUST_STORE_PROVIDER_FACTORY_BASE_TYPE as TRUST_STORE_PROVIDER_FACTORY_BASE_TYPE$1, validateHostLogical } from '@naylence/runtime';
1
3
  import { AsnConvert, OctetString } from '@peculiar/asn1-schema';
2
4
  import { Certificate, id_ce_subjectAltName, SubjectAlternativeName, id_ce_nameConstraints, NameConstraints, Name, RelativeDistinguishedName, AttributeTypeAndValue, AttributeValue, SubjectPublicKeyInfo, GeneralName, Extensions, Extension, Attribute, AlgorithmIdentifier, TBSCertificate, Validity, Version, BasicConstraints, id_ce_basicConstraints, KeyUsageFlags, KeyUsage, id_ce_keyUsage, SubjectKeyIdentifier, id_ce_subjectKeyIdentifier, AuthorityKeyIdentifier, KeyIdentifier, id_ce_authorityKeyIdentifier, GeneralSubtrees, GeneralSubtree, ExtendedKeyUsage, id_kp_clientAuth, id_kp_serverAuth, id_ce_extKeyUsage } from '@peculiar/asn1-x509';
3
5
  import { sha512, sha256 } from '@noble/hashes/sha2.js';
4
6
  import { verify, etc } from '@noble/ed25519';
5
- import { getLogger, EncryptionResult, urlsafeBase64Decode, sealedDecrypt, sealedEncrypt, FIXED_PREFIX_LEN, urlsafeBase64Encode, ENCRYPTION_MANAGER_FACTORY_BASE_TYPE, 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 as TrustStoreProviderFactory$1, 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, formatTimestamp, AnsiColor, jsonDumps, validateHostLogicals, HTTP_CONNECTION_GRANT_TYPE, WELCOME_SERVICE_FACTORY_BASE_TYPE, WelcomeServiceFactory, NodePlacementStrategyFactory, TransportProvisionerFactory, TokenIssuerFactory, AuthorizerFactory, AuthInjectionStrategyFactory, CERTIFICATE_MANAGER_FACTORY_BASE_TYPE, CertificateManagerFactory, TRUST_STORE_PROVIDER_FACTORY_BASE_TYPE as TRUST_STORE_PROVIDER_FACTORY_BASE_TYPE$1, validateHostLogical } from '@naylence/runtime';
6
7
  import { Attributes, CertificationRequestInfo, CertificationRequest } from '@peculiar/asn1-csr';
7
8
  import { X509Certificate } from '@peculiar/x509';
8
9
  import { localDeliveryContext, createFameEnvelope, FameAddress, generateId, formatAddress, SigningMaterial, DeliveryOriginType as DeliveryOriginType$1 } from '@naylence/core';
@@ -11,603 +12,1130 @@ import { x25519 } from '@noble/curves/ed25519.js';
11
12
  import { hkdf } from '@noble/hashes/hkdf.js';
12
13
  import { utf8ToBytes, randomBytes as randomBytes$1 } from '@noble/hashes/utils.js';
13
14
  import { SignJWT, importPKCS8, compactVerify, importJWK, importSPKI } from 'jose';
14
- import { ExtensionManager, Registry, AbstractResourceFactory, createResource, createDefaultResource } from '@naylence/factory';
15
15
  import { sha256 as sha256$1 } from '@noble/hashes/sha256.js';
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
+ function registerEncryptionManagerFactory(factory) {
217
+ globalRegistry.registerFactory(factory);
218
+ }
219
+
220
+ const SECURITY_PREFIX = "./security/";
221
+ const SECURITY_MODULES = MODULES.filter((spec) => spec.startsWith(SECURITY_PREFIX));
222
+ const EXTRA_MODULES = MODULES.filter((spec) => !spec.startsWith(SECURITY_PREFIX));
223
+ const NODE_ONLY_MODULES = new Set([
224
+ "./security/cert/default-ca-service-factory.js",
225
+ "./security/cert/trust-store/node-trust-store-provider-factory.js",
226
+ ]);
227
+ const FACTORY_MODULE_PREFIX$1 = "@naylence/advanced-security/naylence/fame/";
228
+ const BROWSER_DIST_SEGMENT = "/dist/browser/";
229
+ function detectModuleUrl() {
230
+ if (typeof __filename === "string") {
155
231
  try {
156
- certificate = AsnConvert.parse(der, Certificate);
232
+ return __filename.startsWith("file://")
233
+ ? __filename
234
+ : `file://${__filename}`;
157
235
  }
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}`);
236
+ catch {
237
+ // fall through to stack parsing
161
238
  }
162
- parsed.push(createParsedCertificate(certificate, der));
163
- derChunks.push(der);
164
- }
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 [];
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);
187
- }
240
+ try {
241
+ throw new Error();
188
242
  }
189
- return uris;
190
- }
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(", ")}`);
243
+ catch (error) {
244
+ const stack = typeof error === "object" && error && "stack" in error
245
+ ? String(error.stack ?? "")
246
+ : "";
247
+ const lines = stack.split("\n");
248
+ for (const line of lines) {
249
+ const match = line.match(/(https?:\/\/[^\s)]+|file:\/\/[^\s)]+\.(?:js|ts)|\/(?:[^\s)]+\.(?:js|ts)))/u);
250
+ const candidate = match?.[1];
251
+ if (!candidate) {
252
+ continue;
253
+ }
254
+ if (candidate.startsWith("http://") || candidate.startsWith("https://")) {
255
+ return candidate;
256
+ }
257
+ if (candidate.startsWith("file://")) {
258
+ return candidate;
209
259
  }
260
+ return `file://${candidate}`;
210
261
  }
211
262
  }
263
+ return null;
212
264
  }
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);
219
- }
265
+ function computeBrowserFactoryBase(rawUrl) {
266
+ if (!rawUrl) {
267
+ return null;
220
268
  }
221
- return uris;
222
- }
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");
269
+ const sanitized = rawUrl.split("?")[0]?.split("#")[0] ?? rawUrl;
270
+ const esmMarker = "/dist/esm/naylence/fame/";
271
+ const distMarker = "/dist/";
272
+ if (sanitized.includes(esmMarker)) {
273
+ return sanitized.slice(0, sanitized.indexOf(esmMarker) + esmMarker.length);
227
274
  }
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
- }
275
+ if (rawUrl.includes(BROWSER_DIST_SEGMENT)) {
276
+ return new URL("../esm/naylence/fame/", rawUrl).href;
250
277
  }
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
- });
261
- return;
262
- }
278
+ if (sanitized.includes(BROWSER_DIST_SEGMENT)) {
279
+ const base = sanitized.slice(0, sanitized.indexOf(BROWSER_DIST_SEGMENT) + BROWSER_DIST_SEGMENT.length);
280
+ return `${base.replace(/browser\/?$/u, "")}esm/naylence/fame/`;
263
281
  }
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
- }
277
- }
282
+ if (sanitized.includes(distMarker)) {
283
+ const index = sanitized.indexOf(distMarker);
284
+ const base = sanitized.slice(0, index + distMarker.length);
285
+ return `${base}esm/naylence/fame/`;
278
286
  }
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) {
287
+ const srcMarker = "/src/naylence/fame/";
288
+ if (sanitized.includes(srcMarker)) {
289
+ const index = sanitized.indexOf(srcMarker);
290
+ const projectRoot = sanitized.slice(0, index);
291
+ return `${projectRoot}/dist/esm/naylence/fame/`;
292
+ }
293
+ if (sanitized.startsWith("http://") || sanitized.startsWith("https://")) {
294
294
  try {
295
- const der = decodeBase64$2(block);
296
- const certificate = AsnConvert.parse(der, Certificate);
297
- parsed.push(createParsedCertificate(certificate, der));
295
+ const parsed = new URL(rawUrl);
296
+ const viteDepsSegment = "/node_modules/.vite/deps/";
297
+ if (parsed.pathname.includes(viteDepsSegment)) {
298
+ const baseOrigin = `${parsed.protocol}//${parsed.host}`;
299
+ return `${baseOrigin}/node_modules/@naylence/advanced-security/dist/esm/naylence/fame/`;
300
+ }
298
301
  }
299
- catch (error) {
300
- const reason = error instanceof Error ? error.message : String(error);
301
- logger$h.debug("trust_store_certificate_parse_failed", { reason });
302
+ catch {
303
+ // ignore
302
304
  }
303
305
  }
304
- return parsed;
306
+ return null;
305
307
  }
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, ""));
308
+ const moduleUrl = detectModuleUrl();
309
+ const browserFactoryBase = computeBrowserFactoryBase(moduleUrl);
310
+ const prefersSource = typeof moduleUrl === "string" && moduleUrl.includes("/src/");
311
+ function resolveFactoryModuleSpecifier$1(specifier) {
312
+ if (specifier.startsWith("../")) {
313
+ return `${FACTORY_MODULE_PREFIX$1}${specifier.slice("../".length)}`;
314
314
  }
315
- return blocks;
316
- }
317
- function validateChainContinuity(chain) {
318
- if (chain.length <= 1) {
319
- return;
315
+ if (specifier.startsWith("./")) {
316
+ return `${FACTORY_MODULE_PREFIX$1}${specifier.slice("./".length)}`;
320
317
  }
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`);
318
+ return null;
319
+ }
320
+ function resolveModuleCandidates(spec) {
321
+ const candidates = [];
322
+ const seen = new Set();
323
+ const addCandidate = (candidate) => {
324
+ if (!candidate) {
325
+ return;
326
+ }
327
+ if (!seen.has(candidate)) {
328
+ seen.add(candidate);
329
+ candidates.push(candidate);
330
+ }
331
+ };
332
+ if (prefersSource && spec.startsWith("./")) {
333
+ const sourceCandidate = `../${spec.slice(2)}`;
334
+ addCandidate(sourceCandidate);
335
+ if (sourceCandidate.endsWith(".js")) {
336
+ addCandidate(sourceCandidate.replace(/\.js$/u, ".ts"));
334
337
  }
338
+ }
339
+ if (browserFactoryBase && spec.startsWith("./")) {
335
340
  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
- });
341
+ const browserCandidate = new URL(spec.slice("./".length), browserFactoryBase).href;
342
+ addCandidate(browserCandidate);
343
+ if (browserCandidate.endsWith(".js")) {
344
+ addCandidate(browserCandidate.replace(/\.js$/u, ".ts"));
345
+ }
342
346
  }
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}`);
347
+ catch {
348
+ // ignore resolution failures for browser base
355
349
  }
356
350
  }
357
- logger$h.debug("chain_continuity_validation_passed", {
358
- chain_length: chain.length,
359
- });
360
- }
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})`);
351
+ const packageCandidate = resolveFactoryModuleSpecifier$1(spec);
352
+ addCandidate(packageCandidate);
353
+ if (packageCandidate?.endsWith(".js")) {
354
+ addCandidate(packageCandidate.replace(/\.js$/u, ".ts"));
367
355
  }
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");
356
+ const fallback = spec.startsWith("./") ? `../${spec.slice(2)}` : spec;
357
+ addCandidate(fallback);
358
+ if (fallback.endsWith(".js")) {
359
+ addCandidate(fallback.replace(/\.js$/u, ".ts"));
373
360
  }
374
- const valid = verify(signatureBytes, tbsBytes, issuerKey);
375
- if (!valid) {
376
- throw new Error("Certificate signature verification failed");
361
+ addCandidate(spec);
362
+ if (spec.endsWith(".js")) {
363
+ addCandidate(spec.replace(/\.js$/u, ".ts"));
377
364
  }
365
+ return candidates;
378
366
  }
379
- function ensureEd25519Support() {
380
- const etcPatch = etc;
381
- if (!etcPatch.sha512) {
382
- etcPatch.sha512 = (message) => sha512(message);
367
+ const registeredModules = new Set();
368
+ const inflightModules = new Map();
369
+ const browserSkippedModules = new Set();
370
+ function isNodeEnvironment$5() {
371
+ return (typeof process !== "undefined" &&
372
+ typeof process.release !== "undefined" &&
373
+ process.release?.name === "node");
374
+ }
375
+ function shouldSkipModule(spec) {
376
+ if (isNodeEnvironment$5()) {
377
+ return false;
383
378
  }
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
- };
379
+ if (!NODE_ONLY_MODULES.has(spec)) {
380
+ return false;
381
+ }
382
+ if (!browserSkippedModules.has(spec)) {
383
+ // console.warn(
384
+ // "[advanced-security:factory-manifest] skipped browser-incompatible module",
385
+ // spec,
386
+ // );
387
+ browserSkippedModules.add(spec);
392
388
  }
389
+ return true;
393
390
  }
394
- function findExtension(certificate, oid) {
395
- const extensions = certificate.tbsCertificate.extensions;
396
- if (!extensions) {
391
+ function getDynamicImporter() {
392
+ if (typeof globalThis === "undefined") {
397
393
  return null;
398
394
  }
399
- for (const extension of extensions) {
400
- if (extension.extnID === oid) {
401
- return extension;
402
- }
395
+ const candidate = globalThis.__naylenceFactoryDynamicImporter;
396
+ if (typeof candidate === "function") {
397
+ return candidate;
403
398
  }
404
399
  return null;
405
400
  }
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;
401
+ async function registerModule(spec, registrar) {
402
+ const candidates = resolveModuleCandidates(spec);
403
+ const dynamicImporter = getDynamicImporter();
404
+ const loader = dynamicImporter
405
+ ? (specifier) => dynamicImporter(specifier)
406
+ : (specifier) => import(/* @vite-ignore */ specifier);
407
+ const attempts = [];
408
+ const staticLoader = MODULE_LOADERS?.[spec];
409
+ if (staticLoader) {
410
+ attempts.push({ load: () => staticLoader(), candidate: spec });
411
411
  }
412
- for (let i = 0; i < left.length; i += 1) {
413
- if (left[i] !== right[i]) {
412
+ for (const candidate of candidates) {
413
+ attempts.push({ load: () => loader(candidate), candidate });
414
+ }
415
+ const registerFromModule = (mod) => {
416
+ const meta = mod.FACTORY_META;
417
+ const Ctor = mod.default;
418
+ if (!meta?.base || !meta?.key || typeof Ctor !== "function") {
419
+ console.warn("[debug] invalid factory module", spec, {
420
+ meta,
421
+ hasCtor: typeof Ctor === "function",
422
+ });
423
+ console.warn("[advanced-security:factory-manifest] skipped", spec, "— missing FACTORY_META or default export ctor");
414
424
  return false;
415
425
  }
426
+ const { base, key, ...metadata } = meta;
427
+ const extraMetadata = Object.keys(metadata).length > 0 ? metadata : undefined;
428
+ // console.log("[debug] registering module", { spec, base, key, metadata: extraMetadata });
429
+ registrar.registerFactory(base, key, Ctor, extraMetadata);
430
+ return true;
431
+ };
432
+ for (const [index, { candidate, load }] of attempts.entries()) {
433
+ try {
434
+ const mod = await load();
435
+ return registerFromModule(mod);
436
+ }
437
+ catch (error) {
438
+ const message = error instanceof Error ? error.message : String(error);
439
+ const moduleNotFound = message.includes("Cannot find module") ||
440
+ message.includes("ERR_MODULE_NOT_FOUND") ||
441
+ message.includes("Unknown file extension") ||
442
+ message.includes("Failed to fetch dynamically imported module") ||
443
+ message.includes("Failed to resolve module specifier") ||
444
+ message.includes("Importing a module script failed");
445
+ const isLastAttempt = index === attempts.length - 1;
446
+ if (!moduleNotFound || isLastAttempt) {
447
+ console.warn("[debug] failed to import candidate", {
448
+ spec,
449
+ candidate,
450
+ message,
451
+ });
452
+ console.warn("[advanced-security:factory-manifest] skipped", spec, "-", message);
453
+ return false;
454
+ }
455
+ }
416
456
  }
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(",");
457
+ return false;
426
458
  }
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;
459
+ async function registerModuleOnce(spec, registrar) {
460
+ if (registeredModules.has(spec)) {
461
+ return false;
443
462
  }
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;
463
+ const inflight = inflightModules.get(spec);
464
+ if (inflight) {
465
+ return inflight;
466
+ }
467
+ const registration = (async () => {
468
+ const registered = await registerModule(spec, registrar);
469
+ if (registered) {
470
+ registeredModules.add(spec);
471
+ }
472
+ return registered;
473
+ })();
474
+ inflightModules.set(spec, registration);
475
+ try {
476
+ return await registration;
477
+ }
478
+ finally {
479
+ inflightModules.delete(spec);
452
480
  }
453
- return result;
454
481
  }
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"));
482
+ async function registerModules(modules, registrar) {
483
+ if (modules.length === 0) {
484
+ return 0;
459
485
  }
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;
486
+ const eligibleModules = modules.filter((spec) => !shouldSkipModule(spec));
487
+ if (eligibleModules.length === 0) {
488
+ return 0;
468
489
  }
469
- throw new Error("No base64 decoder available in this environment");
490
+ const results = await Promise.all(eligibleModules.map((spec) => registerModuleOnce(spec, registrar)));
491
+ return results.reduce((count, registered) => (registered ? count + 1 : count), 0);
470
492
  }
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;
493
+ async function registerAdvancedSecurityFactories(registrar = Registry, options) {
494
+ const newlyRegisteredSecurity = await registerModules(SECURITY_MODULES, registrar);
495
+ if (newlyRegisteredSecurity > 0) {
496
+ getEncryptionManagerFactoryRegistry().forceRediscovery();
488
497
  }
489
- if (Date.now() > entry.expiresAt) {
490
- trustCache.delete(cacheKey);
491
- logger$h.debug("certificate_cache_expired", { cache_key: cacheKey });
492
- return null;
498
+ if (options?.includeExtras === true) {
499
+ await registerModules(EXTRA_MODULES, registrar);
493
500
  }
494
- return entry.value.slice();
495
501
  }
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;
502
+
503
+ // This file is auto-generated during build - do not edit manually
504
+ // Generated from package.json version: 0.3.15
505
+ /**
506
+ * The package version, injected at build time.
507
+ * @internal
508
+ */
509
+ const VERSION = '0.3.15';
510
+
511
+ async function registerAdvancedSecurityPluginFactories(registrar = Registry) {
512
+ await registerAdvancedSecurityFactories(registrar, { includeExtras: true });
513
+ }
514
+ let initialized = false;
515
+ let initializing = null;
516
+ const advancedSecurityPlugin = {
517
+ name: "naylence:advanced-security",
518
+ version: VERSION,
519
+ async register() {
520
+ // console.log('[naylence:advanced-security] register() called, initialized=', initialized);
521
+ if (initialized) {
522
+ // console.log('[naylence:advanced-security] already initialized, skipping');
523
+ return;
501
524
  }
502
- trustCache.delete(firstKey);
503
- logger$h.debug("certificate_cache_evicted", { cache_key: firstKey });
525
+ if (initializing) {
526
+ console.log("[naylence:advanced-security] already initializing, awaiting...");
527
+ await initializing;
528
+ return;
529
+ }
530
+ initializing = (async () => {
531
+ try {
532
+ // console.log('[naylence:advanced-security] registering advanced security factories...');
533
+ await registerAdvancedSecurityPluginFactories();
534
+ // console.log('[naylence:advanced-security] advanced security factories registered');
535
+ initialized = true;
536
+ }
537
+ finally {
538
+ initializing = null;
539
+ }
540
+ })();
541
+ await initializing;
542
+ },
543
+ };
544
+ const ADVANCED_SECURITY_PLUGIN_SPECIFIER = advancedSecurityPlugin.name;
545
+
546
+ var plugin = /*#__PURE__*/Object.freeze({
547
+ __proto__: null,
548
+ ADVANCED_SECURITY_PLUGIN_SPECIFIER: ADVANCED_SECURITY_PLUGIN_SPECIFIER,
549
+ default: advancedSecurityPlugin,
550
+ registerAdvancedSecurityPluginFactories: registerAdvancedSecurityPluginFactories
551
+ });
552
+
553
+ const logger$g = getLogger("naylence.fame.security.cert.util");
554
+ const CACHE_LIMIT = 512;
555
+ const OID_ED25519 = "1.3.101.112";
556
+ const textEncoder = new TextEncoder();
557
+ const trustCache = new Map();
558
+ function publicKeyFromX5c(x5c, options = {}) {
559
+ if (!Array.isArray(x5c) || x5c.length === 0) {
560
+ throw new Error("Empty certificate chain");
504
561
  }
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,
562
+ const callId = generateCallId();
563
+ const enforceNameConstraints = options.enforceNameConstraints ?? true;
564
+ const trustStorePem = normalizeTrustStoreOption(options.trustStorePem ?? null);
565
+ const returnCertificate = options.returnCertificate ?? false;
566
+ const { parsed, chainBytes } = parseCertificateChain(x5c);
567
+ logger$g.debug("public_key_from_x5c_called", {
568
+ call_id: callId,
569
+ x5c_count: parsed.length,
570
+ enforce_name_constraints: enforceNameConstraints,
571
+ has_trust_store: Boolean(trustStorePem),
572
+ return_cert: returnCertificate,
513
573
  });
514
- }
515
- function normalizeTrustStoreOption(value) {
516
- if (!value) {
517
- return null;
574
+ let cacheKey = null;
575
+ if (!returnCertificate) {
576
+ cacheKey = buildCacheKey(chainBytes, trustStorePem, enforceNameConstraints);
577
+ const cached = getCachedPublicKey(cacheKey);
578
+ if (cached) {
579
+ logger$g.debug("certificate_cache_hit", {
580
+ call_id: callId,
581
+ cache_key: cacheKey,
582
+ });
583
+ return cached;
584
+ }
585
+ logger$g.debug("certificate_cache_miss", {
586
+ call_id: callId,
587
+ cache_key: cacheKey,
588
+ });
518
589
  }
519
- const trimmed = value.trim();
520
- if (trimmed.length === 0) {
521
- return null;
590
+ const validation = validateCertificateChain(parsed, enforceNameConstraints, trustStorePem);
591
+ if (cacheKey) {
592
+ setCachedPublicKey(cacheKey, validation.publicKey, validation.notAfter);
522
593
  }
523
- if (!trimmed.includes("-----BEGIN CERTIFICATE-----")) {
524
- throw new Error("trustStorePem must contain PEM-encoded certificates when provided");
594
+ if (returnCertificate) {
595
+ return {
596
+ publicKey: validation.publicKey.slice(),
597
+ certificate: validation.certificate,
598
+ };
525
599
  }
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);
600
+ return validation.publicKey.slice();
533
601
  }
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");
602
+ function validateJwkX5cCertificate(options) {
603
+ const { jwk, trustStorePem = null, enforceNameConstraints = true, strict = true, } = options;
604
+ if (!jwk || typeof jwk !== "object") {
605
+ const error = "Invalid JWK object";
606
+ if (strict) {
607
+ throw new Error(error);
608
+ }
609
+ return { isValid: false, error };
544
610
  }
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");
611
+ const x5c = jwk.x5c;
612
+ if (x5c === undefined) {
613
+ return { isValid: true };
550
614
  }
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");
615
+ if (!Array.isArray(x5c) ||
616
+ x5c.length === 0 ||
617
+ x5c.some((entry) => typeof entry !== "string")) {
618
+ const error = "Invalid x5c field in JWK";
619
+ if (strict) {
620
+ throw new Error(error);
621
+ }
622
+ return { isValid: false, error };
564
623
  }
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);
624
+ try {
625
+ publicKeyFromX5c(x5c, {
626
+ trustStorePem,
627
+ enforceNameConstraints,
628
+ });
629
+ return { isValid: true };
570
630
  }
571
- if (typeof globalThis.btoa !== "function") {
572
- throw new Error("Base64 encoding not available in this environment");
631
+ catch (error) {
632
+ const message = error instanceof Error ? error.message : String(error ?? "unknown");
633
+ const normalized = `Certificate validation failed: ${message}`;
634
+ if (strict) {
635
+ throw new Error(normalized);
636
+ }
637
+ return { isValid: false, error: normalized };
573
638
  }
574
- return globalThis.btoa(binary);
575
639
  }
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));
640
+ function validateCertificateChain(parsed, enforceNameConstraints, trustStorePem) {
641
+ const leaf = parsed[0];
642
+ const nowMs = Date.now();
643
+ const notBefore = leaf.certificate.tbsCertificate.validity.notBefore.getTime();
644
+ const notAfter = leaf.certificate.tbsCertificate.validity.notAfter.getTime();
645
+ const notBeforeMs = notBefore.getTime();
646
+ const notAfterMs = notAfter.getTime();
647
+ if (nowMs < notBeforeMs || nowMs > notAfterMs) {
648
+ throw new Error(`Certificate is not currently valid (notBefore: ${notBefore.toISOString()}, notAfter: ${notAfter.toISOString()}, now: ${new Date(nowMs).toISOString()})`);
581
649
  }
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'");
650
+ const issuers = parsed.slice(1);
651
+ if (enforceNameConstraints && issuers.length > 0) {
652
+ const leafUris = extractUrisFromCert(leaf.certificate);
653
+ validateNameConstraints(issuers, leafUris);
589
654
  }
590
- if (!(publicKey instanceof CryptoKey) || publicKey.type !== "public") {
591
- throw new Error("publicKey must be a CryptoKey of type 'public'");
655
+ if (trustStorePem) {
656
+ validateTrustAnchor(parsed, trustStorePem);
592
657
  }
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,
610
- extnValue: new OctetString(AsnConvert.serialize(san)),
658
+ validateChainContinuity(parsed);
659
+ const publicKey = leaf.subjectPublicKey.slice();
660
+ return {
661
+ publicKey,
662
+ certificate: leaf.certificate,
663
+ notAfter,
664
+ };
665
+ }
666
+ function parseCertificateChain(x5c) {
667
+ const parsed = [];
668
+ const derChunks = [];
669
+ for (let index = 0; index < x5c.length; index += 1) {
670
+ const entry = x5c[index];
671
+ if (typeof entry !== "string" || entry.trim().length === 0) {
672
+ throw new Error(`Invalid certificate at index ${index}`);
673
+ }
674
+ let der;
675
+ try {
676
+ der = decodeBase64$2(entry);
677
+ }
678
+ catch (error) {
679
+ const reason = error instanceof Error ? error.message : String(error);
680
+ throw new Error(`Failed to decode certificate at index ${index}: ${reason}`);
681
+ }
682
+ let certificate;
683
+ try {
684
+ certificate = AsnConvert.parse(der, Certificate);
685
+ }
686
+ catch (error) {
687
+ const reason = error instanceof Error ? error.message : String(error);
688
+ throw new Error(`Failed to parse certificate at index ${index}: ${reason}`);
689
+ }
690
+ parsed.push(createParsedCertificate(certificate, der));
691
+ derChunks.push(der);
692
+ }
693
+ return { parsed, chainBytes: concatBytes(derChunks) };
694
+ }
695
+ function createParsedCertificate(certificate, raw) {
696
+ return {
697
+ raw,
698
+ certificate,
699
+ serialNumber: toHex(new Uint8Array(certificate.tbsCertificate.serialNumber)).toUpperCase(),
700
+ subjectName: serializeName(certificate.tbsCertificate.subject),
701
+ issuerName: serializeName(certificate.tbsCertificate.issuer),
702
+ subjectPublicKey: new Uint8Array(certificate.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey).slice(),
703
+ };
704
+ }
705
+ function extractUrisFromCert(cert) {
706
+ const extension = findExtension(cert, id_ce_subjectAltName);
707
+ if (!extension) {
708
+ return [];
709
+ }
710
+ const subjectAlternativeName = AsnConvert.parse(extension.extnValue.buffer, SubjectAlternativeName);
711
+ const uris = [];
712
+ for (const generalName of subjectAlternativeName) {
713
+ if (generalName.uniformResourceIdentifier) {
714
+ uris.push(generalName.uniformResourceIdentifier);
715
+ }
716
+ }
717
+ return uris;
718
+ }
719
+ function validateNameConstraints(issuers, leafUris) {
720
+ for (const issuer of issuers) {
721
+ const extension = findExtension(issuer.certificate, id_ce_nameConstraints);
722
+ if (!extension) {
723
+ continue;
724
+ }
725
+ const constraints = AsnConvert.parse(extension.extnValue.buffer, NameConstraints);
726
+ if (!constraints.permittedSubtrees) {
727
+ continue;
728
+ }
729
+ const permittedUris = collectPermittedUris(Array.from(constraints.permittedSubtrees));
730
+ if (permittedUris.length === 0) {
731
+ continue;
732
+ }
733
+ for (const uri of leafUris) {
734
+ const allowed = permittedUris.some((prefix) => uri.startsWith(prefix));
735
+ if (!allowed) {
736
+ throw new Error(`URI '${uri}' violates name constraints - not in permitted subtrees: ${permittedUris.join(", ")}`);
737
+ }
738
+ }
739
+ }
740
+ }
741
+ function collectPermittedUris(subtrees) {
742
+ const uris = [];
743
+ for (const subtree of subtrees) {
744
+ if (subtree.base.uniformResourceIdentifier &&
745
+ subtree.base.uniformResourceIdentifier.length > 0) {
746
+ uris.push(subtree.base.uniformResourceIdentifier);
747
+ }
748
+ }
749
+ return uris;
750
+ }
751
+ function validateTrustAnchor(chain, trustStorePem) {
752
+ const trustedCerts = parseTrustStore(trustStorePem);
753
+ if (trustedCerts.length === 0) {
754
+ throw new Error("No valid certificates found in trust store");
755
+ }
756
+ logger$g.debug("trust_anchor_validation_start", {
757
+ chain_length: chain.length,
758
+ trust_store_cert_count: trustedCerts.length,
759
+ });
760
+ const chainInfo = chain.map((cert, index) => `[${index}] ${cert.subjectName} (Serial: ${cert.serialNumber})`);
761
+ const trustedInfo = trustedCerts.map((cert, index) => `[${index}] ${cert.subjectName} (Serial: ${cert.serialNumber})`);
762
+ logger$g.debug("certificate_chain_validation", {
763
+ chain_certificates: chainInfo,
764
+ trust_store_certificates: trustedInfo,
765
+ });
766
+ // Strategy 1: direct trust (exact certificate match)
767
+ for (let i = 0; i < chain.length; i += 1) {
768
+ const cert = chain[i];
769
+ const match = trustedCerts.find((trusted) => trusted.serialNumber === cert.serialNumber &&
770
+ namesEqual(trusted.certificate.tbsCertificate.subject, cert.certificate.tbsCertificate.subject));
771
+ if (match) {
772
+ logger$g.debug("certificate_chain_trust_validation_passed", {
773
+ matching_serial: match.serialNumber,
774
+ validation_strategy: `direct_trust_cert_${i}`,
775
+ });
776
+ return;
777
+ }
778
+ }
779
+ const leaf = chain[0];
780
+ // Strategy 2: leaf issuer in trust store
781
+ for (const trusted of trustedCerts) {
782
+ if (namesEqual(trusted.certificate.tbsCertificate.subject, leaf.certificate.tbsCertificate.issuer) &&
783
+ trusted.serialNumber !== leaf.serialNumber) {
784
+ verifyCertificateSignature(leaf.certificate, trusted.certificate);
785
+ logger$g.debug("certificate_chain_trust_validation_passed", {
786
+ matching_serial: trusted.serialNumber,
787
+ validation_strategy: "leaf_issuer_trust",
788
+ });
789
+ return;
790
+ }
791
+ }
792
+ // Strategy 3: any intermediate issuer in trust store
793
+ for (let index = 1; index < chain.length; index += 1) {
794
+ const intermediate = chain[index];
795
+ for (const trusted of trustedCerts) {
796
+ if (namesEqual(trusted.certificate.tbsCertificate.subject, intermediate.certificate.tbsCertificate.issuer) &&
797
+ trusted.serialNumber !== intermediate.serialNumber) {
798
+ verifyCertificateSignature(intermediate.certificate, trusted.certificate);
799
+ logger$g.debug("certificate_chain_trust_validation_passed", {
800
+ matching_serial: trusted.serialNumber,
801
+ validation_strategy: `intermediate_issuer_trust_cert_${index}`,
802
+ });
803
+ return;
804
+ }
805
+ }
806
+ }
807
+ logger$g.warning("certificate_chain_trust_validation_failed", {
808
+ leaf_subject: leaf.subjectName,
809
+ leaf_issuer: leaf.issuerName,
810
+ leaf_serial: leaf.serialNumber,
811
+ trusted_certificates: trustedInfo,
812
+ chain_certificates: chainInfo,
813
+ reason: "no_matching_trust_anchor",
814
+ });
815
+ throw new Error("Certificate chain is not rooted in a trusted anchor");
816
+ }
817
+ function parseTrustStore(trustStorePem) {
818
+ const normalized = normalizePem$2(trustStorePem);
819
+ const blocks = extractPemBlocks$1(normalized);
820
+ const parsed = [];
821
+ for (const block of blocks) {
822
+ try {
823
+ const der = decodeBase64$2(block);
824
+ const certificate = AsnConvert.parse(der, Certificate);
825
+ parsed.push(createParsedCertificate(certificate, der));
826
+ }
827
+ catch (error) {
828
+ const reason = error instanceof Error ? error.message : String(error);
829
+ logger$g.debug("trust_store_certificate_parse_failed", { reason });
830
+ }
831
+ }
832
+ return parsed;
833
+ }
834
+ function extractPemBlocks$1(pem) {
835
+ const blocks = [];
836
+ const regex = /-----BEGIN CERTIFICATE-----([\s\S]*?)-----END CERTIFICATE-----/gu;
837
+ let match;
838
+ // eslint-disable-next-line no-cond-assign
839
+ while ((match = regex.exec(pem)) !== null) {
840
+ const body = match[1] ?? "";
841
+ blocks.push(body.replace(/\s+/gu, ""));
842
+ }
843
+ return blocks;
844
+ }
845
+ function validateChainContinuity(chain) {
846
+ if (chain.length <= 1) {
847
+ return;
848
+ }
849
+ logger$g.debug("validating_chain_continuity", { chain_length: chain.length });
850
+ for (let index = 0; index < chain.length - 1; index += 1) {
851
+ const cert = chain[index];
852
+ const issuer = chain[index + 1];
853
+ if (!namesEqual(cert.certificate.tbsCertificate.issuer, issuer.certificate.tbsCertificate.subject)) {
854
+ logger$g.warning("certificate_chain_continuity_failed", {
855
+ cert_index: index,
856
+ cert_subject: cert.subjectName,
857
+ cert_issuer: cert.issuerName,
858
+ expected_issuer_subject: issuer.subjectName,
859
+ reason: "issuer_name_mismatch",
860
+ });
861
+ throw new Error(`Certificate chain continuity broken: certificate at index ${index} issuer does not match next certificate subject`);
862
+ }
863
+ try {
864
+ verifyCertificateSignature(cert.certificate, issuer.certificate);
865
+ logger$g.debug("chain_continuity_verification_success", {
866
+ cert_index: index,
867
+ cert_serial: cert.serialNumber,
868
+ issuer_serial: issuer.serialNumber,
869
+ });
870
+ }
871
+ catch (error) {
872
+ const reason = error instanceof Error ? error.message : String(error);
873
+ logger$g.warning("certificate_chain_continuity_failed", {
874
+ cert_index: index,
875
+ cert_subject: cert.subjectName,
876
+ issuer_subject: issuer.subjectName,
877
+ cert_serial: cert.serialNumber,
878
+ issuer_serial: issuer.serialNumber,
879
+ error: reason,
880
+ reason: "signature_verification_failed",
881
+ });
882
+ throw new Error(`Certificate chain continuity broken: certificate at index ${index} was not signed by certificate at index ${index + 1}: ${reason}`);
883
+ }
884
+ }
885
+ logger$g.debug("chain_continuity_validation_passed", {
886
+ chain_length: chain.length,
887
+ });
888
+ }
889
+ function verifyCertificateSignature(certificate, issuer) {
890
+ ensureEd25519Support();
891
+ const signatureAlgorithm = certificate.signatureAlgorithm.algorithm;
892
+ const issuerAlgorithm = issuer.tbsCertificate.subjectPublicKeyInfo.algorithm.algorithm;
893
+ if (signatureAlgorithm !== OID_ED25519 || issuerAlgorithm !== OID_ED25519) {
894
+ throw new Error(`Unsupported signature algorithm (certificate: ${signatureAlgorithm}, issuer: ${issuerAlgorithm})`);
895
+ }
896
+ const signatureBytes = new Uint8Array(certificate.signatureValue);
897
+ const tbsBytes = new Uint8Array(AsnConvert.serialize(certificate.tbsCertificate));
898
+ const issuerKey = new Uint8Array(issuer.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey);
899
+ if (issuerKey.length !== 32) {
900
+ throw new Error("Issuer Ed25519 public key must be 32 bytes");
901
+ }
902
+ const valid = verify(signatureBytes, tbsBytes, issuerKey);
903
+ if (!valid) {
904
+ throw new Error("Certificate signature verification failed");
905
+ }
906
+ }
907
+ function ensureEd25519Support() {
908
+ const etcPatch = etc;
909
+ if (!etcPatch.sha512) {
910
+ etcPatch.sha512 = (message) => sha512(message);
911
+ }
912
+ if (!etcPatch.sha512Sync) {
913
+ etcPatch.sha512Sync = (...messages) => {
914
+ if (messages.length === 1) {
915
+ return sha512(messages[0]);
916
+ }
917
+ const combined = etc.concatBytes(...messages);
918
+ return sha512(combined);
919
+ };
920
+ }
921
+ }
922
+ function findExtension(certificate, oid) {
923
+ const extensions = certificate.tbsCertificate.extensions;
924
+ if (!extensions) {
925
+ return null;
926
+ }
927
+ for (const extension of extensions) {
928
+ if (extension.extnID === oid) {
929
+ return extension;
930
+ }
931
+ }
932
+ return null;
933
+ }
934
+ function namesEqual(a, b) {
935
+ const left = new Uint8Array(AsnConvert.serialize(a));
936
+ const right = new Uint8Array(AsnConvert.serialize(b));
937
+ if (left.length !== right.length) {
938
+ return false;
939
+ }
940
+ for (let i = 0; i < left.length; i += 1) {
941
+ if (left[i] !== right[i]) {
942
+ return false;
943
+ }
944
+ }
945
+ return true;
946
+ }
947
+ function serializeName(name) {
948
+ const rdns = Array.from(name);
949
+ return rdns
950
+ .map((rdn) => Array.from(rdn)
951
+ .map((attr) => `${oidToLabel$1(attr.type)}=${attr.value.toString()}`)
952
+ .join("+"))
953
+ .join(",");
954
+ }
955
+ function oidToLabel$1(oid) {
956
+ switch (oid) {
957
+ case "2.5.4.3":
958
+ return "CN";
959
+ case "2.5.4.6":
960
+ return "C";
961
+ case "2.5.4.7":
962
+ return "L";
963
+ case "2.5.4.8":
964
+ return "ST";
965
+ case "2.5.4.10":
966
+ return "O";
967
+ case "2.5.4.11":
968
+ return "OU";
969
+ default:
970
+ return oid;
971
+ }
972
+ }
973
+ function concatBytes(chunks) {
974
+ const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
975
+ const result = new Uint8Array(totalLength);
976
+ let offset = 0;
977
+ for (const chunk of chunks) {
978
+ result.set(chunk, offset);
979
+ offset += chunk.length;
980
+ }
981
+ return result;
982
+ }
983
+ function decodeBase64$2(input) {
984
+ if (typeof Buffer !== "undefined") {
985
+ const normalized = input.replace(/\s+/gu, "");
986
+ return new Uint8Array(Buffer.from(normalized, "base64"));
987
+ }
988
+ if (typeof atob === "function") {
989
+ const normalized = input.replace(/\s+/gu, "");
990
+ const binary = atob(normalized);
991
+ const bytes = new Uint8Array(binary.length);
992
+ for (let i = 0; i < binary.length; i += 1) {
993
+ bytes[i] = binary.charCodeAt(i);
994
+ }
995
+ return bytes;
996
+ }
997
+ throw new Error("No base64 decoder available in this environment");
998
+ }
999
+ function toHex(data) {
1000
+ return Array.from(data)
1001
+ .map((byte) => byte.toString(16).padStart(2, "0"))
1002
+ .join("");
1003
+ }
1004
+ function buildCacheKey(chainBytes, trustStorePem, enforceNameConstraints) {
1005
+ const chainHash = toHex(sha256(chainBytes));
1006
+ const trustHash = trustStorePem
1007
+ ? toHex(sha256(textEncoder.encode(trustStorePem)))
1008
+ : "no-trust";
1009
+ const constraintFlag = enforceNameConstraints ? "nc1" : "nc0";
1010
+ return `${chainHash}|${trustHash}|${constraintFlag}`;
1011
+ }
1012
+ function getCachedPublicKey(cacheKey) {
1013
+ const entry = trustCache.get(cacheKey);
1014
+ if (!entry) {
1015
+ return null;
1016
+ }
1017
+ if (Date.now() > entry.expiresAt) {
1018
+ trustCache.delete(cacheKey);
1019
+ logger$g.debug("certificate_cache_expired", { cache_key: cacheKey });
1020
+ return null;
1021
+ }
1022
+ return entry.value.slice();
1023
+ }
1024
+ function setCachedPublicKey(cacheKey, value, notAfter) {
1025
+ while (trustCache.size >= CACHE_LIMIT) {
1026
+ const firstKey = trustCache.keys().next().value;
1027
+ if (firstKey === undefined) {
1028
+ break;
1029
+ }
1030
+ trustCache.delete(firstKey);
1031
+ logger$g.debug("certificate_cache_evicted", { cache_key: firstKey });
1032
+ }
1033
+ trustCache.set(cacheKey, {
1034
+ value: value.slice(),
1035
+ expiresAt: notAfter.getTime(),
1036
+ });
1037
+ logger$g.debug("certificate_cache_stored", {
1038
+ cache_key: cacheKey,
1039
+ expires_at: notAfter.toISOString(),
1040
+ cache_size: trustCache.size,
1041
+ });
1042
+ }
1043
+ function normalizeTrustStoreOption(value) {
1044
+ if (!value) {
1045
+ return null;
1046
+ }
1047
+ const trimmed = value.trim();
1048
+ if (trimmed.length === 0) {
1049
+ return null;
1050
+ }
1051
+ if (!trimmed.includes("-----BEGIN CERTIFICATE-----")) {
1052
+ throw new Error("trustStorePem must contain PEM-encoded certificates when provided");
1053
+ }
1054
+ return normalizePem$2(trimmed);
1055
+ }
1056
+ function normalizePem$2(pem) {
1057
+ return pem.replace(/\r/gu, "").trim();
1058
+ }
1059
+ function generateCallId() {
1060
+ return Math.random().toString(36).slice(2, 10);
1061
+ }
1062
+
1063
+ const GRANT_PURPOSE_CA_SIGN = "ca_sign";
1064
+
1065
+ const ED25519_OID$2 = "1.3.101.112";
1066
+ const OID_COMMON_NAME$2 = "2.5.4.3";
1067
+ const LOGICAL_URI_PREFIX$1 = "naylence://";
1068
+ function ensureSubtleCrypto() {
1069
+ const instance = globalThis.crypto?.subtle;
1070
+ if (!instance) {
1071
+ throw new Error("WebCrypto subtle API is required to create a CSR");
1072
+ }
1073
+ return instance;
1074
+ }
1075
+ function buildSubject(commonName) {
1076
+ if (!commonName || typeof commonName !== "string") {
1077
+ throw new Error("commonName must be a non-empty string");
1078
+ }
1079
+ return new Name([
1080
+ new RelativeDistinguishedName([
1081
+ new AttributeTypeAndValue({
1082
+ type: OID_COMMON_NAME$2,
1083
+ value: new AttributeValue({ utf8String: commonName }),
1084
+ }),
1085
+ ]),
1086
+ ]);
1087
+ }
1088
+ function arrayBufferToBase64(buffer) {
1089
+ const bytes = new Uint8Array(buffer);
1090
+ if (typeof globalThis.Buffer?.from === "function") {
1091
+ return globalThis.Buffer.from(bytes).toString("base64");
1092
+ }
1093
+ let binary = "";
1094
+ const chunkSize = 0x8000;
1095
+ for (let offset = 0; offset < bytes.length; offset += chunkSize) {
1096
+ const slice = bytes.subarray(offset, offset + chunkSize);
1097
+ binary += String.fromCharCode(...slice);
1098
+ }
1099
+ if (typeof globalThis.btoa !== "function") {
1100
+ throw new Error("Base64 encoding not available in this environment");
1101
+ }
1102
+ return globalThis.btoa(binary);
1103
+ }
1104
+ function derToPem$1(der, label) {
1105
+ const base64 = arrayBufferToBase64(der);
1106
+ const lines = [];
1107
+ for (let index = 0; index < base64.length; index += 64) {
1108
+ lines.push(base64.slice(index, index + 64));
1109
+ }
1110
+ return `-----BEGIN ${label}-----\n${lines.join("\n")}\n-----END ${label}-----\n`;
1111
+ }
1112
+ async function createEd25519Csr(options) {
1113
+ const subtle = ensureSubtleCrypto();
1114
+ const { privateKey, publicKey, commonName } = options;
1115
+ if (!(privateKey instanceof CryptoKey) || privateKey.type !== "private") {
1116
+ throw new Error("privateKey must be a CryptoKey of type 'private'");
1117
+ }
1118
+ if (!(publicKey instanceof CryptoKey) || publicKey.type !== "public") {
1119
+ throw new Error("publicKey must be a CryptoKey of type 'public'");
1120
+ }
1121
+ const subject = buildSubject(commonName);
1122
+ const spkiDer = await subtle.exportKey("spki", publicKey);
1123
+ const subjectPublicKeyInfo = AsnConvert.parse(spkiDer, SubjectPublicKeyInfo);
1124
+ const attributes = new Attributes();
1125
+ const sanitizedLogicals = Array.isArray(options.logicals)
1126
+ ? options.logicals
1127
+ .map((logical) => logical.trim())
1128
+ .filter((logical) => logical.length > 0)
1129
+ : [];
1130
+ if (sanitizedLogicals.length > 0) {
1131
+ const san = new SubjectAlternativeName(sanitizedLogicals.map((logical) => new GeneralName({
1132
+ uniformResourceIdentifier: `${LOGICAL_URI_PREFIX$1}${logical}`,
1133
+ })));
1134
+ const extensions = new Extensions([
1135
+ new Extension({
1136
+ extnID: id_ce_subjectAltName,
1137
+ critical: false,
1138
+ extnValue: new OctetString(AsnConvert.serialize(san)),
611
1139
  }),
612
1140
  ]);
613
1141
  attributes.push(new Attribute({
@@ -686,7 +1214,7 @@ const NODE_ID_OID = "1.3.6.1.4.1.58530.4";
686
1214
  * Provides async HTTP client to request certificates from the CA signing service.
687
1215
  */
688
1216
  // Simple logger for now - TODO: integrate with runtime logging
689
- const logger$g = {
1217
+ const logger$f = {
690
1218
  debug: (_event, _meta) => {
691
1219
  // console.log(`[DEBUG] ${event}`, meta);
692
1220
  },
@@ -1135,7 +1663,7 @@ class CAServiceClient {
1135
1663
  logicals: logicals || [],
1136
1664
  };
1137
1665
  const url = `${this.connectionGrant.url.replace(/\/$/, "")}/sign`;
1138
- logger$g.debug("requesting_certificate", {
1666
+ logger$f.debug("requesting_certificate", {
1139
1667
  requester_id: requesterId,
1140
1668
  ca_service_url: url,
1141
1669
  physical_path: physicalPath,
@@ -1164,13 +1692,13 @@ class CAServiceClient {
1164
1692
  const result = await response.json();
1165
1693
  const certificatePem = result.certificate_pem;
1166
1694
  const certificateChainPem = result.certificate_chain_pem || certificatePem;
1167
- logger$g.debug("certificate_request_successful", {
1695
+ logger$f.debug("certificate_request_successful", {
1168
1696
  requester_id: requesterId,
1169
1697
  expires_at: result.expires_at,
1170
1698
  });
1171
1699
  // Extract and log certificate information with structured logging
1172
1700
  const certInfo = extractCertificateInfo(certificatePem);
1173
- logger$g.debug("certificate_details", {
1701
+ logger$f.debug("certificate_details", {
1174
1702
  requester_id: requesterId,
1175
1703
  certificate_type: "issued_certificate",
1176
1704
  ...certInfo,
@@ -1189,7 +1717,7 @@ class CAServiceClient {
1189
1717
  // First cert in chain is usually the issued certificate
1190
1718
  if (certPemBlock.trim() !== certificatePem.trim()) {
1191
1719
  const chainCertInfo = extractCertificateInfo(certPemBlock);
1192
- logger$g.debug("certificate_chain_details", {
1720
+ logger$f.debug("certificate_chain_details", {
1193
1721
  requester_id: requesterId,
1194
1722
  certificate_type: "certificate_chain",
1195
1723
  chain_index: i,
@@ -1200,7 +1728,7 @@ class CAServiceClient {
1200
1728
  else {
1201
1729
  // Subsequent certs are intermediate/root CAs
1202
1730
  const caCertInfo = extractCertificateInfo(certPemBlock);
1203
- logger$g.debug("certificate_chain_details", {
1731
+ logger$f.debug("certificate_chain_details", {
1204
1732
  requester_id: requesterId,
1205
1733
  certificate_type: "ca_certificate",
1206
1734
  chain_index: i,
@@ -1228,7 +1756,7 @@ class CAServiceClient {
1228
1756
  // Body read failed entirely
1229
1757
  errorDetail = `HTTP ${response.status}`;
1230
1758
  }
1231
- logger$g.error("certificate_request_failed", {
1759
+ logger$f.error("certificate_request_failed", {
1232
1760
  requester_id: requesterId,
1233
1761
  status_code: response.status,
1234
1762
  error: errorDetail,
@@ -1245,13 +1773,13 @@ class CAServiceClient {
1245
1773
  throw error;
1246
1774
  }
1247
1775
  if (error instanceof Error && error.name === "AbortError") {
1248
- logger$g.error("certificate_request_timeout", {
1776
+ logger$f.error("certificate_request_timeout", {
1249
1777
  requester_id: requesterId,
1250
1778
  timeout_seconds: this.timeoutSeconds,
1251
1779
  });
1252
1780
  throw new CertificateRequestError(`Certificate request timed out after ${this.timeoutSeconds} seconds`);
1253
1781
  }
1254
- logger$g.error("certificate_request_network_error", {
1782
+ logger$f.error("certificate_request_network_error", {
1255
1783
  requester_id: requesterId,
1256
1784
  error: String(error),
1257
1785
  });
@@ -1260,7 +1788,7 @@ class CAServiceClient {
1260
1788
  }
1261
1789
  }
1262
1790
 
1263
- const logger$f = getLogger("naylence.fame.security.encryption.sealed.x25519_encryption_manager");
1791
+ const logger$e = getLogger("naylence.fame.security.encryption.sealed.x25519_encryption_manager");
1264
1792
  class X25519EncryptionManager {
1265
1793
  constructor({ keyProvider, nodeLike = null, cryptoProvider = null, }) {
1266
1794
  this.pendingEnvelopes = new Map();
@@ -1277,7 +1805,7 @@ class X25519EncryptionManager {
1277
1805
  // KeyManagementHandler will queue the envelope and send KeyRequest.
1278
1806
  // X25519 should NOT queue here to avoid dual queueing.
1279
1807
  if (opts?.requestAddress) {
1280
- logger$f.debug("key_not_found_delegating_to_key_management", {
1808
+ logger$e.debug("key_not_found_delegating_to_key_management", {
1281
1809
  envelope_id: envelope.id,
1282
1810
  request_address: String(opts.requestAddress),
1283
1811
  });
@@ -1293,7 +1821,7 @@ class X25519EncryptionManager {
1293
1821
  return await this.encryptWithKey(envelope, recipPub, recipKid);
1294
1822
  }
1295
1823
  catch (error) {
1296
- logger$f.error("x25519_encryption_failed", {
1824
+ logger$e.error("x25519_encryption_failed", {
1297
1825
  error: error instanceof Error ? error.message : String(error),
1298
1826
  });
1299
1827
  return EncryptionResult.skipped(envelope);
@@ -1331,20 +1859,20 @@ class X25519EncryptionManager {
1331
1859
  return envelope;
1332
1860
  }
1333
1861
  catch (error) {
1334
- logger$f.error("x25519_decryption_failed", {
1862
+ logger$e.error("x25519_decryption_failed", {
1335
1863
  error: error instanceof Error ? error.message : String(error),
1336
1864
  });
1337
1865
  return envelope;
1338
1866
  }
1339
1867
  }
1340
1868
  async notifyKeyAvailable(keyId) {
1341
- logger$f.debug("x25519_notify_key_available_called", {
1869
+ logger$e.debug("x25519_notify_key_available_called", {
1342
1870
  key_id: keyId,
1343
1871
  pending_keys: Array.from(this.pendingEnvelopes.keys()),
1344
1872
  });
1345
1873
  const queued = this.pendingEnvelopes.get(keyId);
1346
1874
  if (!queued || queued.length === 0) {
1347
- logger$f.debug("no_queued_envelopes_for_key", {
1875
+ logger$e.debug("no_queued_envelopes_for_key", {
1348
1876
  key_id: keyId,
1349
1877
  has_queue: this.pendingEnvelopes.has(keyId),
1350
1878
  queue_length: queued?.length ?? 0,
@@ -1356,13 +1884,13 @@ class X25519EncryptionManager {
1356
1884
  this.keyRequestsInProgress.delete(keyId);
1357
1885
  const node = this.nodeLike;
1358
1886
  if (!node) {
1359
- logger$f.debug("discarding_queued_envelopes_no_node", {
1887
+ logger$e.debug("discarding_queued_envelopes_no_node", {
1360
1888
  key_id: keyId,
1361
1889
  count: queued.length,
1362
1890
  });
1363
1891
  return;
1364
1892
  }
1365
- logger$f.debug("replaying_envelopes_for_key", {
1893
+ logger$e.debug("replaying_envelopes_for_key", {
1366
1894
  key_id: keyId,
1367
1895
  count: queued.length,
1368
1896
  });
@@ -1371,7 +1899,7 @@ class X25519EncryptionManager {
1371
1899
  await node.deliver(envelope);
1372
1900
  }
1373
1901
  catch (error) {
1374
- logger$f.error("failed_to_replay_envelope", {
1902
+ logger$e.error("failed_to_replay_envelope", {
1375
1903
  key_id: keyId,
1376
1904
  envelope_id: envelope.id,
1377
1905
  error: error instanceof Error ? error.message : String(error),
@@ -1472,7 +2000,7 @@ class X25519EncryptionManager {
1472
2000
  ? this.extractPrivateKeyFromRecord(providerRecord)
1473
2001
  : null;
1474
2002
  if (providerRecordKey) {
1475
- logger$f.debug("using_provider_key_record_private_key", {
2003
+ logger$e.debug("using_provider_key_record_private_key", {
1476
2004
  kid,
1477
2005
  provider_key_id: providerKeyId,
1478
2006
  mismatched_kid: kid && providerKeyId !== kid ? kid : null,
@@ -1482,7 +2010,7 @@ class X25519EncryptionManager {
1482
2010
  }
1483
2011
  if (!providerPem) {
1484
2012
  if (kid && providerKeyId && providerKeyId !== kid) {
1485
- logger$f.debug("crypto_provider_key_id_mismatch_no_private_key", {
2013
+ logger$e.debug("crypto_provider_key_id_mismatch_no_private_key", {
1486
2014
  kid,
1487
2015
  provider_key_id: providerKeyId,
1488
2016
  });
@@ -1494,13 +2022,13 @@ class X25519EncryptionManager {
1494
2022
  return null;
1495
2023
  }
1496
2024
  if (!kid || providerKeyId === kid) {
1497
- logger$f.debug("using_crypto_provider_private_key_fallback", {
2025
+ logger$e.debug("using_crypto_provider_private_key_fallback", {
1498
2026
  kid: kid ?? null,
1499
2027
  provider_key_id: providerKeyId,
1500
2028
  });
1501
2029
  }
1502
2030
  else {
1503
- logger$f.warning("crypto_provider_key_id_mismatch_using_private_key", {
2031
+ logger$e.warning("crypto_provider_key_id_mismatch_using_private_key", {
1504
2032
  kid,
1505
2033
  provider_key_id: providerKeyId,
1506
2034
  key_record_present: Boolean(record),
@@ -1509,7 +2037,7 @@ class X25519EncryptionManager {
1509
2037
  return fallbackKey;
1510
2038
  }
1511
2039
  async queueEnvelopeForKey(envelope, opts, recipientKeyId) {
1512
- logger$f.debug("queueing_envelope_for_sealed_encryption", {
2040
+ logger$e.debug("queueing_envelope_for_sealed_encryption", {
1513
2041
  envelope_id: envelope.id,
1514
2042
  recipient_key_id: recipientKeyId,
1515
2043
  request_address: opts?.requestAddress
@@ -1557,7 +2085,7 @@ class X25519EncryptionManager {
1557
2085
  await node.deliver(keyRequestEnvelope, context);
1558
2086
  }
1559
2087
  catch (error) {
1560
- logger$f.error("failed_to_request_recipient_key", {
2088
+ logger$e.error("failed_to_request_recipient_key", {
1561
2089
  recipient_key_id: recipientKeyId,
1562
2090
  error: error instanceof Error ? error.message : String(error),
1563
2091
  });
@@ -1570,7 +2098,7 @@ class X25519EncryptionManager {
1570
2098
  return this.extractPublicKeyFromRecord(record);
1571
2099
  }
1572
2100
  catch (error) {
1573
- logger$f.debug("recipient_key_lookup_failed", {
2101
+ logger$e.debug("recipient_key_lookup_failed", {
1574
2102
  kid,
1575
2103
  error: error instanceof Error ? error.message : String(error),
1576
2104
  });
@@ -1585,7 +2113,7 @@ class X25519EncryptionManager {
1585
2113
  return await this.keyProvider.getKey(kid);
1586
2114
  }
1587
2115
  catch (error) {
1588
- logger$f.debug("private_key_lookup_failed", {
2116
+ logger$e.debug("private_key_lookup_failed", {
1589
2117
  kid,
1590
2118
  error: error instanceof Error ? error.message : String(error),
1591
2119
  });
@@ -1656,7 +2184,7 @@ class X25519EncryptionManager {
1656
2184
  const base64 = base64Lines.join("");
1657
2185
  const der = this.decodeBase64Flexible(base64);
1658
2186
  if (!der) {
1659
- logger$f.debug("pem_decode_failed", {
2187
+ logger$e.debug("pem_decode_failed", {
1660
2188
  key_type: keyType,
1661
2189
  });
1662
2190
  return null;
@@ -1889,7 +2417,7 @@ var index$1 = /*#__PURE__*/Object.freeze({
1889
2417
  X25519EncryptionManagerFactory: X25519EncryptionManagerFactory
1890
2418
  });
1891
2419
 
1892
- const logger$e = getLogger("naylence.fame.security.encryption.channel.channel_encryption_manager");
2420
+ const logger$d = getLogger("naylence.fame.security.encryption.channel.channel_encryption_manager");
1893
2421
  const SUPPORTED_CHANNEL_ALGORITHMS = ["chacha20-poly1305-channel"];
1894
2422
  const CHANNEL_ENCRYPTION_ALGORITHM = "chacha20-poly1305-channel";
1895
2423
  const HANDSHAKE_ALGORITHM = "CHACHA20P1305";
@@ -2040,13 +2568,13 @@ class ChannelEncryptionManager {
2040
2568
  const destination = opts?.destination ?? envelope.to ?? null;
2041
2569
  const destinationStr = toDestinationString(destination);
2042
2570
  if (!destinationStr) {
2043
- logger$e.warning("no_destination_for_channel_encryption", {
2571
+ logger$d.warning("no_destination_for_channel_encryption", {
2044
2572
  envelope_id: envelope.id,
2045
2573
  });
2046
2574
  return EncryptionResult.skipped(envelope);
2047
2575
  }
2048
2576
  if (!this.secureChannelManager) {
2049
- logger$e.warning("no_secure_channel_manager_available", {
2577
+ logger$d.warning("no_secure_channel_manager_available", {
2050
2578
  envelope_id: envelope.id,
2051
2579
  });
2052
2580
  return EncryptionResult.skipped(envelope);
@@ -2057,7 +2585,7 @@ class ChannelEncryptionManager {
2057
2585
  return this.encryptWithChannel(envelope, existingChannelId);
2058
2586
  }
2059
2587
  catch (error) {
2060
- logger$e.error("channel_encryption_failed", {
2588
+ logger$d.error("channel_encryption_failed", {
2061
2589
  error: error instanceof Error ? error.message : String(error),
2062
2590
  channel_id: existingChannelId,
2063
2591
  });
@@ -2085,35 +2613,35 @@ class ChannelEncryptionManager {
2085
2613
  }
2086
2614
  const channelId = encHeader.kid;
2087
2615
  if (!channelId) {
2088
- logger$e.error("missing_channel_id_in_encryption_header", {
2616
+ logger$d.error("missing_channel_id_in_encryption_header", {
2089
2617
  envelope_id: envelope.id,
2090
2618
  });
2091
2619
  return envelope;
2092
2620
  }
2093
2621
  const nonce = this.decodeNonceValue(encHeader.val ?? "");
2094
2622
  if (!nonce) {
2095
- logger$e.error("invalid_nonce_in_encryption_header", {
2623
+ logger$d.error("invalid_nonce_in_encryption_header", {
2096
2624
  envelope_id: envelope.id,
2097
2625
  value_present: Boolean(encHeader.val),
2098
2626
  });
2099
2627
  return envelope;
2100
2628
  }
2101
2629
  if (!this.secureChannelManager) {
2102
- logger$e.warning("no_secure_channel_manager_for_decryption", {
2630
+ logger$d.warning("no_secure_channel_manager_for_decryption", {
2103
2631
  envelope_id: envelope.id,
2104
2632
  });
2105
2633
  return envelope;
2106
2634
  }
2107
2635
  const channelState = this.getChannelState(channelId);
2108
2636
  if (!channelState) {
2109
- logger$e.error("channel_not_available_for_decryption", {
2637
+ logger$d.error("channel_not_available_for_decryption", {
2110
2638
  channel_id: channelId,
2111
2639
  });
2112
2640
  return envelope;
2113
2641
  }
2114
2642
  const ciphertext = this.extractCiphertext(frame.payload);
2115
2643
  if (!ciphertext) {
2116
- logger$e.error("invalid_ciphertext_payload", { envelope_id: envelope.id });
2644
+ logger$d.error("invalid_ciphertext_payload", { envelope_id: envelope.id });
2117
2645
  return envelope;
2118
2646
  }
2119
2647
  try {
@@ -2138,7 +2666,7 @@ class ChannelEncryptionManager {
2138
2666
  return envelope;
2139
2667
  }
2140
2668
  catch (error) {
2141
- logger$e.error("channel_decryption_failed", {
2669
+ logger$d.error("channel_decryption_failed", {
2142
2670
  channel_id: channelId,
2143
2671
  error: error instanceof Error ? error.message : String(error),
2144
2672
  });
@@ -2146,24 +2674,24 @@ class ChannelEncryptionManager {
2146
2674
  }
2147
2675
  }
2148
2676
  async notifyChannelEstablished(channelId) {
2149
- logger$e.debug("channel_encryption_manager_notified", {
2677
+ logger$d.debug("channel_encryption_manager_notified", {
2150
2678
  channel_id: channelId,
2151
2679
  manager_type: "channel",
2152
2680
  });
2153
2681
  if (!channelId.startsWith("auto-")) {
2154
- logger$e.warning("unexpected_channel_id_format", { channel_id: channelId });
2682
+ logger$d.warning("unexpected_channel_id_format", { channel_id: channelId });
2155
2683
  return;
2156
2684
  }
2157
2685
  const destinationStr = this.extractDestinationFromChannelId(channelId);
2158
2686
  if (!destinationStr) {
2159
- logger$e.warning("cannot_parse_destination_from_channel_id", {
2687
+ logger$d.warning("cannot_parse_destination_from_channel_id", {
2160
2688
  channel_id: channelId,
2161
2689
  });
2162
2690
  return;
2163
2691
  }
2164
2692
  this.handshakeInProgress.delete(destinationStr);
2165
2693
  if (!this.pendingEnvelopes.has(destinationStr)) {
2166
- logger$e.debug("no_pending_queue_for_destination", {
2694
+ logger$d.debug("no_pending_queue_for_destination", {
2167
2695
  destination: destinationStr,
2168
2696
  });
2169
2697
  return;
@@ -2171,7 +2699,7 @@ class ChannelEncryptionManager {
2171
2699
  const queuedEnvelopes = this.pendingEnvelopes.get(destinationStr) ?? [];
2172
2700
  this.pendingEnvelopes.delete(destinationStr);
2173
2701
  if (!this.secureChannelManager) {
2174
- logger$e.error("no_secure_channel_manager_for_queue_drain", {
2702
+ logger$d.error("no_secure_channel_manager_for_queue_drain", {
2175
2703
  channel_id: channelId,
2176
2704
  });
2177
2705
  return;
@@ -2180,7 +2708,7 @@ class ChannelEncryptionManager {
2180
2708
  try {
2181
2709
  const result = this.encryptWithChannel(envelope, channelId);
2182
2710
  if (!result.envelope) {
2183
- logger$e.warning("failed_to_encrypt_queued_envelope", {
2711
+ logger$d.warning("failed_to_encrypt_queued_envelope", {
2184
2712
  envelope_id: envelope.id,
2185
2713
  channel_id: channelId,
2186
2714
  });
@@ -2190,7 +2718,7 @@ class ChannelEncryptionManager {
2190
2718
  this.runAsyncTask(() => this.deliverEnvelope(encryptedEnvelope), `deliver-queued-${envelope.id}`);
2191
2719
  }
2192
2720
  catch (error) {
2193
- logger$e.error("failed_to_encrypt_queued_envelope", {
2721
+ logger$d.error("failed_to_encrypt_queued_envelope", {
2194
2722
  envelope_id: envelope.id,
2195
2723
  error: error instanceof Error ? error.message : String(error),
2196
2724
  });
@@ -2198,19 +2726,19 @@ class ChannelEncryptionManager {
2198
2726
  }
2199
2727
  }
2200
2728
  async notifyChannelFailed(channelId, reason = "handshake_failed") {
2201
- logger$e.debug("channel_encryption_manager_notified_failure", {
2729
+ logger$d.debug("channel_encryption_manager_notified_failure", {
2202
2730
  channel_id: channelId,
2203
2731
  reason,
2204
2732
  });
2205
2733
  if (!channelId.startsWith("auto-")) {
2206
- logger$e.warning("unexpected_channel_id_format_on_failure", {
2734
+ logger$d.warning("unexpected_channel_id_format_on_failure", {
2207
2735
  channel_id: channelId,
2208
2736
  });
2209
2737
  return;
2210
2738
  }
2211
2739
  const destinationStr = this.extractDestinationFromChannelId(channelId);
2212
2740
  if (!destinationStr) {
2213
- logger$e.warning("cannot_parse_destination_from_channel_id_on_failure", {
2741
+ logger$d.warning("cannot_parse_destination_from_channel_id_on_failure", {
2214
2742
  channel_id: channelId,
2215
2743
  });
2216
2744
  return;
@@ -2220,14 +2748,14 @@ class ChannelEncryptionManager {
2220
2748
  const cachedChannelId = this.addrChannelMap.get(destinationStr);
2221
2749
  if (cachedChannelId === channelId) {
2222
2750
  this.addrChannelMap.delete(destinationStr);
2223
- logger$e.debug("cleared_channel_cache_for_failed_channel", {
2751
+ logger$d.debug("cleared_channel_cache_for_failed_channel", {
2224
2752
  destination: destinationStr,
2225
2753
  channel_id: channelId,
2226
2754
  });
2227
2755
  }
2228
2756
  const queuedEnvelopes = this.pendingEnvelopes.get(destinationStr);
2229
2757
  if (!queuedEnvelopes || queuedEnvelopes.length === 0) {
2230
- logger$e.debug("no_pending_queue_for_failed_destination", {
2758
+ logger$d.debug("no_pending_queue_for_failed_destination", {
2231
2759
  destination: destinationStr,
2232
2760
  });
2233
2761
  return;
@@ -2246,7 +2774,7 @@ class ChannelEncryptionManager {
2246
2774
  const cached = this.addrChannelMap.get(destination);
2247
2775
  if (cached) {
2248
2776
  this.addrChannelMap.delete(destination);
2249
- logger$e.debug("cleared_channel_cache_for_destination", {
2777
+ logger$d.debug("cleared_channel_cache_for_destination", {
2250
2778
  destination,
2251
2779
  cached_channel_id: cached,
2252
2780
  });
@@ -2264,14 +2792,14 @@ class ChannelEncryptionManager {
2264
2792
  }
2265
2793
  const cached = this.addrChannelMap.get(destination);
2266
2794
  if (cached && this.getChannelState(cached)) {
2267
- logger$e.debug("using_cached_channel", { destination, channel_id: cached });
2795
+ logger$d.debug("using_cached_channel", { destination, channel_id: cached });
2268
2796
  return cached;
2269
2797
  }
2270
2798
  const channels = this.secureChannelManager.channels;
2271
2799
  for (const channelId of Object.keys(channels)) {
2272
2800
  if (channelId.startsWith(`auto-${destination}-`)) {
2273
2801
  this.addrChannelMap.set(destination, channelId);
2274
- logger$e.debug("using_existing_channel", {
2802
+ logger$d.debug("using_existing_channel", {
2275
2803
  destination,
2276
2804
  channel_id: channelId,
2277
2805
  });
@@ -2284,12 +2812,12 @@ class ChannelEncryptionManager {
2284
2812
  const queue = this.pendingEnvelopes.get(destinationStr) ?? [];
2285
2813
  queue.push(envelope);
2286
2814
  this.pendingEnvelopes.set(destinationStr, queue);
2287
- logger$e.debug("queued_envelope_for_channel_handshake", {
2815
+ logger$d.debug("queued_envelope_for_channel_handshake", {
2288
2816
  envelope_id: envelope.id,
2289
2817
  destination: destinationStr,
2290
2818
  });
2291
2819
  if (this.handshakeInProgress.has(destinationStr)) {
2292
- logger$e.debug("handshake_already_in_progress", {
2820
+ logger$d.debug("handshake_already_in_progress", {
2293
2821
  destination: destinationStr,
2294
2822
  });
2295
2823
  return;
@@ -2308,7 +2836,7 @@ class ChannelEncryptionManager {
2308
2836
  async initiateChannelHandshakeAsync(destination, destinationStr, opts) {
2309
2837
  void opts;
2310
2838
  if (!this.secureChannelManager) {
2311
- logger$e.error("no_secure_channel_manager_for_async_handshake_initiation");
2839
+ logger$d.error("no_secure_channel_manager_for_async_handshake_initiation");
2312
2840
  return;
2313
2841
  }
2314
2842
  const channelId = this.generateChannelId(destinationStr);
@@ -2316,19 +2844,19 @@ class ChannelEncryptionManager {
2316
2844
  const openFrame = this.secureChannelManager.generateOpenFrame(channelId, HANDSHAKE_ALGORITHM);
2317
2845
  const success = await this.sendSecureOpenFrameAsync(openFrame, destination);
2318
2846
  if (success) {
2319
- logger$e.debug("sent_secure_open_frame_async", {
2847
+ logger$d.debug("sent_secure_open_frame_async", {
2320
2848
  channel_id: channelId,
2321
2849
  destination: destinationStr,
2322
2850
  });
2323
2851
  }
2324
2852
  else {
2325
- logger$e.warning("failed_to_send_secure_open_frame_async", {
2853
+ logger$d.warning("failed_to_send_secure_open_frame_async", {
2326
2854
  channel_id: channelId,
2327
2855
  });
2328
2856
  }
2329
2857
  }
2330
2858
  catch (error) {
2331
- logger$e.error("async_channel_handshake_initiation_failed", {
2859
+ logger$d.error("async_channel_handshake_initiation_failed", {
2332
2860
  destination: destinationStr,
2333
2861
  error: error instanceof Error ? error.message : String(error),
2334
2862
  });
@@ -2337,22 +2865,22 @@ class ChannelEncryptionManager {
2337
2865
  async sendSecureOpenFrameAsync(openFrame, destination) {
2338
2866
  const node = this.nodeLike;
2339
2867
  if (!node) {
2340
- logger$e.error("no_node_available_for_sending_secure_open_async");
2868
+ logger$d.error("no_node_available_for_sending_secure_open_async");
2341
2869
  return false;
2342
2870
  }
2343
2871
  const envelopeFactory = node.envelopeFactory;
2344
2872
  if (!envelopeFactory) {
2345
- logger$e.error("no_envelope_factory_available_for_secure_open_async");
2873
+ logger$d.error("no_envelope_factory_available_for_secure_open_async");
2346
2874
  return false;
2347
2875
  }
2348
2876
  const replyTo = this.buildSystemReplyTo();
2349
2877
  if (!replyTo) {
2350
- logger$e.error("no_physical_path_available_for_reply_to_async");
2878
+ logger$d.error("no_physical_path_available_for_reply_to_async");
2351
2879
  return false;
2352
2880
  }
2353
2881
  const toAddress = toFameAddress(destination);
2354
2882
  if (!toAddress) {
2355
- logger$e.error("invalid_destination_for_secure_open", {
2883
+ logger$d.error("invalid_destination_for_secure_open", {
2356
2884
  destination: String(destination),
2357
2885
  });
2358
2886
  return false;
@@ -2364,7 +2892,7 @@ class ChannelEncryptionManager {
2364
2892
  corrId: generateId(),
2365
2893
  });
2366
2894
  await this.deliverEnvelope(envelope);
2367
- logger$e.debug("delivered_secure_open_frame_async", {
2895
+ logger$d.debug("delivered_secure_open_frame_async", {
2368
2896
  channel_id: openFrame.cid,
2369
2897
  });
2370
2898
  return true;
@@ -2372,7 +2900,7 @@ class ChannelEncryptionManager {
2372
2900
  async deliverEnvelope(envelope) {
2373
2901
  const node = this.nodeLike;
2374
2902
  if (!node) {
2375
- logger$e.error("no_node_available_for_delivery", {
2903
+ logger$d.error("no_node_available_for_delivery", {
2376
2904
  envelope_id: envelope.id,
2377
2905
  });
2378
2906
  return;
@@ -2382,19 +2910,19 @@ class ChannelEncryptionManager {
2382
2910
  }
2383
2911
  encryptWithChannel(envelope, channelId) {
2384
2912
  if (!this.secureChannelManager) {
2385
- logger$e.error("no_secure_channel_manager_for_encryption");
2913
+ logger$d.error("no_secure_channel_manager_for_encryption");
2386
2914
  return EncryptionResult.skipped(envelope);
2387
2915
  }
2388
2916
  const frame = envelope.frame;
2389
2917
  if (!this.isDataFrame(frame)) {
2390
- logger$e.error("attempted_to_encrypt_non_dataframe", {
2918
+ logger$d.error("attempted_to_encrypt_non_dataframe", {
2391
2919
  frame_type: frame.type ?? typeof frame,
2392
2920
  });
2393
2921
  return EncryptionResult.skipped(envelope);
2394
2922
  }
2395
2923
  const channelState = this.getChannelState(channelId);
2396
2924
  if (!channelState) {
2397
- logger$e.error("channel_not_in_channels", { channel_id: channelId });
2925
+ logger$d.error("channel_not_in_channels", { channel_id: channelId });
2398
2926
  return EncryptionResult.skipped(envelope);
2399
2927
  }
2400
2928
  const payloadBytes = this.serializePayload(frame.payload);
@@ -2453,7 +2981,7 @@ class ChannelEncryptionManager {
2453
2981
  return decodeBase64$1(payload);
2454
2982
  }
2455
2983
  catch (error) {
2456
- logger$e.error("failed_to_decode_base64_ciphertext", {
2984
+ logger$d.error("failed_to_decode_base64_ciphertext", {
2457
2985
  error: error instanceof Error ? error.message : String(error),
2458
2986
  });
2459
2987
  return null;
@@ -2483,7 +3011,7 @@ class ChannelEncryptionManager {
2483
3011
  return parts.slice(1, -1).join("-");
2484
3012
  }
2485
3013
  async handleFailedEnvelope(envelope, destinationStr, channelId, reason) {
2486
- logger$e.warning("envelope_failed_due_to_channel_handshake_failure", {
3014
+ logger$d.warning("envelope_failed_due_to_channel_handshake_failure", {
2487
3015
  envelope_id: envelope.id,
2488
3016
  destination: destinationStr,
2489
3017
  channel_id: channelId,
@@ -2491,14 +3019,14 @@ class ChannelEncryptionManager {
2491
3019
  });
2492
3020
  const frame = envelope.frame;
2493
3021
  if (!this.isDataFrame(frame)) {
2494
- logger$e.debug("skipping_nack_for_non_dataframe", {
3022
+ logger$d.debug("skipping_nack_for_non_dataframe", {
2495
3023
  envelope_id: envelope.id,
2496
3024
  frame_type: frame.type ?? typeof frame,
2497
3025
  });
2498
3026
  return;
2499
3027
  }
2500
3028
  if (!envelope.replyTo) {
2501
- logger$e.debug("skipping_nack_no_reply_to", { envelope_id: envelope.id });
3029
+ logger$d.debug("skipping_nack_no_reply_to", { envelope_id: envelope.id });
2502
3030
  return;
2503
3031
  }
2504
3032
  await this.sendDeliveryNack(envelope, `channel_handshake_failed: ${reason}`);
@@ -2506,17 +3034,17 @@ class ChannelEncryptionManager {
2506
3034
  async sendDeliveryNack(envelope, failureReason) {
2507
3035
  const node = this.nodeLike;
2508
3036
  if (!node) {
2509
- logger$e.error("no_node_available_for_sending_delivery_nack");
3037
+ logger$d.error("no_node_available_for_sending_delivery_nack");
2510
3038
  return;
2511
3039
  }
2512
3040
  const envelopeFactory = node.envelopeFactory;
2513
3041
  if (!envelopeFactory) {
2514
- logger$e.error("no_envelope_factory_available_for_delivery_nack");
3042
+ logger$d.error("no_envelope_factory_available_for_delivery_nack");
2515
3043
  return;
2516
3044
  }
2517
3045
  const replyTo = toFameAddress(envelope.replyTo ?? null);
2518
3046
  if (!replyTo) {
2519
- logger$e.error("invalid_reply_to_for_delivery_nack", {
3047
+ logger$d.error("invalid_reply_to_for_delivery_nack", {
2520
3048
  reply_to: envelope.replyTo,
2521
3049
  });
2522
3050
  return;
@@ -2533,7 +3061,7 @@ class ChannelEncryptionManager {
2533
3061
  corrId: envelope.corrId ?? generateId(),
2534
3062
  });
2535
3063
  await this.deliverEnvelope(nackEnvelope);
2536
- logger$e.debug("delivered_delivery_nack", {
3064
+ logger$d.debug("delivered_delivery_nack", {
2537
3065
  original_envelope_id: envelope.id,
2538
3066
  nack_envelope_id: nackEnvelope.id,
2539
3067
  });
@@ -2571,7 +3099,7 @@ class ChannelEncryptionManager {
2571
3099
  await task();
2572
3100
  }
2573
3101
  catch (error) {
2574
- logger$e.error("async_task_failed", {
3102
+ logger$d.error("async_task_failed", {
2575
3103
  task_name: name,
2576
3104
  error: error instanceof Error ? error.message : String(error),
2577
3105
  });
@@ -2625,7 +3153,7 @@ class ChannelEncryptionManager {
2625
3153
  }
2626
3154
  }
2627
3155
 
2628
- const logger$d = getLogger("naylence.fame.security.encryption.channel.channel_encryption_manager_factory");
3156
+ const logger$c = getLogger("naylence.fame.security.encryption.channel.channel_encryption_manager_factory");
2629
3157
  const DEFAULT_SUPPORTED_ALGORITHMS = ["chacha20-poly1305-channel"];
2630
3158
  const FACTORY_META$d = {
2631
3159
  base: ENCRYPTION_MANAGER_FACTORY_BASE_TYPE,
@@ -2657,7 +3185,7 @@ class ChannelEncryptionManagerFactory extends EncryptionManagerFactory {
2657
3185
  async create(_config, ...factoryArgs) {
2658
3186
  const [dependencies] = factoryArgs;
2659
3187
  const resolvedDependencies = this.resolveDependencies(dependencies);
2660
- logger$d.debug("creating_channel_encryption_manager", {
3188
+ logger$c.debug("creating_channel_encryption_manager", {
2661
3189
  has_secure_channel_manager: Boolean(resolvedDependencies.secureChannelManager),
2662
3190
  has_node_like: Boolean(resolvedDependencies.nodeLike),
2663
3191
  has_task_spawner: Boolean(resolvedDependencies.taskSpawner),
@@ -2719,7 +3247,7 @@ var index = /*#__PURE__*/Object.freeze({
2719
3247
  ChannelEncryptionManagerFactory: ChannelEncryptionManagerFactory
2720
3248
  });
2721
3249
 
2722
- const logger$c = getLogger("naylence.fame.security.encryption.default_secure_channel_manager");
3250
+ const logger$b = getLogger("naylence.fame.security.encryption.default_secure_channel_manager");
2723
3251
  const DEFAULT_ALGORITHM = "CHACHA20P1305";
2724
3252
  const CHANNEL_KEY_LENGTH = 32;
2725
3253
  const NONCE_PREFIX_LENGTH = 4;
@@ -2766,7 +3294,7 @@ class DefaultSecureChannelManager {
2766
3294
  const privateKey = x25519.utils.randomSecretKey();
2767
3295
  const publicKey = x25519.scalarMultBase(privateKey);
2768
3296
  this.ephemeralKeys.set(channelId, privateKey);
2769
- logger$c.debug("generated_channel_open", { cid: channelId, algorithm });
3297
+ logger$b.debug("generated_channel_open", { cid: channelId, algorithm });
2770
3298
  return {
2771
3299
  type: "SecureOpen",
2772
3300
  cid: channelId,
@@ -2779,7 +3307,7 @@ class DefaultSecureChannelManager {
2779
3307
  requireCryptoSupport();
2780
3308
  const algorithm = frame.alg || DEFAULT_ALGORITHM;
2781
3309
  if (!this.isSupportedAlgorithm(algorithm)) {
2782
- logger$c.warning("unsupported_channel_algorithm", {
3310
+ logger$b.warning("unsupported_channel_algorithm", {
2783
3311
  cid: frame.cid,
2784
3312
  alg: algorithm,
2785
3313
  });
@@ -2797,7 +3325,7 @@ class DefaultSecureChannelManager {
2797
3325
  peerPublicKey = decodeBase64(frame.ephPub);
2798
3326
  }
2799
3327
  catch (error) {
2800
- logger$c.warning("invalid_peer_public_key", {
3328
+ logger$b.warning("invalid_peer_public_key", {
2801
3329
  cid: frame.cid,
2802
3330
  error: error instanceof Error ? error.message : String(error),
2803
3331
  });
@@ -2819,7 +3347,7 @@ class DefaultSecureChannelManager {
2819
3347
  algorithm,
2820
3348
  });
2821
3349
  this.channelsMap.set(frame.cid, channelState);
2822
- logger$c.debug("channel_established", { cid: frame.cid, algorithm });
3350
+ logger$b.debug("channel_established", { cid: frame.cid, algorithm });
2823
3351
  myPrivateKey.fill(0);
2824
3352
  sharedSecret.fill(0);
2825
3353
  return {
@@ -2833,7 +3361,7 @@ class DefaultSecureChannelManager {
2833
3361
  async handleAcceptFrame(frame) {
2834
3362
  requireCryptoSupport();
2835
3363
  if (frame.ok === false) {
2836
- logger$c.warning("channel_rejected", {
3364
+ logger$b.warning("channel_rejected", {
2837
3365
  cid: frame.cid,
2838
3366
  error: frame.reason,
2839
3367
  });
@@ -2842,7 +3370,7 @@ class DefaultSecureChannelManager {
2842
3370
  }
2843
3371
  const privateKey = this.ephemeralKeys.get(frame.cid);
2844
3372
  if (!privateKey) {
2845
- logger$c.error("no_ephemeral_key", { cid: frame.cid });
3373
+ logger$b.error("no_ephemeral_key", { cid: frame.cid });
2846
3374
  return false;
2847
3375
  }
2848
3376
  let peerPublicKey;
@@ -2850,7 +3378,7 @@ class DefaultSecureChannelManager {
2850
3378
  peerPublicKey = decodeBase64(frame.ephPub);
2851
3379
  }
2852
3380
  catch (error) {
2853
- logger$c.warning("invalid_accept_public_key", {
3381
+ logger$b.warning("invalid_accept_public_key", {
2854
3382
  cid: frame.cid,
2855
3383
  error: error instanceof Error ? error.message : String(error),
2856
3384
  });
@@ -2865,17 +3393,17 @@ class DefaultSecureChannelManager {
2865
3393
  algorithm,
2866
3394
  });
2867
3395
  this.channelsMap.set(frame.cid, channelState);
2868
- logger$c.debug("channel_completed", { cid: frame.cid, algorithm });
3396
+ logger$b.debug("channel_completed", { cid: frame.cid, algorithm });
2869
3397
  sharedSecret.fill(0);
2870
3398
  this.cleanupEphemeralKey(frame.cid);
2871
3399
  return true;
2872
3400
  }
2873
3401
  handleCloseFrame(frame) {
2874
3402
  if (this.channelsMap.delete(frame.cid)) {
2875
- logger$c.debug("channel_closed", { cid: frame.cid, reason: frame.reason });
3403
+ logger$b.debug("channel_closed", { cid: frame.cid, reason: frame.reason });
2876
3404
  }
2877
3405
  else {
2878
- logger$c.warning("close_unknown_channel", { cid: frame.cid });
3406
+ logger$b.warning("close_unknown_channel", { cid: frame.cid });
2879
3407
  }
2880
3408
  this.cleanupEphemeralKey(frame.cid);
2881
3409
  }
@@ -2902,7 +3430,7 @@ class DefaultSecureChannelManager {
2902
3430
  }
2903
3431
  closeChannel(channelId, reason = "User requested") {
2904
3432
  if (this.channelsMap.delete(channelId)) {
2905
- logger$c.debug("channel_closed_by_user", { cid: channelId, reason });
3433
+ logger$b.debug("channel_closed_by_user", { cid: channelId, reason });
2906
3434
  }
2907
3435
  this.cleanupEphemeralKey(channelId);
2908
3436
  return {
@@ -2919,7 +3447,7 @@ class DefaultSecureChannelManager {
2919
3447
  this.channelsMap.delete(channelId);
2920
3448
  this.cleanupEphemeralKey(channelId);
2921
3449
  removed += 1;
2922
- logger$c.debug("channel_expired_cleanup", { cid: channelId });
3450
+ logger$b.debug("channel_expired_cleanup", { cid: channelId });
2923
3451
  }
2924
3452
  }
2925
3453
  return removed;
@@ -2948,7 +3476,7 @@ class DefaultSecureChannelManager {
2948
3476
  if (channelId.startsWith(prefix)) {
2949
3477
  if (this.removeChannel(channelId)) {
2950
3478
  removed += 1;
2951
- logger$c.debug("removed_channel_for_destination", {
3479
+ logger$b.debug("removed_channel_for_destination", {
2952
3480
  channel_id: channelId,
2953
3481
  destination,
2954
3482
  });
@@ -2956,7 +3484,7 @@ class DefaultSecureChannelManager {
2956
3484
  }
2957
3485
  }
2958
3486
  if (removed > 0) {
2959
- logger$c.info("cleanup_channels_for_destination", {
3487
+ logger$b.info("cleanup_channels_for_destination", {
2960
3488
  destination,
2961
3489
  channels_removed: removed,
2962
3490
  });
@@ -2996,222 +3524,58 @@ const FACTORY_META$c = {
2996
3524
  base: SECURE_CHANNEL_MANAGER_FACTORY_BASE_TYPE,
2997
3525
  key: "DefaultSecureChannelManager",
2998
3526
  };
2999
- class DefaultSecureChannelManagerFactory extends SecureChannelManagerFactory {
3000
- constructor() {
3001
- super(...arguments);
3002
- this.type = "DefaultSecureChannelManager";
3003
- this.isDefault = true;
3004
- this.priority = 500;
3005
- }
3006
- async create(config = null) {
3007
- const ttl = this.resolveChannelTtl(config);
3008
- return new DefaultSecureChannelManager(ttl ? { channelTtlSeconds: ttl } : {});
3009
- }
3010
- getSupportedAlgorithms() {
3011
- return ["CHACHA20P1305"];
3012
- }
3013
- resolveChannelTtl(config) {
3014
- if (!config) {
3015
- return undefined;
3016
- }
3017
- const candidates = [
3018
- config.channelTtlSeconds,
3019
- config.channelTtl,
3020
- config.channel_ttl,
3021
- config.channelTTL,
3022
- ];
3023
- for (const candidate of candidates) {
3024
- const normalized = this.toPositiveNumber(candidate);
3025
- if (typeof normalized === "number") {
3026
- return normalized;
3027
- }
3028
- }
3029
- return undefined;
3030
- }
3031
- toPositiveNumber(value) {
3032
- if (typeof value === "number" && Number.isFinite(value) && value > 0) {
3033
- return value;
3034
- }
3035
- if (typeof value === "string" && value.trim() !== "") {
3036
- const parsed = Number(value);
3037
- if (Number.isFinite(parsed) && parsed > 0) {
3038
- return parsed;
3039
- }
3040
- }
3041
- return undefined;
3042
- }
3043
- }
3044
-
3045
- var defaultSecureChannelManagerFactory = /*#__PURE__*/Object.freeze({
3046
- __proto__: null,
3047
- DefaultSecureChannelManagerFactory: DefaultSecureChannelManagerFactory,
3048
- FACTORY_META: FACTORY_META$c,
3049
- default: DefaultSecureChannelManagerFactory
3050
- });
3051
-
3052
- const logger$b = getLogger("naylence.fame.security.encryption.encryption_manager_registry");
3053
- class EncryptionManagerFactoryRegistry {
3054
- constructor(autoDiscover = true) {
3055
- this.factories = [];
3056
- this.algorithmToFactory = new Map();
3057
- this.typeToFactories = new Map();
3058
- this.factorySet = new Set();
3059
- this.autoDiscoveredFactories = new Set();
3060
- this.autoDiscovered = false;
3061
- if (autoDiscover) {
3062
- this.autoDiscoverFactories();
3063
- }
3064
- }
3065
- autoDiscoverFactories() {
3066
- if (this.autoDiscovered) {
3067
- return;
3068
- }
3069
- try {
3070
- const extensionInfos = ExtensionManager.getExtensionsByType(ENCRYPTION_MANAGER_FACTORY_BASE_TYPE);
3071
- let registeredCount = 0;
3072
- for (const [factoryName, info] of extensionInfos) {
3073
- if (factoryName === "CompositeEncryptionManager") {
3074
- logger$b.debug("skipping_composite_factory_to_avoid_circular_dependency", {
3075
- factory_name: factoryName,
3076
- });
3077
- continue;
3078
- }
3079
- try {
3080
- const factoryInstance = (info.instance ??
3081
- ExtensionManager.getGlobalFactory(ENCRYPTION_MANAGER_FACTORY_BASE_TYPE, factoryName));
3082
- this.registerFactory(factoryInstance, { autoDiscovered: true });
3083
- registeredCount += 1;
3084
- logger$b.debug("auto_discovered_factory", {
3085
- factory_name: factoryName,
3086
- factory_class: factoryInstance.constructor.name,
3087
- algorithms: factoryInstance.getSupportedAlgorithms(),
3088
- encryption_type: factoryInstance.getEncryptionType(),
3089
- priority: factoryInstance.getPriority(),
3090
- });
3091
- }
3092
- catch (error) {
3093
- logger$b.warning("failed_to_auto_register_factory", {
3094
- factory_name: factoryName,
3095
- error: error instanceof Error ? error.message : String(error),
3096
- });
3097
- }
3098
- }
3099
- this.autoDiscovered = true;
3100
- logger$b.debug("completed_auto_discovery", {
3101
- registered_factories: registeredCount,
3102
- total_discovered: extensionInfos.size,
3103
- skipped_composite: true,
3104
- });
3105
- }
3106
- catch (error) {
3107
- logger$b.warning("failed_auto_discovery_of_factories", {
3108
- error: error instanceof Error ? error.message : String(error),
3109
- });
3110
- }
3111
- }
3112
- registerFactory(factory, options = {}) {
3113
- if (this.factorySet.has(factory)) {
3114
- return;
3115
- }
3116
- this.factorySet.add(factory);
3117
- this.factories.push(factory);
3118
- if (options.autoDiscovered) {
3119
- this.autoDiscoveredFactories.add(factory);
3120
- }
3121
- for (const algorithm of factory.getSupportedAlgorithms()) {
3122
- const existing = this.algorithmToFactory.get(algorithm);
3123
- if (!existing || factory.getPriority() > existing.getPriority()) {
3124
- this.algorithmToFactory.set(algorithm, factory);
3125
- logger$b.debug("registered_algorithm_mapping", {
3126
- algorithm,
3127
- factory: factory.constructor.name,
3128
- priority: factory.getPriority(),
3129
- });
3130
- }
3131
- }
3132
- const encryptionType = factory.getEncryptionType();
3133
- const typeFactories = this.typeToFactories.get(encryptionType) ?? [];
3134
- typeFactories.push(factory);
3135
- typeFactories.sort((a, b) => b.getPriority() - a.getPriority());
3136
- this.typeToFactories.set(encryptionType, typeFactories);
3137
- logger$b.debug("registered_encryption_manager_factory", {
3138
- factory: factory.constructor.name,
3139
- encryption_type: encryptionType,
3140
- algorithms: factory.getSupportedAlgorithms(),
3141
- priority: factory.getPriority(),
3142
- auto_discovered: options.autoDiscovered ?? false,
3143
- });
3144
- }
3145
- getFactoryForAlgorithm(algorithm) {
3146
- this.ensureAutoDiscovery();
3147
- return this.algorithmToFactory.get(algorithm);
3148
- }
3149
- getFactoryForOptions(opts) {
3150
- this.ensureAutoDiscovery();
3151
- for (const factory of this.factories) {
3152
- if (factory.supportsOptions(opts ?? undefined)) {
3153
- logger$b.debug("found_factory_for_options", {
3154
- factory: factory.constructor.name,
3155
- encryption_type: factory.getEncryptionType(),
3156
- });
3157
- return factory;
3158
- }
3159
- }
3160
- logger$b.debug("no_factory_found_for_options", { opts });
3161
- return undefined;
3162
- }
3163
- getFactoriesByType(encryptionType) {
3164
- this.ensureAutoDiscovery();
3165
- return this.typeToFactories.get(encryptionType) ?? [];
3166
- }
3167
- getAllSupportedAlgorithms() {
3168
- this.ensureAutoDiscovery();
3169
- return Array.from(this.algorithmToFactory.keys());
3170
- }
3171
- getRegistryInfo() {
3172
- return {
3173
- totalFactories: this.factories.length,
3174
- autoDiscovered: this.autoDiscovered,
3175
- algorithmMappings: Object.fromEntries(Array.from(this.algorithmToFactory.entries()).map(([algorithm, factory]) => [algorithm, factory.constructor.name])),
3176
- typeMappings: Object.fromEntries(Array.from(this.typeToFactories.entries()).map(([encType, factories]) => [
3177
- encType,
3178
- factories.map((factory) => factory.constructor.name),
3179
- ])),
3180
- };
3181
- }
3182
- forceRediscovery() {
3183
- const manualFactories = this.factories.filter((factory) => !this.autoDiscoveredFactories.has(factory));
3184
- this.autoDiscovered = false;
3185
- this.algorithmToFactory.clear();
3186
- this.typeToFactories.clear();
3187
- this.factories.length = 0;
3188
- this.factorySet.clear();
3189
- this.autoDiscoveredFactories.clear();
3190
- for (const factory of manualFactories) {
3191
- this.registerFactory(factory);
3192
- }
3193
- this.autoDiscoverFactories();
3527
+ class DefaultSecureChannelManagerFactory extends SecureChannelManagerFactory {
3528
+ constructor() {
3529
+ super(...arguments);
3530
+ this.type = "DefaultSecureChannelManager";
3531
+ this.isDefault = true;
3532
+ this.priority = 500;
3194
3533
  }
3195
- isAutoDiscovered() {
3196
- return this.autoDiscovered;
3534
+ async create(config = null) {
3535
+ const ttl = this.resolveChannelTtl(config);
3536
+ return new DefaultSecureChannelManager(ttl ? { channelTtlSeconds: ttl } : {});
3197
3537
  }
3198
- ensureInitialized() {
3199
- this.ensureAutoDiscovery();
3538
+ getSupportedAlgorithms() {
3539
+ return ["CHACHA20P1305"];
3200
3540
  }
3201
- ensureAutoDiscovery() {
3202
- if (!this.autoDiscovered) {
3203
- this.autoDiscoverFactories();
3541
+ resolveChannelTtl(config) {
3542
+ if (!config) {
3543
+ return undefined;
3544
+ }
3545
+ const candidates = [
3546
+ config.channelTtlSeconds,
3547
+ config.channelTtl,
3548
+ config.channel_ttl,
3549
+ config.channelTTL,
3550
+ ];
3551
+ for (const candidate of candidates) {
3552
+ const normalized = this.toPositiveNumber(candidate);
3553
+ if (typeof normalized === "number") {
3554
+ return normalized;
3555
+ }
3204
3556
  }
3557
+ return undefined;
3558
+ }
3559
+ toPositiveNumber(value) {
3560
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) {
3561
+ return value;
3562
+ }
3563
+ if (typeof value === "string" && value.trim() !== "") {
3564
+ const parsed = Number(value);
3565
+ if (Number.isFinite(parsed) && parsed > 0) {
3566
+ return parsed;
3567
+ }
3568
+ }
3569
+ return undefined;
3205
3570
  }
3206
3571
  }
3207
- const globalRegistry = new EncryptionManagerFactoryRegistry(true);
3208
- function getEncryptionManagerFactoryRegistry() {
3209
- globalRegistry.ensureInitialized();
3210
- return globalRegistry;
3211
- }
3212
- function registerEncryptionManagerFactory(factory) {
3213
- globalRegistry.registerFactory(factory);
3214
- }
3572
+
3573
+ var defaultSecureChannelManagerFactory = /*#__PURE__*/Object.freeze({
3574
+ __proto__: null,
3575
+ DefaultSecureChannelManagerFactory: DefaultSecureChannelManagerFactory,
3576
+ FACTORY_META: FACTORY_META$c,
3577
+ default: DefaultSecureChannelManagerFactory
3578
+ });
3215
3579
 
3216
3580
  const logger$a = getLogger("naylence.fame.security.encryption.composite_encryption_manager");
3217
3581
  const DEFAULT_SEALED_ALGORITHMS = [
@@ -5133,1275 +5497,953 @@ class AFTLoadBalancerStickinessManager extends BaseNodeEventListener {
5133
5497
  }
5134
5498
  const verification = await this.verifier.verify(aftToken, envelope.sid ?? undefined);
5135
5499
  if (!verification.valid) {
5136
- this.metrics.verifyFailures += 1;
5137
- logger$4.warning("aft_verification_failed", {
5138
- envelope_id: envelope.id,
5139
- replica_id: replicaId,
5140
- error: verification.error,
5141
- });
5142
- return null;
5143
- }
5144
- this.storeAssociation(aftToken, {
5145
- replicaId,
5146
- token: aftToken,
5147
- sid: verification.sid ?? "",
5148
- exp: verification.exp ?? Math.floor(Date.now() / 1000) + this.defaultTtlSec,
5149
- trustLevel: verification.trustLevel,
5150
- scope: verification.scope ?? null,
5151
- clientSid: verification.clientSid ?? null,
5152
- });
5153
- if (verification.clientSid) {
5154
- this.sidCache.set(verification.clientSid, replicaId);
5155
- logger$4.debug("sid_cache_updated", {
5156
- envelope_id: envelope.id,
5157
- client_sid: verification.clientSid,
5158
- replica_id: replicaId,
5159
- });
5160
- }
5161
- this.metrics.associationsCreated += 1;
5162
- logger$4.debug("aft_association_created", {
5163
- envelope_id: envelope.id,
5164
- replica_id: replicaId,
5165
- sid: verification.sid,
5166
- exp: verification.exp,
5167
- trust_level: verification.trustLevel,
5168
- scope: verification.scope,
5169
- });
5170
- return this.config.clientEcho ? aftToken : null;
5171
- }
5172
- getStickyReplicaSegment(envelope, segments) {
5173
- if (!this.config.enabled) {
5174
- logger$4.debug("stickiness_disabled", { envelope_id: envelope.id });
5175
- return null;
5176
- }
5177
- if (envelope.aft) {
5178
- const replicaId = this.routeByAft(envelope.aft, envelope);
5179
- if (replicaId) {
5180
- this.metrics.cacheHits += 1;
5181
- logger$4.debug("aft_routed_envelope", {
5182
- envelope_id: envelope.id,
5183
- replica_id: replicaId,
5184
- routing_type: "aft_direct",
5185
- });
5186
- return replicaId;
5187
- }
5188
- }
5189
- if (envelope.sid) {
5190
- const cachedReplica = this.sidCache.get(envelope.sid);
5191
- if (cachedReplica) {
5192
- if (this.config.securityLevel === StickinessMode.SID_ONLY) {
5193
- this.metrics.cacheHits += 1;
5194
- logger$4.debug("sid_cache_routed_envelope", {
5195
- envelope_id: envelope.id,
5196
- replica_id: cachedReplica,
5197
- sid: envelope.sid,
5198
- routing_type: "sid_only",
5199
- });
5200
- return cachedReplica;
5201
- }
5202
- for (const [token, association] of this.aftAssociations.entries()) {
5203
- if (association.replicaId === cachedReplica &&
5204
- !association.isExpired()) {
5205
- envelope.aft = token;
5206
- this.metrics.cacheHits += 1;
5207
- logger$4.debug("sid_cache_routed_envelope", {
5208
- envelope_id: envelope.id,
5209
- replica_id: cachedReplica,
5210
- sid: envelope.sid,
5211
- routing_type: "sid_cache_with_aft",
5212
- });
5213
- return cachedReplica;
5214
- }
5215
- }
5216
- this.metrics.cacheHits += 1;
5217
- logger$4.debug("sid_cache_routed_envelope", {
5218
- envelope_id: envelope.id,
5219
- replica_id: cachedReplica,
5220
- sid: envelope.sid,
5221
- routing_type: "sid_cache_direct",
5222
- });
5223
- return cachedReplica;
5224
- }
5225
- logger$4.debug("no_cached_replica_for_sid", {
5226
- envelope_id: envelope.id,
5227
- sid: envelope.sid,
5228
- });
5229
- }
5230
- if (envelope.sid && Array.isArray(segments) && segments.length > 0) {
5231
- const index = computeDeterministicIndex(envelope.sid, segments.length);
5232
- const chosen = segments[index];
5233
- this.metrics.cacheHits += 1;
5234
- logger$4.debug("sid_based_deterministic_choice", {
5235
- envelope_id: envelope.id,
5236
- sid: envelope.sid,
5237
- chosen,
5238
- routing_type: "sid_deterministic",
5239
- });
5240
- return chosen;
5241
- }
5242
- this.metrics.cacheMisses += 1;
5243
- logger$4.debug("no_stickiness_routing", {
5244
- envelope_id: envelope.id,
5245
- has_aft: Boolean(envelope.aft),
5246
- has_sid: Boolean(envelope.sid),
5247
- });
5248
- return null;
5249
- }
5250
- cleanupExpiredAssociations() {
5251
- const now = Math.floor(Date.now() / 1000);
5252
- const expiredTokens = [];
5253
- for (const [token, association] of this.aftAssociations.entries()) {
5254
- if (association.isExpired(now)) {
5255
- expiredTokens.push(token);
5256
- }
5257
- }
5258
- for (const token of expiredTokens) {
5259
- this.removeAssociation(token);
5260
- }
5261
- if (expiredTokens.length > 0) {
5262
- this.metrics.associationsExpired += expiredTokens.length;
5263
- logger$4.debug("cleaned_expired_associations", {
5264
- count: expiredTokens.length,
5265
- });
5266
- }
5267
- }
5268
- replicaLeft(replicaId) {
5269
- const tokensToRemove = [];
5270
- for (const [token, association] of this.aftAssociations.entries()) {
5271
- if (association.replicaId === replicaId) {
5272
- tokensToRemove.push(token);
5273
- }
5274
- }
5275
- for (const token of tokensToRemove) {
5276
- this.removeAssociation(token);
5277
- }
5278
- if (tokensToRemove.length > 0) {
5279
- logger$4.debug("removed_associations_for_departed_replica", {
5280
- replica_id: replicaId,
5281
- count: tokensToRemove.length,
5282
- });
5283
- }
5284
- }
5285
- handleReplicaLeft(replicaId) {
5286
- this.replicaLeft(replicaId);
5287
- logger$4.debug("stickiness_replica_cleanup", { replica_id: replicaId });
5288
- }
5289
- getMetrics() {
5290
- return {
5291
- ...this.metrics,
5292
- cacheSize: this.aftAssociations.size,
5293
- sidCacheSize: this.sidCache.size,
5294
- };
5295
- }
5296
- getAssociations() {
5297
- const result = {};
5298
- for (const [token, association] of this.aftAssociations.entries()) {
5299
- result[token] = {
5300
- replica_id: association.replicaId,
5301
- sid: association.sid,
5302
- client_sid: association.clientSid,
5303
- exp: association.exp,
5304
- trust_level: association.trustLevel,
5305
- scope: association.scope,
5306
- created_at: association.createdAt,
5307
- expired: association.isExpired(),
5308
- };
5309
- }
5310
- return result;
5311
- }
5312
- getStickinessMetrics() {
5313
- return this.getMetrics();
5314
- }
5315
- logMetrics() {
5316
- const hits = this.metrics.cacheHits;
5317
- const misses = this.metrics.cacheMisses;
5318
- const total = hits + misses;
5319
- const hitRate = total > 0 ? Math.round((hits / total) * 10000) / 100 : 0;
5320
- logger$4.info("stickiness_metrics_report", {
5321
- enabled: this.config.enabled,
5322
- security_level: this.config.securityLevel,
5323
- cache_hits: hits,
5324
- cache_misses: misses,
5325
- verify_failures: this.metrics.verifyFailures,
5326
- associations_created: this.metrics.associationsCreated,
5327
- associations_expired: this.metrics.associationsExpired,
5328
- active_associations: this.aftAssociations.size,
5329
- sid_cache_entries: this.sidCache.size,
5330
- hit_rate: hitRate,
5500
+ this.metrics.verifyFailures += 1;
5501
+ logger$4.warning("aft_verification_failed", {
5502
+ envelope_id: envelope.id,
5503
+ replica_id: replicaId,
5504
+ error: verification.error,
5505
+ });
5506
+ return null;
5507
+ }
5508
+ this.storeAssociation(aftToken, {
5509
+ replicaId,
5510
+ token: aftToken,
5511
+ sid: verification.sid ?? "",
5512
+ exp: verification.exp ?? Math.floor(Date.now() / 1000) + this.defaultTtlSec,
5513
+ trustLevel: verification.trustLevel,
5514
+ scope: verification.scope ?? null,
5515
+ clientSid: verification.clientSid ?? null,
5331
5516
  });
5332
- }
5333
- async onDeliver(_node, envelope, context) {
5334
- logger$4.debug("stickiness_manager_on_deliver", {
5517
+ if (verification.clientSid) {
5518
+ this.sidCache.set(verification.clientSid, replicaId);
5519
+ logger$4.debug("sid_cache_updated", {
5520
+ envelope_id: envelope.id,
5521
+ client_sid: verification.clientSid,
5522
+ replica_id: replicaId,
5523
+ });
5524
+ }
5525
+ this.metrics.associationsCreated += 1;
5526
+ logger$4.debug("aft_association_created", {
5335
5527
  envelope_id: envelope.id,
5336
- origin_type: context?.originType ?? "unknown",
5337
- from_system_id: context?.fromSystemId ?? null,
5528
+ replica_id: replicaId,
5529
+ sid: verification.sid,
5530
+ exp: verification.exp,
5531
+ trust_level: verification.trustLevel,
5532
+ scope: verification.scope,
5338
5533
  });
5339
- if (context?.originType === DeliveryOriginType$1.DOWNSTREAM) {
5340
- const sourceRoute = context.fromSystemId;
5341
- if (sourceRoute) {
5342
- logger$4.debug("processing_downstream_envelope", {
5534
+ return this.config.clientEcho ? aftToken : null;
5535
+ }
5536
+ getStickyReplicaSegment(envelope, segments) {
5537
+ if (!this.config.enabled) {
5538
+ logger$4.debug("stickiness_disabled", { envelope_id: envelope.id });
5539
+ return null;
5540
+ }
5541
+ if (envelope.aft) {
5542
+ const replicaId = this.routeByAft(envelope.aft, envelope);
5543
+ if (replicaId) {
5544
+ this.metrics.cacheHits += 1;
5545
+ logger$4.debug("aft_routed_envelope", {
5343
5546
  envelope_id: envelope.id,
5344
- source_route: sourceRoute,
5547
+ replica_id: replicaId,
5548
+ routing_type: "aft_direct",
5345
5549
  });
5346
- if (this.config.securityLevel === StickinessMode.SID_ONLY &&
5347
- envelope.sid &&
5348
- !this.sidCache.has(envelope.sid)) {
5349
- this.sidCache.set(envelope.sid, sourceRoute);
5350
- logger$4.debug("sid_only_association_recorded", {
5550
+ return replicaId;
5551
+ }
5552
+ }
5553
+ if (envelope.sid) {
5554
+ const cachedReplica = this.sidCache.get(envelope.sid);
5555
+ if (cachedReplica) {
5556
+ if (this.config.securityLevel === StickinessMode.SID_ONLY) {
5557
+ this.metrics.cacheHits += 1;
5558
+ logger$4.debug("sid_cache_routed_envelope", {
5351
5559
  envelope_id: envelope.id,
5560
+ replica_id: cachedReplica,
5352
5561
  sid: envelope.sid,
5353
- replica_id: sourceRoute,
5354
- });
5355
- }
5356
- const hadInstruction = Boolean(extractAftInstruction(envelope));
5357
- const token = await this.handleOutboundEnvelope(envelope, sourceRoute);
5358
- if (hadInstruction) {
5359
- logger$4.debug("processed_aft_setter_instruction", {
5360
- envelope_id: envelope.id,
5361
- source_route: sourceRoute,
5362
- client_echo: Boolean(token),
5562
+ routing_type: "sid_only",
5363
5563
  });
5564
+ return cachedReplica;
5364
5565
  }
5365
- else {
5366
- logger$4.debug("no_aft_setter_instruction", {
5367
- envelope_id: envelope.id,
5368
- source_route: sourceRoute,
5369
- });
5566
+ for (const [token, association] of this.aftAssociations.entries()) {
5567
+ if (association.replicaId === cachedReplica &&
5568
+ !association.isExpired()) {
5569
+ envelope.aft = token;
5570
+ this.metrics.cacheHits += 1;
5571
+ logger$4.debug("sid_cache_routed_envelope", {
5572
+ envelope_id: envelope.id,
5573
+ replica_id: cachedReplica,
5574
+ sid: envelope.sid,
5575
+ routing_type: "sid_cache_with_aft",
5576
+ });
5577
+ return cachedReplica;
5578
+ }
5370
5579
  }
5371
- }
5372
- else {
5373
- logger$4.debug("downstream_envelope_without_source_route", {
5580
+ this.metrics.cacheHits += 1;
5581
+ logger$4.debug("sid_cache_routed_envelope", {
5374
5582
  envelope_id: envelope.id,
5583
+ replica_id: cachedReplica,
5584
+ sid: envelope.sid,
5585
+ routing_type: "sid_cache_direct",
5375
5586
  });
5587
+ return cachedReplica;
5376
5588
  }
5377
- }
5378
- else {
5379
- logger$4.debug("envelope_not_from_downstream", {
5589
+ logger$4.debug("no_cached_replica_for_sid", {
5380
5590
  envelope_id: envelope.id,
5591
+ sid: envelope.sid,
5381
5592
  });
5382
5593
  }
5383
- return envelope;
5384
- }
5385
- storeAssociation(token, data) {
5386
- if (this.aftAssociations.has(token)) {
5387
- this.aftAssociations.delete(token);
5388
- }
5389
- const association = new AFTAssociation(data);
5390
- this.aftAssociations.set(token, association);
5391
- while (this.aftAssociations.size > this.cacheMax) {
5392
- const oldest = this.aftAssociations.keys().next();
5393
- if (oldest.done) {
5394
- break;
5395
- }
5396
- const oldestToken = oldest.value;
5397
- this.removeAssociation(oldestToken);
5398
- }
5399
- }
5400
- removeAssociation(token) {
5401
- this.aftAssociations.delete(token);
5402
- for (const [sid, cachedToken] of this.sidCache.entries()) {
5403
- if (cachedToken === token) {
5404
- this.sidCache.delete(sid);
5405
- }
5406
- }
5407
- }
5408
- routeByAft(token, envelope) {
5409
- const association = this.aftAssociations.get(token);
5410
- if (!association) {
5411
- return null;
5412
- }
5413
- if (association.isExpired()) {
5414
- this.metrics.associationsExpired += 1;
5415
- this.removeAssociation(token);
5416
- return null;
5417
- }
5418
- if (this.verifier.securityLevel === StickinessMode.STRICT &&
5419
- association.isLowTrust()) {
5420
- logger$4.warning("rejecting_low_trust_association", {
5594
+ if (envelope.sid && Array.isArray(segments) && segments.length > 0) {
5595
+ const index = computeDeterministicIndex(envelope.sid, segments.length);
5596
+ const chosen = segments[index];
5597
+ this.metrics.cacheHits += 1;
5598
+ logger$4.debug("sid_based_deterministic_choice", {
5421
5599
  envelope_id: envelope.id,
5422
- replica_id: association.replicaId,
5423
- reason: "strict mode rejects low-trust associations",
5600
+ sid: envelope.sid,
5601
+ chosen,
5602
+ routing_type: "sid_deterministic",
5424
5603
  });
5425
- return null;
5604
+ return chosen;
5426
5605
  }
5427
- this.aftAssociations.delete(token);
5428
- this.aftAssociations.set(token, association);
5429
- return association.replicaId;
5430
- }
5431
- }
5432
- function extractAftInstruction(envelope) {
5433
- if (!envelope.meta) {
5606
+ this.metrics.cacheMisses += 1;
5607
+ logger$4.debug("no_stickiness_routing", {
5608
+ envelope_id: envelope.id,
5609
+ has_aft: Boolean(envelope.aft),
5610
+ has_sid: Boolean(envelope.sid),
5611
+ });
5434
5612
  return null;
5435
5613
  }
5436
- const meta = envelope.meta;
5437
- const nested = meta.set;
5438
- if (nested && typeof nested === "object" && !Array.isArray(nested)) {
5439
- const aftValue = nested.aft;
5440
- if (aftValue !== undefined) {
5441
- return aftValue;
5442
- }
5443
- }
5444
- if (meta["set.aft"] !== undefined) {
5445
- return meta["set.aft"];
5446
- }
5447
- return null;
5448
- }
5449
- function computeDeterministicIndex(key, modulo) {
5450
- if (modulo <= 0) {
5451
- return 0;
5452
- }
5453
- let hash = 0;
5454
- for (let i = 0; i < key.length; i += 1) {
5455
- hash = (hash * 31 + key.charCodeAt(i)) >>> 0;
5456
- }
5457
- return hash % modulo;
5458
- }
5459
-
5460
- const FACTORY_META$7 = {
5461
- base: LOAD_BALANCER_STICKINESS_MANAGER_FACTORY_BASE_TYPE,
5462
- key: "AFTLoadBalancerStickinessManager",
5463
- };
5464
- const DEFAULT_VALUES$1 = {
5465
- enabled: true,
5466
- clientEcho: false,
5467
- defaultTtlSec: 30,
5468
- cacheMax: 100000,
5469
- securityLevel: StickinessMode.SIGNED_OPTIONAL,
5470
- maxTtlSec: 7200,
5471
- };
5472
- function toBoolean(value, fallback) {
5473
- return typeof value === "boolean" ? value : fallback;
5474
- }
5475
- function toNumber(value, fallback) {
5476
- if (typeof value === "number" && Number.isFinite(value)) {
5477
- return value;
5478
- }
5479
- return fallback;
5480
- }
5481
- function normalizeConfig$4(config) {
5482
- const record = (config ?? {});
5483
- const normalizedSecurity = record.securityLevel
5484
- ? normalizeStickinessMode(record.securityLevel)
5485
- : DEFAULT_VALUES$1.securityLevel;
5486
- return {
5487
- ...record,
5488
- type: "AFTLoadBalancerStickinessManager",
5489
- enabled: toBoolean(record.enabled, DEFAULT_VALUES$1.enabled),
5490
- clientEcho: toBoolean(record.clientEcho, DEFAULT_VALUES$1.clientEcho),
5491
- defaultTtlSec: toNumber(record.defaultTtlSec, DEFAULT_VALUES$1.defaultTtlSec),
5492
- cacheMax: toNumber(record.cacheMax, DEFAULT_VALUES$1.cacheMax),
5493
- securityLevel: normalizedSecurity,
5494
- maxTtlSec: toNumber(record.maxTtlSec, DEFAULT_VALUES$1.maxTtlSec),
5495
- };
5496
- }
5497
- class AFTLoadBalancerStickinessManagerFactory extends LoadBalancerStickinessManagerFactory {
5498
- constructor() {
5499
- super(...arguments);
5500
- this.type = "AFTLoadBalancerStickinessManager";
5501
- this.isDefault = false;
5502
- }
5503
- async create(config, keyProvider, verifier) {
5504
- const resolvedConfig = normalizeConfig$4(config);
5505
- let effectiveVerifier = verifier ?? null;
5506
- if (!effectiveVerifier && keyProvider) {
5507
- effectiveVerifier = createAftVerifier({
5508
- securityLevel: resolvedConfig.securityLevel ?? DEFAULT_VALUES$1.securityLevel,
5509
- keyProvider,
5510
- defaultTtlSec: resolvedConfig.defaultTtlSec ?? DEFAULT_VALUES$1.defaultTtlSec,
5614
+ cleanupExpiredAssociations() {
5615
+ const now = Math.floor(Date.now() / 1000);
5616
+ const expiredTokens = [];
5617
+ for (const [token, association] of this.aftAssociations.entries()) {
5618
+ if (association.isExpired(now)) {
5619
+ expiredTokens.push(token);
5620
+ }
5621
+ }
5622
+ for (const token of expiredTokens) {
5623
+ this.removeAssociation(token);
5624
+ }
5625
+ if (expiredTokens.length > 0) {
5626
+ this.metrics.associationsExpired += expiredTokens.length;
5627
+ logger$4.debug("cleaned_expired_associations", {
5628
+ count: expiredTokens.length,
5511
5629
  });
5512
5630
  }
5513
- if (!effectiveVerifier) {
5514
- throw new Error("AFTLoadBalancerStickinessManagerFactory requires an AFT verifier or key provider");
5631
+ }
5632
+ replicaLeft(replicaId) {
5633
+ const tokensToRemove = [];
5634
+ for (const [token, association] of this.aftAssociations.entries()) {
5635
+ if (association.replicaId === replicaId) {
5636
+ tokensToRemove.push(token);
5637
+ }
5638
+ }
5639
+ for (const token of tokensToRemove) {
5640
+ this.removeAssociation(token);
5641
+ }
5642
+ if (tokensToRemove.length > 0) {
5643
+ logger$4.debug("removed_associations_for_departed_replica", {
5644
+ replica_id: replicaId,
5645
+ count: tokensToRemove.length,
5646
+ });
5515
5647
  }
5516
- return new AFTLoadBalancerStickinessManager(resolvedConfig, effectiveVerifier);
5517
5648
  }
5518
- }
5519
-
5520
- var aftLoadBalancerStickinessManagerFactory = /*#__PURE__*/Object.freeze({
5521
- __proto__: null,
5522
- AFTLoadBalancerStickinessManagerFactory: AFTLoadBalancerStickinessManagerFactory,
5523
- FACTORY_META: FACTORY_META$7,
5524
- default: AFTLoadBalancerStickinessManagerFactory
5525
- });
5526
-
5527
- const logger$3 = getLogger("naylence.fame.stickiness.aft_replica_stickiness_manager");
5528
- function isStickinessRequired(context) {
5529
- if (typeof context.stickinessRequired === "boolean") {
5530
- return context.stickinessRequired;
5649
+ handleReplicaLeft(replicaId) {
5650
+ this.replicaLeft(replicaId);
5651
+ logger$4.debug("stickiness_replica_cleanup", { replica_id: replicaId });
5531
5652
  }
5532
- if (typeof context.stickiness_required === "boolean") {
5533
- return context.stickiness_required;
5653
+ getMetrics() {
5654
+ return {
5655
+ ...this.metrics,
5656
+ cacheSize: this.aftAssociations.size,
5657
+ sidCacheSize: this.sidCache.size,
5658
+ };
5534
5659
  }
5535
- return false;
5536
- }
5537
- class AFTReplicaStickinessManager extends BaseNodeEventListener {
5538
- constructor(options = {}) {
5539
- super();
5540
- this.securityLevel =
5541
- normalizeStickinessMode(options.securityLevel ?? DEFAULT_STICKINESS_SECURITY_LEVEL) ?? DEFAULT_STICKINESS_SECURITY_LEVEL;
5542
- this.aftHelper = options.aftHelper ?? null;
5543
- this.maxTtlSec = options.maxTtlSec ?? 7200;
5544
- this.isInitialized = this.aftHelper !== null;
5545
- this.negotiatedStickiness = null;
5546
- if (this.aftHelper) {
5547
- logger$3.debug("aft_replica_stickiness_manager_initialized", {
5548
- helper_type: this.aftHelper.signer.constructor.name,
5549
- security_level: this.aftHelper.signer.securityLevel,
5550
- max_ttl_sec: this.aftHelper.maxTtlSec,
5551
- });
5552
- }
5553
- else {
5554
- logger$3.debug("aft_replica_stickiness_manager_created", {
5555
- security_level: this.securityLevel,
5556
- max_ttl_sec: this.maxTtlSec,
5557
- });
5660
+ getAssociations() {
5661
+ const result = {};
5662
+ for (const [token, association] of this.aftAssociations.entries()) {
5663
+ result[token] = {
5664
+ replica_id: association.replicaId,
5665
+ sid: association.sid,
5666
+ client_sid: association.clientSid,
5667
+ exp: association.exp,
5668
+ trust_level: association.trustLevel,
5669
+ scope: association.scope,
5670
+ created_at: association.createdAt,
5671
+ expired: association.isExpired(),
5672
+ };
5558
5673
  }
5674
+ return result;
5559
5675
  }
5560
- offer() {
5561
- return { mode: "aft", supportedModes: ["aft", "attr"], version: 1 };
5676
+ getStickinessMetrics() {
5677
+ return this.getMetrics();
5562
5678
  }
5563
- accept(stickiness) {
5564
- this.negotiatedStickiness = stickiness ?? null;
5565
- logger$3.debug("replica_stickiness_policy_set", {
5566
- enabled: stickiness?.enabled ?? null,
5567
- mode: stickiness?.mode ?? null,
5568
- ttl: stickiness?.ttlSec ?? null,
5679
+ logMetrics() {
5680
+ const hits = this.metrics.cacheHits;
5681
+ const misses = this.metrics.cacheMisses;
5682
+ const total = hits + misses;
5683
+ const hitRate = total > 0 ? Math.round((hits / total) * 10000) / 100 : 0;
5684
+ logger$4.info("stickiness_metrics_report", {
5685
+ enabled: this.config.enabled,
5686
+ security_level: this.config.securityLevel,
5687
+ cache_hits: hits,
5688
+ cache_misses: misses,
5689
+ verify_failures: this.metrics.verifyFailures,
5690
+ associations_created: this.metrics.associationsCreated,
5691
+ associations_expired: this.metrics.associationsExpired,
5692
+ active_associations: this.aftAssociations.size,
5693
+ sid_cache_entries: this.sidCache.size,
5694
+ hit_rate: hitRate,
5569
5695
  });
5570
5696
  }
5571
- async onForwardUpstream(_node, envelope, context) {
5572
- if (!context) {
5573
- return envelope;
5574
- }
5575
- const helper = this.aftHelper;
5576
- if (!helper) {
5577
- logger$3.debug("aft_helper_not_ready_skip_injection", {
5578
- envelope_id: envelope.id,
5579
- delivery_origin: context.originType ?? null,
5580
- reason: "not_initialized",
5581
- });
5582
- return envelope;
5583
- }
5584
- const stickinessContext = context;
5585
- if (isStickinessRequired(stickinessContext) &&
5586
- context.originType === DeliveryOriginType$1.LOCAL) {
5587
- if (this.negotiatedStickiness) {
5588
- const negotiated = this.negotiatedStickiness;
5589
- if (negotiated.enabled === false ||
5590
- (negotiated.mode !== null &&
5591
- negotiated.mode !== undefined &&
5592
- negotiated.mode !== "aft")) {
5593
- logger$3.debug("aft_injection_skipped_due_to_policy", {
5697
+ async onDeliver(_node, envelope, context) {
5698
+ logger$4.debug("stickiness_manager_on_deliver", {
5699
+ envelope_id: envelope.id,
5700
+ origin_type: context?.originType ?? "unknown",
5701
+ from_system_id: context?.fromSystemId ?? null,
5702
+ });
5703
+ if (context?.originType === DeliveryOriginType$1.DOWNSTREAM) {
5704
+ const sourceRoute = context.fromSystemId;
5705
+ if (sourceRoute) {
5706
+ logger$4.debug("processing_downstream_envelope", {
5707
+ envelope_id: envelope.id,
5708
+ source_route: sourceRoute,
5709
+ });
5710
+ if (this.config.securityLevel === StickinessMode.SID_ONLY &&
5711
+ envelope.sid &&
5712
+ !this.sidCache.has(envelope.sid)) {
5713
+ this.sidCache.set(envelope.sid, sourceRoute);
5714
+ logger$4.debug("sid_only_association_recorded", {
5594
5715
  envelope_id: envelope.id,
5595
- policy_mode: negotiated.mode ?? null,
5596
- policy_enabled: negotiated.enabled ?? null,
5716
+ sid: envelope.sid,
5717
+ replica_id: sourceRoute,
5718
+ });
5719
+ }
5720
+ const hadInstruction = Boolean(extractAftInstruction(envelope));
5721
+ const token = await this.handleOutboundEnvelope(envelope, sourceRoute);
5722
+ if (hadInstruction) {
5723
+ logger$4.debug("processed_aft_setter_instruction", {
5724
+ envelope_id: envelope.id,
5725
+ source_route: sourceRoute,
5726
+ client_echo: Boolean(token),
5727
+ });
5728
+ }
5729
+ else {
5730
+ logger$4.debug("no_aft_setter_instruction", {
5731
+ envelope_id: envelope.id,
5732
+ source_route: sourceRoute,
5597
5733
  });
5598
- return envelope;
5599
5734
  }
5600
- }
5601
- logger$3.debug("applying_aft_for_upstream_stickiness_required", {
5602
- envelope_id: envelope.id,
5603
- from_system_id: context.fromSystemId ?? null,
5604
- delivery_origin: context.originType ?? null,
5605
- });
5606
- const success = await helper.requestStickiness(envelope, {
5607
- ttlSec: null,
5608
- scope: "node",
5609
- context: stickinessContext,
5610
- });
5611
- if (success) {
5612
- logger$3.debug("aft_token_applied_via_context_flag_upstream", {
5613
- envelope_id: envelope.id,
5614
- from_system_id: context.fromSystemId ?? null,
5615
- delivery_origin: context.originType ?? null,
5616
- });
5617
5735
  }
5618
5736
  else {
5619
- logger$3.debug("aft_token_not_applied_upstream", {
5737
+ logger$4.debug("downstream_envelope_without_source_route", {
5620
5738
  envelope_id: envelope.id,
5621
- delivery_origin: context.originType ?? null,
5622
- reason: "helper_returned_false",
5623
5739
  });
5624
5740
  }
5625
5741
  }
5626
- return envelope;
5627
- }
5628
- async onNodeStarted(node) {
5629
- if (!this.isInitialized) {
5630
- await this.initializeAftHelper(node);
5631
- return;
5632
- }
5633
- if (this.aftHelper && node.sid) {
5634
- this.updateNodeSid(node.sid);
5635
- logger$3.debug("aft_replica_stickiness_manager_sid_updated", {
5636
- node_id: node.id ?? "unknown",
5637
- node_sid: node.sid,
5638
- security_level: this.aftHelper.signer.securityLevel,
5639
- });
5640
- }
5641
- else if (!node.sid) {
5642
- logger$3.warning("aft_replica_stickiness_manager_no_sid_available", {
5643
- node_id: node.id ?? "unknown",
5644
- });
5645
- }
5646
5742
  else {
5647
- logger$3.error("aft_replica_stickiness_manager_node_missing_sid", {
5648
- node_type: node.constructor?.name ?? typeof node,
5743
+ logger$4.debug("envelope_not_from_downstream", {
5744
+ envelope_id: envelope.id,
5649
5745
  });
5650
5746
  }
5747
+ return envelope;
5651
5748
  }
5652
- updateNodeSid(nodeSid) {
5653
- if (this.aftHelper) {
5654
- this.aftHelper.nodeSid = nodeSid;
5655
- logger$3.debug("aft_replica_stickiness_manager_sid_updated", {
5656
- new_sid: nodeSid,
5657
- });
5749
+ storeAssociation(token, data) {
5750
+ if (this.aftAssociations.has(token)) {
5751
+ this.aftAssociations.delete(token);
5658
5752
  }
5659
- }
5660
- async initializeAftHelper(node) {
5661
- const nodeSid = node.sid;
5662
- if (!nodeSid) {
5663
- logger$3.error("aft_replica_stickiness_manager_cannot_initialize_no_sid", {
5664
- node_id: node.id ?? "unknown",
5665
- });
5666
- return;
5753
+ const association = new AFTAssociation(data);
5754
+ this.aftAssociations.set(token, association);
5755
+ while (this.aftAssociations.size > this.cacheMax) {
5756
+ const oldest = this.aftAssociations.keys().next();
5757
+ if (oldest.done) {
5758
+ break;
5759
+ }
5760
+ const oldestToken = oldest.value;
5761
+ this.removeAssociation(oldestToken);
5667
5762
  }
5668
- const cryptoProvider = node.cryptoProvider ?? null;
5669
- if (!cryptoProvider) {
5670
- logger$3.error("aft_replica_stickiness_manager_cannot_initialize_no_crypto_provider", {
5671
- node_id: node.id ?? "unknown",
5672
- });
5673
- return;
5763
+ }
5764
+ removeAssociation(token) {
5765
+ this.aftAssociations.delete(token);
5766
+ for (const [sid, cachedToken] of this.sidCache.entries()) {
5767
+ if (cachedToken === token) {
5768
+ this.sidCache.delete(sid);
5769
+ }
5674
5770
  }
5675
- const keyId = typeof cryptoProvider.signatureKeyId === "string" &&
5676
- cryptoProvider.signatureKeyId.length > 0
5677
- ? cryptoProvider.signatureKeyId
5678
- : "default-key-id";
5679
- const privateKeyPem = typeof cryptoProvider.signingPrivatePem === "string"
5680
- ? cryptoProvider.signingPrivatePem
5681
- : null;
5682
- if (this.securityLevel === StickinessMode.STRICT && !privateKeyPem) {
5683
- logger$3.error("aft_replica_stickiness_manager_initialization_failed", {
5684
- node_id: node.id ?? "unknown",
5685
- error: "Missing signing private key for strict security level",
5686
- });
5687
- return;
5771
+ }
5772
+ routeByAft(token, envelope) {
5773
+ const association = this.aftAssociations.get(token);
5774
+ if (!association) {
5775
+ return null;
5688
5776
  }
5689
- try {
5690
- const helper = createAftHelper({
5691
- securityLevel: this.securityLevel,
5692
- nodeSid,
5693
- kid: keyId,
5694
- privateKeyPem,
5695
- maxTtlSec: this.maxTtlSec,
5696
- });
5697
- this.aftHelper = helper;
5698
- this.isInitialized = true;
5699
- logger$3.debug("aft_replica_stickiness_manager_initialized", {
5700
- node_id: node.id ?? "unknown",
5701
- node_sid: nodeSid,
5702
- key_id: keyId,
5703
- security_level: helper.signer.securityLevel,
5704
- });
5777
+ if (association.isExpired()) {
5778
+ this.metrics.associationsExpired += 1;
5779
+ this.removeAssociation(token);
5780
+ return null;
5705
5781
  }
5706
- catch (error) {
5707
- logger$3.error("aft_replica_stickiness_manager_initialization_failed", {
5708
- node_id: node.id ?? "unknown",
5709
- error: error instanceof Error ? error.message : String(error),
5782
+ if (this.verifier.securityLevel === StickinessMode.STRICT &&
5783
+ association.isLowTrust()) {
5784
+ logger$4.warning("rejecting_low_trust_association", {
5785
+ envelope_id: envelope.id,
5786
+ replica_id: association.replicaId,
5787
+ reason: "strict mode rejects low-trust associations",
5710
5788
  });
5789
+ return null;
5711
5790
  }
5791
+ this.aftAssociations.delete(token);
5792
+ this.aftAssociations.set(token, association);
5793
+ return association.replicaId;
5712
5794
  }
5713
- get signer() {
5714
- return this.aftHelper?.signer ?? null;
5795
+ }
5796
+ function extractAftInstruction(envelope) {
5797
+ if (!envelope.meta) {
5798
+ return null;
5715
5799
  }
5716
- getHelper() {
5717
- return this.aftHelper;
5800
+ const meta = envelope.meta;
5801
+ const nested = meta.set;
5802
+ if (nested && typeof nested === "object" && !Array.isArray(nested)) {
5803
+ const aftValue = nested.aft;
5804
+ if (aftValue !== undefined) {
5805
+ return aftValue;
5806
+ }
5807
+ }
5808
+ if (meta["set.aft"] !== undefined) {
5809
+ return meta["set.aft"];
5718
5810
  }
5811
+ return null;
5719
5812
  }
5720
- function createAftReplicaStickinessManager(aftHelper) {
5721
- return new AFTReplicaStickinessManager({ aftHelper });
5813
+ function computeDeterministicIndex(key, modulo) {
5814
+ if (modulo <= 0) {
5815
+ return 0;
5816
+ }
5817
+ let hash = 0;
5818
+ for (let i = 0; i < key.length; i += 1) {
5819
+ hash = (hash * 31 + key.charCodeAt(i)) >>> 0;
5820
+ }
5821
+ return hash % modulo;
5722
5822
  }
5723
5823
 
5724
- const FACTORY_META$6 = {
5725
- base: REPLICA_STICKINESS_MANAGER_FACTORY_BASE_TYPE,
5726
- key: "AFTReplicaStickinessManager",
5824
+ const FACTORY_META$7 = {
5825
+ base: LOAD_BALANCER_STICKINESS_MANAGER_FACTORY_BASE_TYPE,
5826
+ key: "AFTLoadBalancerStickinessManager",
5727
5827
  };
5728
- const DEFAULT_VALUES = {
5828
+ const DEFAULT_VALUES$1 = {
5829
+ enabled: true,
5830
+ clientEcho: false,
5831
+ defaultTtlSec: 30,
5832
+ cacheMax: 100000,
5729
5833
  securityLevel: StickinessMode.SIGNED_OPTIONAL,
5730
5834
  maxTtlSec: 7200,
5731
5835
  };
5732
- function normalizeConfig$3(config) {
5836
+ function toBoolean(value, fallback) {
5837
+ return typeof value === "boolean" ? value : fallback;
5838
+ }
5839
+ function toNumber(value, fallback) {
5840
+ if (typeof value === "number" && Number.isFinite(value)) {
5841
+ return value;
5842
+ }
5843
+ return fallback;
5844
+ }
5845
+ function normalizeConfig$4(config) {
5733
5846
  const record = (config ?? {});
5734
5847
  const normalizedSecurity = record.securityLevel
5735
5848
  ? normalizeStickinessMode(record.securityLevel)
5736
- : DEFAULT_VALUES.securityLevel;
5737
- const securityLevel = normalizedSecurity ?? DEFAULT_VALUES.securityLevel;
5738
- const maxTtlSecValue = typeof record.maxTtlSec === "number" && Number.isFinite(record.maxTtlSec)
5739
- ? Math.max(0, Math.floor(record.maxTtlSec))
5740
- : DEFAULT_VALUES.maxTtlSec;
5849
+ : DEFAULT_VALUES$1.securityLevel;
5741
5850
  return {
5742
5851
  ...record,
5743
- type: "AFTReplicaStickinessManager",
5744
- securityLevel,
5745
- maxTtlSec: maxTtlSecValue,
5852
+ type: "AFTLoadBalancerStickinessManager",
5853
+ enabled: toBoolean(record.enabled, DEFAULT_VALUES$1.enabled),
5854
+ clientEcho: toBoolean(record.clientEcho, DEFAULT_VALUES$1.clientEcho),
5855
+ defaultTtlSec: toNumber(record.defaultTtlSec, DEFAULT_VALUES$1.defaultTtlSec),
5856
+ cacheMax: toNumber(record.cacheMax, DEFAULT_VALUES$1.cacheMax),
5857
+ securityLevel: normalizedSecurity,
5858
+ maxTtlSec: toNumber(record.maxTtlSec, DEFAULT_VALUES$1.maxTtlSec),
5746
5859
  };
5747
5860
  }
5748
- class AFTReplicaStickinessManagerFactory extends ReplicaStickinessManagerFactory {
5861
+ class AFTLoadBalancerStickinessManagerFactory extends LoadBalancerStickinessManagerFactory {
5749
5862
  constructor() {
5750
5863
  super(...arguments);
5751
- this.type = FACTORY_META$6.key;
5752
- this.isDefault = true;
5864
+ this.type = "AFTLoadBalancerStickinessManager";
5865
+ this.isDefault = false;
5753
5866
  }
5754
- async create(config, dependencies) {
5755
- const resolvedConfig = normalizeConfig$3(config);
5756
- const helper = dependencies?.aftHelper ?? null;
5757
- const securityLevel = normalizeStickinessMode(resolvedConfig.securityLevel ?? DEFAULT_VALUES.securityLevel) ?? DEFAULT_VALUES.securityLevel;
5758
- const maxTtlSec = typeof resolvedConfig.maxTtlSec === "number" &&
5759
- Number.isFinite(resolvedConfig.maxTtlSec)
5760
- ? Math.max(0, Math.floor(resolvedConfig.maxTtlSec))
5761
- : DEFAULT_VALUES.maxTtlSec;
5762
- return new AFTReplicaStickinessManager({
5763
- securityLevel,
5764
- maxTtlSec,
5765
- aftHelper: helper,
5766
- });
5867
+ async create(config, keyProvider, verifier) {
5868
+ const resolvedConfig = normalizeConfig$4(config);
5869
+ let effectiveVerifier = verifier ?? null;
5870
+ if (!effectiveVerifier && keyProvider) {
5871
+ effectiveVerifier = createAftVerifier({
5872
+ securityLevel: resolvedConfig.securityLevel ?? DEFAULT_VALUES$1.securityLevel,
5873
+ keyProvider,
5874
+ defaultTtlSec: resolvedConfig.defaultTtlSec ?? DEFAULT_VALUES$1.defaultTtlSec,
5875
+ });
5876
+ }
5877
+ if (!effectiveVerifier) {
5878
+ throw new Error("AFTLoadBalancerStickinessManagerFactory requires an AFT verifier or key provider");
5879
+ }
5880
+ return new AFTLoadBalancerStickinessManager(resolvedConfig, effectiveVerifier);
5767
5881
  }
5768
5882
  }
5769
5883
 
5770
- var aftReplicaStickinessManagerFactory = /*#__PURE__*/Object.freeze({
5884
+ var aftLoadBalancerStickinessManagerFactory = /*#__PURE__*/Object.freeze({
5771
5885
  __proto__: null,
5772
- AFTReplicaStickinessManagerFactory: AFTReplicaStickinessManagerFactory,
5773
- FACTORY_META: FACTORY_META$6,
5774
- default: AFTReplicaStickinessManagerFactory
5886
+ AFTLoadBalancerStickinessManagerFactory: AFTLoadBalancerStickinessManagerFactory,
5887
+ FACTORY_META: FACTORY_META$7,
5888
+ default: AFTLoadBalancerStickinessManagerFactory
5775
5889
  });
5776
5890
 
5777
- const logger$2 = getLogger("naylence.fame.welcome.advanced_welcome_service");
5778
- const ENV_VAR_SHOW_ENVELOPES = "FAME_SHOW_ENVELOPES";
5779
- const DEFAULT_TTL_SEC = 3600;
5780
- const showEnvelopes = typeof process !== "undefined" &&
5781
- process.env?.[ENV_VAR_SHOW_ENVELOPES] === "true";
5782
- function nowUtc() {
5783
- return new Date();
5784
- }
5785
- function formatTimestampForConsole() {
5786
- return color(formatTimestamp(), AnsiColor.GRAY);
5787
- }
5788
- function prettyModel(value) {
5789
- try {
5790
- return jsonDumps(value);
5791
- }
5792
- catch (error) {
5793
- return String(error);
5794
- }
5795
- }
5796
- function coercePlacementMetadataValue(metadata, camelCaseKey, snakeCaseKey) {
5797
- if (!metadata) {
5798
- return undefined;
5799
- }
5800
- const record = metadata;
5801
- if (record[camelCaseKey] !== undefined) {
5802
- return record[camelCaseKey];
5891
+ const logger$3 = getLogger("naylence.fame.stickiness.aft_replica_stickiness_manager");
5892
+ function isStickinessRequired(context) {
5893
+ if (typeof context.stickinessRequired === "boolean") {
5894
+ return context.stickinessRequired;
5803
5895
  }
5804
- if (record[snakeCaseKey] !== undefined) {
5805
- return record[snakeCaseKey];
5896
+ if (typeof context.stickiness_required === "boolean") {
5897
+ return context.stickiness_required;
5806
5898
  }
5807
- return undefined;
5899
+ return false;
5808
5900
  }
5809
- class AdvancedWelcomeService {
5810
- constructor(options) {
5811
- this.placementStrategy = options.placementStrategy;
5812
- this.transportProvisioner = options.transportProvisioner;
5813
- this.tokenIssuer = options.tokenIssuer;
5814
- this.authorizer = options.authorizer ?? null;
5815
- this.caServiceUrl = options.caServiceUrl;
5816
- this.ttlSec =
5817
- typeof options.ttlSec === "number" && Number.isFinite(options.ttlSec)
5818
- ? Math.max(0, options.ttlSec)
5819
- : DEFAULT_TTL_SEC;
5820
- logger$2.debug("initialized_advanced_welcome_service", {
5821
- ca_service_url: this.caServiceUrl,
5822
- ttl_sec: this.ttlSec,
5823
- });
5824
- }
5825
- async handleHello(hello, metadata) {
5826
- const fullMetadata = metadata
5827
- ? { ...metadata }
5828
- : {};
5829
- const trimmedSystemId = typeof hello.systemId === "string" ? hello.systemId.trim() : "";
5830
- const systemId = trimmedSystemId.length > 0 ? trimmedSystemId : generateId();
5831
- const wasAssigned = trimmedSystemId.length === 0;
5832
- const normalizedHello = {
5833
- ...hello,
5834
- systemId,
5835
- };
5836
- if (showEnvelopes) {
5837
- // eslint-disable-next-line no-console
5838
- console.log(`\n${formatTimestampForConsole()} - ${color("Received envelope 📨", AnsiColor.BLUE)}\n${prettyModel(normalizedHello)}`);
5901
+ class AFTReplicaStickinessManager extends BaseNodeEventListener {
5902
+ constructor(options = {}) {
5903
+ super();
5904
+ this.securityLevel =
5905
+ normalizeStickinessMode(options.securityLevel ?? DEFAULT_STICKINESS_SECURITY_LEVEL) ?? DEFAULT_STICKINESS_SECURITY_LEVEL;
5906
+ this.aftHelper = options.aftHelper ?? null;
5907
+ this.maxTtlSec = options.maxTtlSec ?? 7200;
5908
+ this.isInitialized = this.aftHelper !== null;
5909
+ this.negotiatedStickiness = null;
5910
+ if (this.aftHelper) {
5911
+ logger$3.debug("aft_replica_stickiness_manager_initialized", {
5912
+ helper_type: this.aftHelper.signer.constructor.name,
5913
+ security_level: this.aftHelper.signer.securityLevel,
5914
+ max_ttl_sec: this.aftHelper.maxTtlSec,
5915
+ });
5916
+ }
5917
+ else {
5918
+ logger$3.debug("aft_replica_stickiness_manager_created", {
5919
+ security_level: this.securityLevel,
5920
+ max_ttl_sec: this.maxTtlSec,
5921
+ });
5839
5922
  }
5840
- logger$2.debug("starting_hello_frame_processing", {
5841
- instanceId: normalizedHello.instanceId,
5842
- systemId,
5843
- logicals: normalizedHello.logicals,
5844
- capabilities: normalizedHello.capabilities,
5845
- ttlSec: this.ttlSec,
5923
+ }
5924
+ offer() {
5925
+ return { mode: "aft", supportedModes: ["aft", "attr"], version: 1 };
5926
+ }
5927
+ accept(stickiness) {
5928
+ this.negotiatedStickiness = stickiness ?? null;
5929
+ logger$3.debug("replica_stickiness_policy_set", {
5930
+ enabled: stickiness?.enabled ?? null,
5931
+ mode: stickiness?.mode ?? null,
5932
+ ttl: stickiness?.ttlSec ?? null,
5846
5933
  });
5847
- const now = nowUtc();
5848
- const expiry = new Date(now.getTime() + this.ttlSec * 1000);
5849
- if (normalizedHello.instanceId) {
5850
- if (fullMetadata.instanceId === undefined) {
5851
- fullMetadata.instanceId = normalizedHello.instanceId;
5852
- }
5853
- if (fullMetadata.instance_id === undefined) {
5854
- fullMetadata.instance_id = normalizedHello.instanceId;
5855
- }
5934
+ }
5935
+ async onForwardUpstream(_node, envelope, context) {
5936
+ if (!context) {
5937
+ return envelope;
5856
5938
  }
5857
- logger$2.debug("system_id_assignment_completed", {
5858
- systemId,
5859
- wasAssigned,
5860
- });
5861
- if (normalizedHello.logicals?.length) {
5862
- logger$2.debug("validating_logicals_for_dns_compatibility", {
5863
- logicals: normalizedHello.logicals,
5939
+ const helper = this.aftHelper;
5940
+ if (!helper) {
5941
+ logger$3.debug("aft_helper_not_ready_skip_injection", {
5942
+ envelope_id: envelope.id,
5943
+ delivery_origin: context.originType ?? null,
5944
+ reason: "not_initialized",
5864
5945
  });
5865
- const [pathsValid, pathError] = validateHostLogicals(normalizedHello.logicals);
5866
- if (!pathsValid) {
5867
- logger$2.error("logical_validation_failed", {
5868
- error: pathError,
5869
- logicals: normalizedHello.logicals,
5946
+ return envelope;
5947
+ }
5948
+ const stickinessContext = context;
5949
+ if (isStickinessRequired(stickinessContext) &&
5950
+ context.originType === DeliveryOriginType$1.LOCAL) {
5951
+ if (this.negotiatedStickiness) {
5952
+ const negotiated = this.negotiatedStickiness;
5953
+ if (negotiated.enabled === false ||
5954
+ (negotiated.mode !== null &&
5955
+ negotiated.mode !== undefined &&
5956
+ negotiated.mode !== "aft")) {
5957
+ logger$3.debug("aft_injection_skipped_due_to_policy", {
5958
+ envelope_id: envelope.id,
5959
+ policy_mode: negotiated.mode ?? null,
5960
+ policy_enabled: negotiated.enabled ?? null,
5961
+ });
5962
+ return envelope;
5963
+ }
5964
+ }
5965
+ logger$3.debug("applying_aft_for_upstream_stickiness_required", {
5966
+ envelope_id: envelope.id,
5967
+ from_system_id: context.fromSystemId ?? null,
5968
+ delivery_origin: context.originType ?? null,
5969
+ });
5970
+ const success = await helper.requestStickiness(envelope, {
5971
+ ttlSec: null,
5972
+ scope: "node",
5973
+ context: stickinessContext,
5974
+ });
5975
+ if (success) {
5976
+ logger$3.debug("aft_token_applied_via_context_flag_upstream", {
5977
+ envelope_id: envelope.id,
5978
+ from_system_id: context.fromSystemId ?? null,
5979
+ delivery_origin: context.originType ?? null,
5980
+ });
5981
+ }
5982
+ else {
5983
+ logger$3.debug("aft_token_not_applied_upstream", {
5984
+ envelope_id: envelope.id,
5985
+ delivery_origin: context.originType ?? null,
5986
+ reason: "helper_returned_false",
5870
5987
  });
5871
- throw new Error(`Invalid logical format: ${pathError}`);
5872
5988
  }
5873
- logger$2.debug("logicals_validation_successful");
5874
5989
  }
5875
- logger$2.debug("requesting_node_placement", { systemId });
5876
- const placementResult = await this.placementStrategy.place(normalizedHello);
5877
- if (!placementResult.accept) {
5878
- logger$2.error("node_placement_rejected", {
5879
- systemId,
5880
- reason: placementResult.reason,
5990
+ return envelope;
5991
+ }
5992
+ async onNodeStarted(node) {
5993
+ if (!this.isInitialized) {
5994
+ await this.initializeAftHelper(node);
5995
+ return;
5996
+ }
5997
+ if (this.aftHelper && node.sid) {
5998
+ this.updateNodeSid(node.sid);
5999
+ logger$3.debug("aft_replica_stickiness_manager_sid_updated", {
6000
+ node_id: node.id ?? "unknown",
6001
+ node_sid: node.sid,
6002
+ security_level: this.aftHelper.signer.securityLevel,
5881
6003
  });
5882
- throw new Error(placementResult.reason || "Node not accepted");
5883
6004
  }
5884
- const assignedPath = placementResult.assignedPath;
5885
- logger$2.debug("node_placement_accepted", {
5886
- systemId,
5887
- assignedPath,
5888
- targetPhysicalPath: placementResult.targetPhysicalPath ?? null,
5889
- targetSystemId: placementResult.targetSystemId ?? null,
5890
- });
5891
- const acceptedCapabilities = coercePlacementMetadataValue(placementResult.metadata, "acceptedCapabilities", "accepted_capabilities") ??
5892
- normalizedHello.capabilities ??
5893
- null;
5894
- const acceptedLogicals = coercePlacementMetadataValue(placementResult.metadata, "acceptedLogicals", "accepted_logicals") ??
5895
- normalizedHello.logicals ??
5896
- null;
5897
- logger$2.debug("processing_placement_result_metadata", {
5898
- acceptedCapabilities,
5899
- acceptedLogicals,
5900
- hasPlacementMetadata: placementResult.metadata !== undefined &&
5901
- placementResult.metadata !== null,
5902
- });
5903
- const connectionGrants = [];
5904
- const metadataInstanceId = (typeof fullMetadata.instanceId === "string" &&
5905
- fullMetadata.instanceId) ||
5906
- (typeof fullMetadata.instance_id === "string" &&
5907
- fullMetadata.instance_id) ||
5908
- normalizedHello.instanceId ||
5909
- generateId();
5910
- if (placementResult.targetSystemId) {
5911
- logger$2.debug("issuing_node_attach_token", {
5912
- systemId,
5913
- assignedPath,
6005
+ else if (!node.sid) {
6006
+ logger$3.warning("aft_replica_stickiness_manager_no_sid_available", {
6007
+ node_id: node.id ?? "unknown",
5914
6008
  });
5915
- const nodeAttachToken = await this.tokenIssuer.issue({
5916
- aud: placementResult.targetPhysicalPath,
5917
- system_id: systemId,
5918
- parent_path: placementResult.targetPhysicalPath,
5919
- assigned_path: placementResult.assignedPath,
5920
- accepted_logicals: acceptedLogicals,
5921
- instance_id: metadataInstanceId,
6009
+ }
6010
+ else {
6011
+ logger$3.error("aft_replica_stickiness_manager_node_missing_sid", {
6012
+ node_type: node.constructor?.name ?? typeof node,
5922
6013
  });
5923
- logger$2.debug("token_issued_successfully");
5924
- logger$2.debug("provisioning_transport", { systemId });
5925
- const transportInfo = await this.transportProvisioner.provision(placementResult, normalizedHello, fullMetadata, nodeAttachToken);
5926
- logger$2.debug("transport_provisioned_successfully", {
5927
- systemId,
5928
- directiveType: transportInfo.connectionGrant &&
5929
- typeof transportInfo.connectionGrant === "object"
5930
- ? (transportInfo.connectionGrant.type ??
5931
- "Unknown")
5932
- : "Unknown",
6014
+ }
6015
+ }
6016
+ updateNodeSid(nodeSid) {
6017
+ if (this.aftHelper) {
6018
+ this.aftHelper.nodeSid = nodeSid;
6019
+ logger$3.debug("aft_replica_stickiness_manager_sid_updated", {
6020
+ new_sid: nodeSid,
5933
6021
  });
5934
- connectionGrants.push(transportInfo.connectionGrant);
5935
6022
  }
5936
- const caSignToken = await this.tokenIssuer.issue({
5937
- aud: "ca",
5938
- system_id: systemId,
5939
- assigned_path: assignedPath,
5940
- accepted_logicals: acceptedLogicals,
5941
- instance_id: metadataInstanceId,
5942
- });
5943
- const caGrant = {
5944
- type: HTTP_CONNECTION_GRANT_TYPE,
5945
- purpose: GRANT_PURPOSE_CA_SIGN,
5946
- url: this.caServiceUrl,
5947
- auth: {
5948
- type: "BearerTokenHeaderAuth",
5949
- tokenProvider: {
5950
- type: "StaticTokenProvider",
5951
- token: caSignToken,
5952
- },
5953
- },
5954
- };
5955
- connectionGrants.push(caGrant);
5956
- const welcomeFrame = {
5957
- type: "NodeWelcome",
5958
- systemId,
5959
- targetSystemId: placementResult.targetSystemId ?? undefined,
5960
- targetPhysicalPath: placementResult.targetPhysicalPath ?? undefined,
5961
- instanceId: normalizedHello.instanceId,
5962
- assignedPath,
5963
- acceptedCapabilities: acceptedCapabilities ?? undefined,
5964
- acceptedLogicals: acceptedLogicals ?? undefined,
5965
- rejectedLogicals: undefined,
5966
- connectionGrants,
5967
- metadata: Object.keys(fullMetadata).length > 0 ? fullMetadata : undefined,
5968
- expiresAt: expiry.toISOString(),
5969
- };
5970
- logger$2.debug("hello_frame_processing_completed_successfully", {
5971
- systemId,
5972
- assignedPath,
5973
- acceptedLogicals,
5974
- acceptedCapabilities,
5975
- expiresAt: welcomeFrame.expiresAt,
5976
- instanceId: normalizedHello.instanceId,
5977
- });
5978
- if (showEnvelopes) {
5979
- // eslint-disable-next-line no-console
5980
- console.log(`\n${formatTimestampForConsole()} - ${color("Sent envelope", AnsiColor.BLUE)} 🚀\n${prettyModel(welcomeFrame)}`);
6023
+ }
6024
+ async initializeAftHelper(node) {
6025
+ const nodeSid = node.sid;
6026
+ if (!nodeSid) {
6027
+ logger$3.error("aft_replica_stickiness_manager_cannot_initialize_no_sid", {
6028
+ node_id: node.id ?? "unknown",
6029
+ });
6030
+ return;
6031
+ }
6032
+ const cryptoProvider = node.cryptoProvider ?? null;
6033
+ if (!cryptoProvider) {
6034
+ logger$3.error("aft_replica_stickiness_manager_cannot_initialize_no_crypto_provider", {
6035
+ node_id: node.id ?? "unknown",
6036
+ });
6037
+ return;
6038
+ }
6039
+ const keyId = typeof cryptoProvider.signatureKeyId === "string" &&
6040
+ cryptoProvider.signatureKeyId.length > 0
6041
+ ? cryptoProvider.signatureKeyId
6042
+ : "default-key-id";
6043
+ const privateKeyPem = typeof cryptoProvider.signingPrivatePem === "string"
6044
+ ? cryptoProvider.signingPrivatePem
6045
+ : null;
6046
+ if (this.securityLevel === StickinessMode.STRICT && !privateKeyPem) {
6047
+ logger$3.error("aft_replica_stickiness_manager_initialization_failed", {
6048
+ node_id: node.id ?? "unknown",
6049
+ error: "Missing signing private key for strict security level",
6050
+ });
6051
+ return;
6052
+ }
6053
+ try {
6054
+ const helper = createAftHelper({
6055
+ securityLevel: this.securityLevel,
6056
+ nodeSid,
6057
+ kid: keyId,
6058
+ privateKeyPem,
6059
+ maxTtlSec: this.maxTtlSec,
6060
+ });
6061
+ this.aftHelper = helper;
6062
+ this.isInitialized = true;
6063
+ logger$3.debug("aft_replica_stickiness_manager_initialized", {
6064
+ node_id: node.id ?? "unknown",
6065
+ node_sid: nodeSid,
6066
+ key_id: keyId,
6067
+ security_level: helper.signer.securityLevel,
6068
+ });
5981
6069
  }
5982
- return welcomeFrame;
6070
+ catch (error) {
6071
+ logger$3.error("aft_replica_stickiness_manager_initialization_failed", {
6072
+ node_id: node.id ?? "unknown",
6073
+ error: error instanceof Error ? error.message : String(error),
6074
+ });
6075
+ }
6076
+ }
6077
+ get signer() {
6078
+ return this.aftHelper?.signer ?? null;
6079
+ }
6080
+ getHelper() {
6081
+ return this.aftHelper;
5983
6082
  }
5984
6083
  }
6084
+ function createAftReplicaStickinessManager(aftHelper) {
6085
+ return new AFTReplicaStickinessManager({ aftHelper });
6086
+ }
5985
6087
 
5986
- const FACTORY_META$5 = {
5987
- base: WELCOME_SERVICE_FACTORY_BASE_TYPE,
5988
- key: "AdvancedWelcomeService",
5989
- priority: 100,
5990
- isDefault: true,
6088
+ const FACTORY_META$6 = {
6089
+ base: REPLICA_STICKINESS_MANAGER_FACTORY_BASE_TYPE,
6090
+ key: "AFTReplicaStickinessManager",
5991
6091
  };
5992
- class AdvancedWelcomeServiceFactory extends WelcomeServiceFactory {
6092
+ const DEFAULT_VALUES = {
6093
+ securityLevel: StickinessMode.SIGNED_OPTIONAL,
6094
+ maxTtlSec: 7200,
6095
+ };
6096
+ function normalizeConfig$3(config) {
6097
+ const record = (config ?? {});
6098
+ const normalizedSecurity = record.securityLevel
6099
+ ? normalizeStickinessMode(record.securityLevel)
6100
+ : DEFAULT_VALUES.securityLevel;
6101
+ const securityLevel = normalizedSecurity ?? DEFAULT_VALUES.securityLevel;
6102
+ const maxTtlSecValue = typeof record.maxTtlSec === "number" && Number.isFinite(record.maxTtlSec)
6103
+ ? Math.max(0, Math.floor(record.maxTtlSec))
6104
+ : DEFAULT_VALUES.maxTtlSec;
6105
+ return {
6106
+ ...record,
6107
+ type: "AFTReplicaStickinessManager",
6108
+ securityLevel,
6109
+ maxTtlSec: maxTtlSecValue,
6110
+ };
6111
+ }
6112
+ class AFTReplicaStickinessManagerFactory extends ReplicaStickinessManagerFactory {
5993
6113
  constructor() {
5994
6114
  super(...arguments);
5995
- this.type = FACTORY_META$5.key;
5996
- this.isDefault = FACTORY_META$5.isDefault;
5997
- this.priority = FACTORY_META$5.priority;
5998
- }
5999
- async create(config, ...factoryArgs) {
6000
- const normalized = normalizeConfig$2(config);
6001
- // Crypto provider should be passed from upstream (node-welcome-server)
6002
- // Do not create it here - downstream components should use what's passed in factoryArgs
6003
- const placementStrategy = await NodePlacementStrategyFactory.createNodePlacementStrategy(normalized.placementConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
6004
- const transportProvisioner = await TransportProvisionerFactory.createTransportProvisioner(normalized.transportConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
6005
- const tokenIssuer = await TokenIssuerFactory.createTokenIssuer(normalized.tokenIssuerConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
6006
- let authorizer = null;
6007
- if (normalized.authorizerConfig) {
6008
- authorizer =
6009
- (await AuthorizerFactory.createAuthorizer(normalized.authorizerConfig, {
6010
- factoryArgs,
6011
- })) ?? null;
6012
- }
6013
- const options = {
6014
- placementStrategy,
6015
- transportProvisioner,
6016
- tokenIssuer,
6017
- authorizer,
6018
- caServiceUrl: normalized.caServiceUrl,
6019
- };
6020
- if (normalized.ttlSec !== undefined) {
6021
- options.ttlSec = normalized.ttlSec;
6022
- }
6023
- return new AdvancedWelcomeService(options);
6024
- }
6025
- }
6026
- function normalizeConfig$2(config) {
6027
- if (!config) {
6028
- throw new Error("AdvancedWelcomeService requires configuration");
6029
- }
6030
- const source = config;
6031
- const ttlCandidate = typeof source.ttlSec === "number"
6032
- ? source.ttlSec
6033
- : typeof source.ttl_sec === "number"
6034
- ? source.ttl_sec
6035
- : undefined;
6036
- const caServiceUrlCandidate = typeof source.caServiceUrl === "string" &&
6037
- source.caServiceUrl.trim().length > 0
6038
- ? source.caServiceUrl.trim()
6039
- : typeof source.ca_service_url === "string" &&
6040
- source.ca_service_url.trim().length > 0
6041
- ? source.ca_service_url.trim()
6042
- : undefined;
6043
- if (!caServiceUrlCandidate) {
6044
- throw new Error("AdvancedWelcomeService configuration requires caServiceUrl");
6045
- }
6046
- const normalized = {
6047
- caServiceUrl: caServiceUrlCandidate,
6048
- };
6049
- if (source.placement !== undefined) {
6050
- normalized.placementConfig =
6051
- source.placement ?? null;
6052
- }
6053
- if (source.transport !== undefined) {
6054
- normalized.transportConfig =
6055
- source.transport ?? null;
6056
- }
6057
- const tokenIssuerConfig = source.tokenIssuer !== undefined
6058
- ? source.tokenIssuer
6059
- : source.token_issuer !== undefined
6060
- ? source.token_issuer
6061
- : undefined;
6062
- if (tokenIssuerConfig !== undefined) {
6063
- normalized.tokenIssuerConfig =
6064
- tokenIssuerConfig ?? null;
6065
- }
6066
- if (source.authorizer !== undefined) {
6067
- normalized.authorizerConfig =
6068
- source.authorizer ?? null;
6115
+ this.type = FACTORY_META$6.key;
6116
+ this.isDefault = true;
6069
6117
  }
6070
- if (ttlCandidate !== undefined && Number.isFinite(ttlCandidate)) {
6071
- normalized.ttlSec = ttlCandidate;
6118
+ async create(config, dependencies) {
6119
+ const resolvedConfig = normalizeConfig$3(config);
6120
+ const helper = dependencies?.aftHelper ?? null;
6121
+ const securityLevel = normalizeStickinessMode(resolvedConfig.securityLevel ?? DEFAULT_VALUES.securityLevel) ?? DEFAULT_VALUES.securityLevel;
6122
+ const maxTtlSec = typeof resolvedConfig.maxTtlSec === "number" &&
6123
+ Number.isFinite(resolvedConfig.maxTtlSec)
6124
+ ? Math.max(0, Math.floor(resolvedConfig.maxTtlSec))
6125
+ : DEFAULT_VALUES.maxTtlSec;
6126
+ return new AFTReplicaStickinessManager({
6127
+ securityLevel,
6128
+ maxTtlSec,
6129
+ aftHelper: helper,
6130
+ });
6072
6131
  }
6073
- return normalized;
6074
6132
  }
6075
6133
 
6076
- var advancedWelcomeServiceFactory = /*#__PURE__*/Object.freeze({
6134
+ var aftReplicaStickinessManagerFactory = /*#__PURE__*/Object.freeze({
6077
6135
  __proto__: null,
6078
- AdvancedWelcomeServiceFactory: AdvancedWelcomeServiceFactory,
6079
- FACTORY_META: FACTORY_META$5,
6080
- default: AdvancedWelcomeServiceFactory
6136
+ AFTReplicaStickinessManagerFactory: AFTReplicaStickinessManagerFactory,
6137
+ FACTORY_META: FACTORY_META$6,
6138
+ default: AFTReplicaStickinessManagerFactory
6081
6139
  });
6082
6140
 
6083
- /**
6084
- * AUTO-GENERATED FILE. DO NOT EDIT DIRECTLY.
6085
- * Generated by scripts/generate-factory-manifest.mjs
6086
- *
6087
- * Provides the list of advanced security factory modules for registration.
6088
- */
6089
- const MODULES = [
6090
- "./security/cert/default-ca-service-factory.js",
6091
- "./security/cert/default-certificate-manager-factory.js",
6092
- "./security/cert/trust-store/browser-trust-store-provider-factory.js",
6093
- "./security/cert/trust-store/node-trust-store-provider-factory.js",
6094
- "./security/encryption/channel/channel-encryption-manager-factory.js",
6095
- "./security/encryption/composite-encryption-manager-factory.js",
6096
- "./security/encryption/default-secure-channel-manager-factory.js",
6097
- "./security/encryption/sealed/x25519-encryption-manager-factory.js",
6098
- "./security/keys/x5c-key-manager-factory.js",
6099
- "./security/signing/eddsa-envelope-signer-factory.js",
6100
- "./security/signing/eddsa-envelope-verifier-factory.js",
6101
- "./stickiness/aft-load-balancer-stickiness-manager-factory.js",
6102
- "./stickiness/aft-replica-stickiness-manager-factory.js",
6103
- "./welcome/advanced-welcome-service-factory.js"
6104
- ];
6105
- const MODULE_LOADERS = {
6106
- "./security/cert/default-ca-service-factory.js": () => Promise.resolve().then(function () { return defaultCaServiceFactory; }),
6107
- "./security/cert/default-certificate-manager-factory.js": () => Promise.resolve().then(function () { return defaultCertificateManagerFactory; }),
6108
- "./security/cert/trust-store/browser-trust-store-provider-factory.js": () => Promise.resolve().then(function () { return browserTrustStoreProviderFactory; }),
6109
- "./security/cert/trust-store/node-trust-store-provider-factory.js": () => Promise.resolve().then(function () { return nodeTrustStoreProviderFactory; }),
6110
- "./security/encryption/channel/channel-encryption-manager-factory.js": () => Promise.resolve().then(function () { return channelEncryptionManagerFactory; }),
6111
- "./security/encryption/composite-encryption-manager-factory.js": () => Promise.resolve().then(function () { return compositeEncryptionManagerFactory; }),
6112
- "./security/encryption/default-secure-channel-manager-factory.js": () => Promise.resolve().then(function () { return defaultSecureChannelManagerFactory; }),
6113
- "./security/encryption/sealed/x25519-encryption-manager-factory.js": () => Promise.resolve().then(function () { return x25519EncryptionManagerFactory; }),
6114
- "./security/keys/x5c-key-manager-factory.js": () => Promise.resolve().then(function () { return x5cKeyManagerFactory; }),
6115
- "./security/signing/eddsa-envelope-signer-factory.js": () => Promise.resolve().then(function () { return eddsaEnvelopeSignerFactory; }),
6116
- "./security/signing/eddsa-envelope-verifier-factory.js": () => Promise.resolve().then(function () { return eddsaEnvelopeVerifierFactory; }),
6117
- "./stickiness/aft-load-balancer-stickiness-manager-factory.js": () => Promise.resolve().then(function () { return aftLoadBalancerStickinessManagerFactory; }),
6118
- "./stickiness/aft-replica-stickiness-manager-factory.js": () => Promise.resolve().then(function () { return aftReplicaStickinessManagerFactory; }),
6119
- "./welcome/advanced-welcome-service-factory.js": () => Promise.resolve().then(function () { return advancedWelcomeServiceFactory; }),
6120
- };
6121
-
6122
- const SECURITY_PREFIX = "./security/";
6123
- const SECURITY_MODULES = MODULES.filter((spec) => spec.startsWith(SECURITY_PREFIX));
6124
- const EXTRA_MODULES = MODULES.filter((spec) => !spec.startsWith(SECURITY_PREFIX));
6125
- const NODE_ONLY_MODULES = new Set([
6126
- "./security/cert/default-ca-service-factory.js",
6127
- "./security/cert/trust-store/node-trust-store-provider-factory.js",
6128
- ]);
6129
- const FACTORY_MODULE_PREFIX$1 = "@naylence/advanced-security/naylence/fame/";
6130
- const BROWSER_DIST_SEGMENT = "/dist/browser/";
6131
- function detectModuleUrl() {
6132
- if (typeof __filename === "string") {
6133
- try {
6134
- return __filename.startsWith("file://")
6135
- ? __filename
6136
- : `file://${__filename}`;
6137
- }
6138
- catch {
6139
- // fall through to stack parsing
6140
- }
6141
- }
6142
- try {
6143
- throw new Error();
6144
- }
6145
- catch (error) {
6146
- const stack = typeof error === "object" && error && "stack" in error
6147
- ? String(error.stack ?? "")
6148
- : "";
6149
- const lines = stack.split("\n");
6150
- for (const line of lines) {
6151
- const match = line.match(/(https?:\/\/[^\s)]+|file:\/\/[^\s)]+\.(?:js|ts)|\/(?:[^\s)]+\.(?:js|ts)))/u);
6152
- const candidate = match?.[1];
6153
- if (!candidate) {
6154
- continue;
6155
- }
6156
- if (candidate.startsWith("http://") || candidate.startsWith("https://")) {
6157
- return candidate;
6158
- }
6159
- if (candidate.startsWith("file://")) {
6160
- return candidate;
6161
- }
6162
- return `file://${candidate}`;
6163
- }
6164
- }
6165
- return null;
6166
- }
6167
- function computeBrowserFactoryBase(rawUrl) {
6168
- if (!rawUrl) {
6169
- return null;
6170
- }
6171
- const sanitized = rawUrl.split("?")[0]?.split("#")[0] ?? rawUrl;
6172
- const esmMarker = "/dist/esm/naylence/fame/";
6173
- const distMarker = "/dist/";
6174
- if (sanitized.includes(esmMarker)) {
6175
- return sanitized.slice(0, sanitized.indexOf(esmMarker) + esmMarker.length);
6176
- }
6177
- if (rawUrl.includes(BROWSER_DIST_SEGMENT)) {
6178
- return new URL("../esm/naylence/fame/", rawUrl).href;
6141
+ const logger$2 = getLogger("naylence.fame.welcome.advanced_welcome_service");
6142
+ const ENV_VAR_SHOW_ENVELOPES = "FAME_SHOW_ENVELOPES";
6143
+ const DEFAULT_TTL_SEC = 3600;
6144
+ const showEnvelopes = typeof process !== "undefined" &&
6145
+ process.env?.[ENV_VAR_SHOW_ENVELOPES] === "true";
6146
+ function nowUtc() {
6147
+ return new Date();
6148
+ }
6149
+ function formatTimestampForConsole() {
6150
+ return color(formatTimestamp(), AnsiColor.GRAY);
6151
+ }
6152
+ function prettyModel(value) {
6153
+ try {
6154
+ return jsonDumps(value);
6179
6155
  }
6180
- if (sanitized.includes(BROWSER_DIST_SEGMENT)) {
6181
- const base = sanitized.slice(0, sanitized.indexOf(BROWSER_DIST_SEGMENT) + BROWSER_DIST_SEGMENT.length);
6182
- return `${base.replace(/browser\/?$/u, "")}esm/naylence/fame/`;
6156
+ catch (error) {
6157
+ return String(error);
6183
6158
  }
6184
- if (sanitized.includes(distMarker)) {
6185
- const index = sanitized.indexOf(distMarker);
6186
- const base = sanitized.slice(0, index + distMarker.length);
6187
- return `${base}esm/naylence/fame/`;
6159
+ }
6160
+ function coercePlacementMetadataValue(metadata, camelCaseKey, snakeCaseKey) {
6161
+ if (!metadata) {
6162
+ return undefined;
6188
6163
  }
6189
- const srcMarker = "/src/naylence/fame/";
6190
- if (sanitized.includes(srcMarker)) {
6191
- const index = sanitized.indexOf(srcMarker);
6192
- const projectRoot = sanitized.slice(0, index);
6193
- return `${projectRoot}/dist/esm/naylence/fame/`;
6164
+ const record = metadata;
6165
+ if (record[camelCaseKey] !== undefined) {
6166
+ return record[camelCaseKey];
6194
6167
  }
6195
- if (sanitized.startsWith("http://") || sanitized.startsWith("https://")) {
6196
- try {
6197
- const parsed = new URL(rawUrl);
6198
- const viteDepsSegment = "/node_modules/.vite/deps/";
6199
- if (parsed.pathname.includes(viteDepsSegment)) {
6200
- const baseOrigin = `${parsed.protocol}//${parsed.host}`;
6201
- return `${baseOrigin}/node_modules/@naylence/advanced-security/dist/esm/naylence/fame/`;
6202
- }
6203
- }
6204
- catch {
6205
- // ignore
6206
- }
6168
+ if (record[snakeCaseKey] !== undefined) {
6169
+ return record[snakeCaseKey];
6207
6170
  }
6208
- return null;
6171
+ return undefined;
6209
6172
  }
6210
- const moduleUrl = detectModuleUrl();
6211
- const browserFactoryBase = computeBrowserFactoryBase(moduleUrl);
6212
- const prefersSource = typeof moduleUrl === "string" && moduleUrl.includes("/src/");
6213
- function resolveFactoryModuleSpecifier$1(specifier) {
6214
- if (specifier.startsWith("../")) {
6215
- return `${FACTORY_MODULE_PREFIX$1}${specifier.slice("../".length)}`;
6216
- }
6217
- if (specifier.startsWith("./")) {
6218
- return `${FACTORY_MODULE_PREFIX$1}${specifier.slice("./".length)}`;
6173
+ class AdvancedWelcomeService {
6174
+ constructor(options) {
6175
+ this.placementStrategy = options.placementStrategy;
6176
+ this.transportProvisioner = options.transportProvisioner;
6177
+ this.tokenIssuer = options.tokenIssuer;
6178
+ this.authorizer = options.authorizer ?? null;
6179
+ this.caServiceUrl = options.caServiceUrl;
6180
+ this.ttlSec =
6181
+ typeof options.ttlSec === "number" && Number.isFinite(options.ttlSec)
6182
+ ? Math.max(0, options.ttlSec)
6183
+ : DEFAULT_TTL_SEC;
6184
+ logger$2.debug("initialized_advanced_welcome_service", {
6185
+ ca_service_url: this.caServiceUrl,
6186
+ ttl_sec: this.ttlSec,
6187
+ });
6219
6188
  }
6220
- return null;
6221
- }
6222
- function resolveModuleCandidates(spec) {
6223
- const candidates = [];
6224
- const seen = new Set();
6225
- const addCandidate = (candidate) => {
6226
- if (!candidate) {
6227
- return;
6228
- }
6229
- if (!seen.has(candidate)) {
6230
- seen.add(candidate);
6231
- candidates.push(candidate);
6189
+ async handleHello(hello, metadata) {
6190
+ const fullMetadata = metadata
6191
+ ? { ...metadata }
6192
+ : {};
6193
+ const trimmedSystemId = typeof hello.systemId === "string" ? hello.systemId.trim() : "";
6194
+ const systemId = trimmedSystemId.length > 0 ? trimmedSystemId : generateId();
6195
+ const wasAssigned = trimmedSystemId.length === 0;
6196
+ const normalizedHello = {
6197
+ ...hello,
6198
+ systemId,
6199
+ };
6200
+ if (showEnvelopes) {
6201
+ // eslint-disable-next-line no-console
6202
+ console.log(`\n${formatTimestampForConsole()} - ${color("Received envelope 📨", AnsiColor.BLUE)}\n${prettyModel(normalizedHello)}`);
6232
6203
  }
6233
- };
6234
- if (prefersSource && spec.startsWith("./")) {
6235
- const sourceCandidate = `../${spec.slice(2)}`;
6236
- addCandidate(sourceCandidate);
6237
- if (sourceCandidate.endsWith(".js")) {
6238
- addCandidate(sourceCandidate.replace(/\.js$/u, ".ts"));
6204
+ logger$2.debug("starting_hello_frame_processing", {
6205
+ instanceId: normalizedHello.instanceId,
6206
+ systemId,
6207
+ logicals: normalizedHello.logicals,
6208
+ capabilities: normalizedHello.capabilities,
6209
+ ttlSec: this.ttlSec,
6210
+ });
6211
+ const now = nowUtc();
6212
+ const expiry = new Date(now.getTime() + this.ttlSec * 1000);
6213
+ if (normalizedHello.instanceId) {
6214
+ if (fullMetadata.instanceId === undefined) {
6215
+ fullMetadata.instanceId = normalizedHello.instanceId;
6216
+ }
6217
+ if (fullMetadata.instance_id === undefined) {
6218
+ fullMetadata.instance_id = normalizedHello.instanceId;
6219
+ }
6239
6220
  }
6240
- }
6241
- if (browserFactoryBase && spec.startsWith("./")) {
6242
- try {
6243
- const browserCandidate = new URL(spec.slice("./".length), browserFactoryBase).href;
6244
- addCandidate(browserCandidate);
6245
- if (browserCandidate.endsWith(".js")) {
6246
- addCandidate(browserCandidate.replace(/\.js$/u, ".ts"));
6221
+ logger$2.debug("system_id_assignment_completed", {
6222
+ systemId,
6223
+ wasAssigned,
6224
+ });
6225
+ if (normalizedHello.logicals?.length) {
6226
+ logger$2.debug("validating_logicals_for_dns_compatibility", {
6227
+ logicals: normalizedHello.logicals,
6228
+ });
6229
+ const [pathsValid, pathError] = validateHostLogicals(normalizedHello.logicals);
6230
+ if (!pathsValid) {
6231
+ logger$2.error("logical_validation_failed", {
6232
+ error: pathError,
6233
+ logicals: normalizedHello.logicals,
6234
+ });
6235
+ throw new Error(`Invalid logical format: ${pathError}`);
6247
6236
  }
6237
+ logger$2.debug("logicals_validation_successful");
6248
6238
  }
6249
- catch {
6250
- // ignore resolution failures for browser base
6239
+ logger$2.debug("requesting_node_placement", { systemId });
6240
+ const placementResult = await this.placementStrategy.place(normalizedHello);
6241
+ if (!placementResult.accept) {
6242
+ logger$2.error("node_placement_rejected", {
6243
+ systemId,
6244
+ reason: placementResult.reason,
6245
+ });
6246
+ throw new Error(placementResult.reason || "Node not accepted");
6251
6247
  }
6248
+ const assignedPath = placementResult.assignedPath;
6249
+ logger$2.debug("node_placement_accepted", {
6250
+ systemId,
6251
+ assignedPath,
6252
+ targetPhysicalPath: placementResult.targetPhysicalPath ?? null,
6253
+ targetSystemId: placementResult.targetSystemId ?? null,
6254
+ });
6255
+ const acceptedCapabilities = coercePlacementMetadataValue(placementResult.metadata, "acceptedCapabilities", "accepted_capabilities") ??
6256
+ normalizedHello.capabilities ??
6257
+ null;
6258
+ const acceptedLogicals = coercePlacementMetadataValue(placementResult.metadata, "acceptedLogicals", "accepted_logicals") ??
6259
+ normalizedHello.logicals ??
6260
+ null;
6261
+ logger$2.debug("processing_placement_result_metadata", {
6262
+ acceptedCapabilities,
6263
+ acceptedLogicals,
6264
+ hasPlacementMetadata: placementResult.metadata !== undefined &&
6265
+ placementResult.metadata !== null,
6266
+ });
6267
+ const connectionGrants = [];
6268
+ const metadataInstanceId = (typeof fullMetadata.instanceId === "string" &&
6269
+ fullMetadata.instanceId) ||
6270
+ (typeof fullMetadata.instance_id === "string" &&
6271
+ fullMetadata.instance_id) ||
6272
+ normalizedHello.instanceId ||
6273
+ generateId();
6274
+ if (placementResult.targetSystemId) {
6275
+ logger$2.debug("issuing_node_attach_token", {
6276
+ systemId,
6277
+ assignedPath,
6278
+ });
6279
+ const nodeAttachToken = await this.tokenIssuer.issue({
6280
+ aud: placementResult.targetPhysicalPath,
6281
+ system_id: systemId,
6282
+ parent_path: placementResult.targetPhysicalPath,
6283
+ assigned_path: placementResult.assignedPath,
6284
+ accepted_logicals: acceptedLogicals,
6285
+ instance_id: metadataInstanceId,
6286
+ });
6287
+ logger$2.debug("token_issued_successfully");
6288
+ logger$2.debug("provisioning_transport", { systemId });
6289
+ const transportInfo = await this.transportProvisioner.provision(placementResult, normalizedHello, fullMetadata, nodeAttachToken);
6290
+ logger$2.debug("transport_provisioned_successfully", {
6291
+ systemId,
6292
+ directiveType: transportInfo.connectionGrant &&
6293
+ typeof transportInfo.connectionGrant === "object"
6294
+ ? (transportInfo.connectionGrant.type ??
6295
+ "Unknown")
6296
+ : "Unknown",
6297
+ });
6298
+ connectionGrants.push(transportInfo.connectionGrant);
6299
+ }
6300
+ const caSignToken = await this.tokenIssuer.issue({
6301
+ aud: "ca",
6302
+ system_id: systemId,
6303
+ assigned_path: assignedPath,
6304
+ accepted_logicals: acceptedLogicals,
6305
+ instance_id: metadataInstanceId,
6306
+ });
6307
+ const caGrant = {
6308
+ type: HTTP_CONNECTION_GRANT_TYPE,
6309
+ purpose: GRANT_PURPOSE_CA_SIGN,
6310
+ url: this.caServiceUrl,
6311
+ auth: {
6312
+ type: "BearerTokenHeaderAuth",
6313
+ tokenProvider: {
6314
+ type: "StaticTokenProvider",
6315
+ token: caSignToken,
6316
+ },
6317
+ },
6318
+ };
6319
+ connectionGrants.push(caGrant);
6320
+ const welcomeFrame = {
6321
+ type: "NodeWelcome",
6322
+ systemId,
6323
+ targetSystemId: placementResult.targetSystemId ?? undefined,
6324
+ targetPhysicalPath: placementResult.targetPhysicalPath ?? undefined,
6325
+ instanceId: normalizedHello.instanceId,
6326
+ assignedPath,
6327
+ acceptedCapabilities: acceptedCapabilities ?? undefined,
6328
+ acceptedLogicals: acceptedLogicals ?? undefined,
6329
+ rejectedLogicals: undefined,
6330
+ connectionGrants,
6331
+ metadata: Object.keys(fullMetadata).length > 0 ? fullMetadata : undefined,
6332
+ expiresAt: expiry.toISOString(),
6333
+ };
6334
+ logger$2.debug("hello_frame_processing_completed_successfully", {
6335
+ systemId,
6336
+ assignedPath,
6337
+ acceptedLogicals,
6338
+ acceptedCapabilities,
6339
+ expiresAt: welcomeFrame.expiresAt,
6340
+ instanceId: normalizedHello.instanceId,
6341
+ });
6342
+ if (showEnvelopes) {
6343
+ // eslint-disable-next-line no-console
6344
+ console.log(`\n${formatTimestampForConsole()} - ${color("Sent envelope", AnsiColor.BLUE)} 🚀\n${prettyModel(welcomeFrame)}`);
6345
+ }
6346
+ return welcomeFrame;
6252
6347
  }
6253
- const packageCandidate = resolveFactoryModuleSpecifier$1(spec);
6254
- addCandidate(packageCandidate);
6255
- if (packageCandidate?.endsWith(".js")) {
6256
- addCandidate(packageCandidate.replace(/\.js$/u, ".ts"));
6257
- }
6258
- const fallback = spec.startsWith("./") ? `../${spec.slice(2)}` : spec;
6259
- addCandidate(fallback);
6260
- if (fallback.endsWith(".js")) {
6261
- addCandidate(fallback.replace(/\.js$/u, ".ts"));
6262
- }
6263
- addCandidate(spec);
6264
- if (spec.endsWith(".js")) {
6265
- addCandidate(spec.replace(/\.js$/u, ".ts"));
6266
- }
6267
- return candidates;
6268
- }
6269
- const registeredModules = new Set();
6270
- const inflightModules = new Map();
6271
- const browserSkippedModules = new Set();
6272
- function isNodeEnvironment$5() {
6273
- return (typeof process !== "undefined" &&
6274
- typeof process.release !== "undefined" &&
6275
- process.release?.name === "node");
6276
- }
6277
- function shouldSkipModule(spec) {
6278
- if (isNodeEnvironment$5()) {
6279
- return false;
6280
- }
6281
- if (!NODE_ONLY_MODULES.has(spec)) {
6282
- return false;
6283
- }
6284
- if (!browserSkippedModules.has(spec)) {
6285
- // console.warn(
6286
- // "[advanced-security:factory-manifest] skipped browser-incompatible module",
6287
- // spec,
6288
- // );
6289
- browserSkippedModules.add(spec);
6290
- }
6291
- return true;
6292
- }
6293
- function getDynamicImporter() {
6294
- if (typeof globalThis === "undefined") {
6295
- return null;
6296
- }
6297
- const candidate = globalThis.__naylenceFactoryDynamicImporter;
6298
- if (typeof candidate === "function") {
6299
- return candidate;
6300
- }
6301
- return null;
6302
6348
  }
6303
- async function registerModule(spec, registrar) {
6304
- const candidates = resolveModuleCandidates(spec);
6305
- const dynamicImporter = getDynamicImporter();
6306
- const loader = dynamicImporter
6307
- ? (specifier) => dynamicImporter(specifier)
6308
- : (specifier) => import(/* @vite-ignore */ specifier);
6309
- const attempts = [];
6310
- const staticLoader = MODULE_LOADERS?.[spec];
6311
- if (staticLoader) {
6312
- attempts.push({ load: () => staticLoader(), candidate: spec });
6313
- }
6314
- for (const candidate of candidates) {
6315
- attempts.push({ load: () => loader(candidate), candidate });
6349
+
6350
+ const FACTORY_META$5 = {
6351
+ base: WELCOME_SERVICE_FACTORY_BASE_TYPE,
6352
+ key: "AdvancedWelcomeService",
6353
+ priority: 100,
6354
+ isDefault: true,
6355
+ };
6356
+ class AdvancedWelcomeServiceFactory extends WelcomeServiceFactory {
6357
+ constructor() {
6358
+ super(...arguments);
6359
+ this.type = FACTORY_META$5.key;
6360
+ this.isDefault = FACTORY_META$5.isDefault;
6361
+ this.priority = FACTORY_META$5.priority;
6316
6362
  }
6317
- const registerFromModule = (mod) => {
6318
- const meta = mod.FACTORY_META;
6319
- const Ctor = mod.default;
6320
- if (!meta?.base || !meta?.key || typeof Ctor !== "function") {
6321
- console.warn("[debug] invalid factory module", spec, {
6322
- meta,
6323
- hasCtor: typeof Ctor === "function",
6324
- });
6325
- console.warn("[advanced-security:factory-manifest] skipped", spec, "— missing FACTORY_META or default export ctor");
6326
- return false;
6327
- }
6328
- const { base, key, ...metadata } = meta;
6329
- const extraMetadata = Object.keys(metadata).length > 0 ? metadata : undefined;
6330
- // console.log("[debug] registering module", { spec, base, key, metadata: extraMetadata });
6331
- registrar.registerFactory(base, key, Ctor, extraMetadata);
6332
- return true;
6333
- };
6334
- for (const [index, { candidate, load }] of attempts.entries()) {
6335
- try {
6336
- const mod = await load();
6337
- return registerFromModule(mod);
6363
+ async create(config, ...factoryArgs) {
6364
+ const normalized = normalizeConfig$2(config);
6365
+ // Crypto provider should be passed from upstream (node-welcome-server)
6366
+ // Do not create it here - downstream components should use what's passed in factoryArgs
6367
+ const placementStrategy = await NodePlacementStrategyFactory.createNodePlacementStrategy(normalized.placementConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
6368
+ const transportProvisioner = await TransportProvisionerFactory.createTransportProvisioner(normalized.transportConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
6369
+ const tokenIssuer = await TokenIssuerFactory.createTokenIssuer(normalized.tokenIssuerConfig ?? null, factoryArgs.length > 0 ? { factoryArgs } : undefined);
6370
+ let authorizer = null;
6371
+ if (normalized.authorizerConfig) {
6372
+ authorizer =
6373
+ (await AuthorizerFactory.createAuthorizer(normalized.authorizerConfig, {
6374
+ factoryArgs,
6375
+ })) ?? null;
6338
6376
  }
6339
- catch (error) {
6340
- const message = error instanceof Error ? error.message : String(error);
6341
- const moduleNotFound = message.includes("Cannot find module") ||
6342
- message.includes("ERR_MODULE_NOT_FOUND") ||
6343
- message.includes("Unknown file extension") ||
6344
- message.includes("Failed to fetch dynamically imported module") ||
6345
- message.includes("Failed to resolve module specifier") ||
6346
- message.includes("Importing a module script failed");
6347
- const isLastAttempt = index === attempts.length - 1;
6348
- if (!moduleNotFound || isLastAttempt) {
6349
- console.warn("[debug] failed to import candidate", {
6350
- spec,
6351
- candidate,
6352
- message,
6353
- });
6354
- console.warn("[advanced-security:factory-manifest] skipped", spec, "-", message);
6355
- return false;
6356
- }
6377
+ const options = {
6378
+ placementStrategy,
6379
+ transportProvisioner,
6380
+ tokenIssuer,
6381
+ authorizer,
6382
+ caServiceUrl: normalized.caServiceUrl,
6383
+ };
6384
+ if (normalized.ttlSec !== undefined) {
6385
+ options.ttlSec = normalized.ttlSec;
6357
6386
  }
6387
+ return new AdvancedWelcomeService(options);
6358
6388
  }
6359
- return false;
6360
6389
  }
6361
- async function registerModuleOnce(spec, registrar) {
6362
- if (registeredModules.has(spec)) {
6363
- return false;
6364
- }
6365
- const inflight = inflightModules.get(spec);
6366
- if (inflight) {
6367
- return inflight;
6390
+ function normalizeConfig$2(config) {
6391
+ if (!config) {
6392
+ throw new Error("AdvancedWelcomeService requires configuration");
6368
6393
  }
6369
- const registration = (async () => {
6370
- const registered = await registerModule(spec, registrar);
6371
- if (registered) {
6372
- registeredModules.add(spec);
6373
- }
6374
- return registered;
6375
- })();
6376
- inflightModules.set(spec, registration);
6377
- try {
6378
- return await registration;
6394
+ const source = config;
6395
+ const ttlCandidate = typeof source.ttlSec === "number"
6396
+ ? source.ttlSec
6397
+ : typeof source.ttl_sec === "number"
6398
+ ? source.ttl_sec
6399
+ : undefined;
6400
+ const caServiceUrlCandidate = typeof source.caServiceUrl === "string" &&
6401
+ source.caServiceUrl.trim().length > 0
6402
+ ? source.caServiceUrl.trim()
6403
+ : typeof source.ca_service_url === "string" &&
6404
+ source.ca_service_url.trim().length > 0
6405
+ ? source.ca_service_url.trim()
6406
+ : undefined;
6407
+ if (!caServiceUrlCandidate) {
6408
+ throw new Error("AdvancedWelcomeService configuration requires caServiceUrl");
6379
6409
  }
6380
- finally {
6381
- inflightModules.delete(spec);
6410
+ const normalized = {
6411
+ caServiceUrl: caServiceUrlCandidate,
6412
+ };
6413
+ if (source.placement !== undefined) {
6414
+ normalized.placementConfig =
6415
+ source.placement ?? null;
6382
6416
  }
6383
- }
6384
- async function registerModules(modules, registrar) {
6385
- if (modules.length === 0) {
6386
- return 0;
6417
+ if (source.transport !== undefined) {
6418
+ normalized.transportConfig =
6419
+ source.transport ?? null;
6387
6420
  }
6388
- const eligibleModules = modules.filter((spec) => !shouldSkipModule(spec));
6389
- if (eligibleModules.length === 0) {
6390
- return 0;
6421
+ const tokenIssuerConfig = source.tokenIssuer !== undefined
6422
+ ? source.tokenIssuer
6423
+ : source.token_issuer !== undefined
6424
+ ? source.token_issuer
6425
+ : undefined;
6426
+ if (tokenIssuerConfig !== undefined) {
6427
+ normalized.tokenIssuerConfig =
6428
+ tokenIssuerConfig ?? null;
6391
6429
  }
6392
- const results = await Promise.all(eligibleModules.map((spec) => registerModuleOnce(spec, registrar)));
6393
- return results.reduce((count, registered) => (registered ? count + 1 : count), 0);
6394
- }
6395
- async function registerAdvancedSecurityFactories(registrar = Registry, options) {
6396
- const newlyRegisteredSecurity = await registerModules(SECURITY_MODULES, registrar);
6397
- if (newlyRegisteredSecurity > 0) {
6398
- getEncryptionManagerFactoryRegistry().forceRediscovery();
6430
+ if (source.authorizer !== undefined) {
6431
+ normalized.authorizerConfig =
6432
+ source.authorizer ?? null;
6399
6433
  }
6400
- if (options?.includeExtras === true) {
6401
- await registerModules(EXTRA_MODULES, registrar);
6434
+ if (ttlCandidate !== undefined && Number.isFinite(ttlCandidate)) {
6435
+ normalized.ttlSec = ttlCandidate;
6402
6436
  }
6437
+ return normalized;
6403
6438
  }
6404
6439
 
6440
+ var advancedWelcomeServiceFactory = /*#__PURE__*/Object.freeze({
6441
+ __proto__: null,
6442
+ AdvancedWelcomeServiceFactory: AdvancedWelcomeServiceFactory,
6443
+ FACTORY_META: FACTORY_META$5,
6444
+ default: AdvancedWelcomeServiceFactory
6445
+ });
6446
+
6405
6447
  /**
6406
6448
  * Isomorphic entry point for Naylence Advanced Security.
6407
6449
  *
@@ -10098,47 +10140,31 @@ var defaultCaServiceFactory = /*#__PURE__*/Object.freeze({
10098
10140
  * Includes the full factory surface area, including certificate authority
10099
10141
  * helpers that rely on Node.js built-ins.
10100
10142
  */
10101
-
10102
- async function registerAdvancedSecurityPluginFactories(registrar = Registry) {
10103
- await registerAdvancedSecurityFactories(registrar, { includeExtras: true });
10143
+ // Always register the plugin directly. This ensures it is initialized even if
10144
+ // the dynamic import mechanism (used by FAME_PLUGINS) fails.
10145
+ (async () => {
10146
+ try {
10147
+ await advancedSecurityPlugin.register();
10148
+ }
10149
+ catch (err) {
10150
+ console.error('[naylence:advanced-security] Failed to auto-register plugin:', err);
10151
+ }
10152
+ })();
10153
+ const g = (typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof self !== 'undefined' ? self : {});
10154
+ const proc = g.process || (typeof process !== 'undefined' ? process : undefined);
10155
+ const isNode = typeof process !== 'undefined' &&
10156
+ process.versions != null &&
10157
+ process.versions.node != null;
10158
+ // Only in Node.js: populate FAME_PLUGINS so child processes inherit it.
10159
+ if (isNode && proc && proc.env) {
10160
+ const pluginName = '@naylence/advanced-security';
10161
+ const current = proc.env.FAME_PLUGINS || '';
10162
+ const plugins = current.split(',').map((p) => p.trim());
10163
+ if (!plugins.includes(pluginName)) {
10164
+ proc.env.FAME_PLUGINS = current
10165
+ ? `${current},${pluginName}`
10166
+ : pluginName;
10167
+ }
10104
10168
  }
10105
- let initialized = false;
10106
- let initializing = null;
10107
- const advancedSecurityPlugin = {
10108
- name: "naylence:advanced-security",
10109
- version: VERSION,
10110
- async register() {
10111
- // console.log('[naylence:advanced-security] register() called, initialized=', initialized);
10112
- if (initialized) {
10113
- // console.log('[naylence:advanced-security] already initialized, skipping');
10114
- return;
10115
- }
10116
- if (initializing) {
10117
- console.log("[naylence:advanced-security] already initializing, awaiting...");
10118
- await initializing;
10119
- return;
10120
- }
10121
- initializing = (async () => {
10122
- try {
10123
- // console.log('[naylence:advanced-security] registering advanced security factories...');
10124
- await registerAdvancedSecurityPluginFactories();
10125
- // console.log('[naylence:advanced-security] advanced security factories registered');
10126
- initialized = true;
10127
- }
10128
- finally {
10129
- initializing = null;
10130
- }
10131
- })();
10132
- await initializing;
10133
- },
10134
- };
10135
- const ADVANCED_SECURITY_PLUGIN_SPECIFIER = advancedSecurityPlugin.name;
10136
-
10137
- var plugin = /*#__PURE__*/Object.freeze({
10138
- __proto__: null,
10139
- ADVANCED_SECURITY_PLUGIN_SPECIFIER: ADVANCED_SECURITY_PLUGIN_SPECIFIER,
10140
- default: advancedSecurityPlugin,
10141
- registerAdvancedSecurityPluginFactories: registerAdvancedSecurityPluginFactories
10142
- });
10143
10169
 
10144
10170
  export { FACTORY_META$a as ADVANCED_EDDSA_ENVELOPE_SIGNER_FACTORY_META, FACTORY_META$9 as ADVANCED_EDDSA_ENVELOPE_VERIFIER_FACTORY_META, FACTORY_META$5 as ADVANCED_WELCOME_FACTORY_META, AFTHelper, AFTLoadBalancerStickinessManager, AFTLoadBalancerStickinessManagerFactory, AFTReplicaStickinessManager, AFTReplicaStickinessManagerFactory, FACTORY_META$7 as AFT_LOAD_BALANCER_FACTORY_META, FACTORY_META$6 as AFT_REPLICA_FACTORY_META, AdvancedEdDSAEnvelopeSignerFactory, AdvancedEdDSAEnvelopeVerifierFactory, AdvancedWelcomeService, AdvancedWelcomeServiceFactory, FACTORY_META$2 as BROWSER_TRUST_STORE_PROVIDER_FACTORY_META, BrowserTrustStoreProviderFactory, CAService, CAServiceClient, CAServiceFactory, CASigningService, CA_SERVICE_FACTORY_BASE_TYPE, CertificateRequestError, CompositeEncryptionManager, CompositeEncryptionManagerFactory, FACTORY_META$4 as DEFAULT_CERTIFICATE_MANAGER_FACTORY_META, FACTORY_META$c as DEFAULT_SECURE_CHANNEL_MANAGER_FACTORY_META, DEFAULT_STICKINESS_SECURITY_LEVEL, DefaultCAService, DefaultCAServiceFactory, DefaultCertificateManager, DefaultCertificateManagerFactory, DefaultSecureChannelManager, DefaultSecureChannelManagerFactory, ENV_FAME_CA_CERT_FILE, ENV_FAME_CA_CERT_PEM, ENV_FAME_CA_KEY_FILE, ENV_FAME_CA_KEY_PEM, ENV_FAME_INTERMEDIATE_CHAIN_FILE, ENV_FAME_INTERMEDIATE_CHAIN_PEM, ENV_FAME_SIGNING_CERT_FILE, ENV_FAME_SIGNING_CERT_PEM, ENV_FAME_SIGNING_KEY_FILE, ENV_FAME_SIGNING_KEY_PEM, FACTORY_META$3 as ENV_TRUST_STORE_PROVIDER_FACTORY_META, ENV_VAR_FAME_CA_SERVICE_URL, EdDSAEnvelopeVerifier, EnvTrustStoreProviderFactory, GRANT_PURPOSE_CA_SIGN, LOGICALS_OID, NODE_ID_OID, NoAFTSigner, NullTrustStoreProvider, SID_OID, SidOnlyAFTVerifier, SignedAFTSigner, SignedOptionalAFTVerifier, StickinessMode, StrictAFTVerifier, TRUST_STORE_PROVIDER_FACTORY_BASE_TYPE, TrustStoreProviderFactory, UnsignedAFTSigner, VERSION, X5CKeyManager, X5CKeyManagerFactory, FACTORY_META$8 as X5C_KEY_MANAGER_FACTORY_META, __advancedSecurityPluginLoader, base64UrlDecode, base64UrlEncode, index as channelEncryption, createAftHelper, createAftPayload, createAftReplicaStickinessManager, createAftSigner, createAftVerifier, createEd25519Csr, createEd25519CsrFromPem, createTestCA, extractCertificateInfo, extractLogicalHostsFromCert, extractNodeIdFromCert, extractSidFromCert, extractSidFromSpiffeId, extractSpiffeIdFromCert, formatCertificateInfo, normalizeStickinessMode, publicKeyFromX5c, registerAdvancedSecurityFactories, index$1 as sealedEncryption, serializeAftClaims, serializeAftHeader, utf8Decode, validateJwkX5cCertificate, verifyCertSidIntegrity };