'use strict'; const {randomUUID}=require('node:crypto'); const {BrokerAuditEventSchema}=require('../../packages/core/broker-audit.cjs'); const {createProductionBroker}=require('./production-factory.cjs'); const UUID=/^[a-f0-9]{8}-[a-f0-9]{4}-[1-8][a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$/i; const exact=(value,keys)=>value&&typeof value==='object'&&!Array.isArray(value)&&Object.keys(value).sort().join(',')===keys.sort().join(','); /** Inherited IPC is the only bootstrap/control surface. No CLI, environment * credential, public management listener, dynamic module or private key IPC. */ function runProductionProcess(factory=createProductionBroker,channel=process){ if(typeof factory!=='function'||typeof channel.send!=='function'||!channel.connected)throw Error('broker-process-invalid'); let state='waiting',context,broker,construction,initialization,closing,cleanup,sequence=0;const pending=new Map(); const closeBroker=created=>{if(!cleanup){cleanup=Promise.resolve().then(()=>created.close());cleanup.catch(()=>{});}return cleanup;}; const close=()=>{ if(closing)return closing;state='closing';for(const value of pending.values()){clearTimeout(value.timer);value.reject(Error('broker-parent-unavailable'));}pending.clear(); closing=Promise.resolve().then(async()=>{ // Construction and listen retain ownership until their ORIGINAL promises // settle. A late factory result cannot become ready or escape cleanup. let created=broker;try{created=created||await construction;}catch{} try{if(created)await closeBroker(created);}finally{await initialization?.catch(()=>{});} }).finally(()=>{if(channel.connected)channel.disconnect();}); // Event-driven callers may discard the promise; explicit close callers still // receive the real sticky cleanup failure, never a fabricated confirmation. closing.catch(()=>{});return closing; }; const send=message=>{if(!channel.connected||state==='closing')throw Error('broker-parent-unavailable');channel.send(message,error=>{if(error)void close();});}; const rpc=(type,payload)=>new Promise((resolve,reject)=>{ if(pending.size>=8||state==='closing'||!context){reject(Error('broker-parent-unavailable'));return;} if(sequence>=Number.MAX_SAFE_INTEGER){reject(Error('broker-parent-unavailable'));void close();return;} const nextSequence=++sequence,requestId=randomUUID(),timer=setTimeout(()=>{void close();},30000); pending.set(requestId,{type,sequence:nextSequence,eventId:payload.event?.eventId,resolve,reject,timer}); try{send({type,...context,requestId,sequence:nextSequence,...payload});}catch{void close();} }); channel.once('disconnect',()=>{void close();}); channel.on('message',message=>{ try{ const bytes=Buffer.byteLength(JSON.stringify(message));if(!message||bytes>(state==='waiting'?2097152:65536))throw Error(); if(state==='waiting'){ if(!exact(message,['type','version','generation','policyVersion','config'])||message.type!=='start'||message.version!==1||!UUID.test(message.generation)||!Number.isSafeInteger(message.policyVersion)||message.policyVersion<1)throw Error(); context={version:1,generation:message.generation,policyVersion:message.policyVersion};state='starting'; construction=Promise.resolve().then(()=>factory(message.config,{expectedPolicyVersion:context.policyVersion,persistAudit:async event=>{ BrokerAuditEventSchema.parse(event);if(event.policyVersion!==context.policyVersion)throw Error('broker-parent-unavailable'); return rpc('audit',{event}); },acknowledgeCertificate:async({authority,cert})=>rpc('certificate',{authority,cert})})); initialization=construction.then(async created=>{ broker=created;if(state==='closing')return; const port=await broker.listen();if(state==='closing')return; if(created.authMode!=='basic'||port!==message.config.brokerPort||!/^safetynet-[a-f0-9]{32}$/.test(created.credentials?.username)||!/^[A-Za-z0-9_-]{43}$/.test(created.credentials?.password))throw Error(); state='ready';send({type:'ready',...context,sequence:0,authMode:'basic',port,credentials:{...created.credentials}}); }).catch(error=>{const codes=new Set(['broker-bootstrap-invalid','broker-route-unsupported','broker-startup-inspector','broker-startup-certificate','broker-startup-transport','broker-startup-managed']);const code=codes.has(error?.message)?error.message:'broker-startup-failed';try{send({type:'startup-fault',...context,code});}catch{}void close();});return; } if(message.version!==1||message.generation!==context.generation||message.policyVersion!==context.policyVersion)throw Error(); if(message.type==='stop'&&exact(message,['type','version','generation','policyVersion'])){void close();return;} const value=pending.get(message.requestId);if(!value||message.sequence!==value.sequence)throw Error(); if(value.type==='audit'&&exact(message,['type','version','generation','policyVersion','requestId','sequence','receipt'])&&message.type==='audit-receipt'&&exact(message.receipt,['persisted','eventId'])&&message.receipt.persisted===true&&message.receipt.eventId===value.eventId){clearTimeout(value.timer);pending.delete(message.requestId);value.resolve(Object.freeze({...message.receipt}));return;} if(value.type==='certificate'&&exact(message,['type','version','generation','policyVersion','requestId','sequence','accepted'])&&message.type==='certificate-receipt'&&message.accepted===true){clearTimeout(value.timer);pending.delete(message.requestId);value.resolve(true);return;} throw Error(); }catch{void close();} }); return Object.freeze({close}); } if(require.main===module)runProductionProcess(); module.exports={runProductionProcess};