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