diff --git a/dashcaddy-api/src/app.js b/dashcaddy-api/src/app.js index f5ca7ca..2d1d3e6 100644 --- a/dashcaddy-api/src/app.js +++ b/dashcaddy-api/src/app.js @@ -779,7 +779,29 @@ async function createApp() { // Private Network wizard (DC-152). Dogfood finding 2026-10-04: the wizard // factory needs INSTANCES keyed by mode id; without them every mode // selection 503s provider_unavailable (unit tests inject their own map). - const p7TailscaleProvider = require('./network/providers/tailscale').createTailscaleProvider(); // eslint-disable-line global-require + // Coord client wiring (dogfood finding #2, 2026-10-04): the provider is + // built with coordClient=null and nothing ever called attachCoordClient() + // in prod (the promised routes/network.js wiring never landed), so wizard + // credential validation always failed not_configured. Delegate every coord + // method to a FRESH client per call — the sanctioned context pattern + // (ctx.tailscaleCoord.getClient re-reads the token from credentialManager + // each call, so wizard-stored tokens take effect without a restart). + const p7CoordProxy = new Proxy({}, { + get(_t, prop) { + if (typeof prop !== 'string') return undefined; + return async (...args) => { + const client = await ctx.tailscaleCoord.getClient(); + const fn = client ? client[prop] : null; + if (typeof fn !== 'function') { + throw new Error('coord client method unavailable: ' + String(prop)); + } + return fn.apply(client, args); + }; + }, + }); + const p7TailscaleProvider = require('./network/providers/tailscale').createTailscaleProvider({ // eslint-disable-line global-require + coordClient: p7CoordProxy, + }); const p7WireGuardProvider = require('./network/providers/wireguard').createWireGuardProvider(); // eslint-disable-line global-require apiRouter.use('/network/wizard', networkWizardRoutes({ registry: { getActiveProvider },