"use strict"; function registerDeploymentIpc({ register, store, resolveRepository, unraid, deployments, evaluateDeploymentPolicy, audit, deployKeys, repositories, inventoryReviews, diagnostics, git, gitea, ssh, preflight, }) { register("deployment:save-profile", async ({ fullName, profile }) => { const saved = await store.saveDeploymentProfile(fullName, profile); await diagnostics.info("deployment.profile.saved", { repository: fullName, profile: saved, }); return { profile: saved, state: store.getPublicState() }; }); register("deployment:delete-profile", async ({ fullName, profileId }) => { const profiles = await store.deleteDeploymentProfile(fullName, profileId); await diagnostics.info("deployment.profile.deleted", { repository: fullName, profileId, }); return { profiles, state: store.getPublicState() }; }); register("deployment:preflight", async ({ repository, profileId }) => { const current = await resolveRepository(repository); const profile = store.getDeploymentProfile(current.fullName, profileId); if (profile?.provider === "ssh-unraid") return unraid.preflight({ repository: current, profileId }); return preflight.runDeployment({ repository: current, profileId }); }); register("deployment:repair-write-access", async ({ repository, profileId }) => { const current = await resolveRepository(repository); const profile = store.getDeploymentProfile(current.fullName, profileId); if (profile?.provider !== "ssh-unraid") throw new Error("Write-access repair is available only for SSH / Unraid deployment profiles."); const result = await unraid.repairWriteAccess({ repository: current, profileId }); await audit.append("deployment.write-access.repaired", { repository: current.fullName, profileId, changed: result.changed, remotePath: result.after?.remotePath || result.before?.remotePath || null, }); return result; }); register( "deployment:dispatch", async ({ repository, profileId, sha, note = "", override = false, overrideReason = "", }) => { const current = await resolveRepository(repository); const profile = store.getDeploymentProfile(current.fullName, profileId); const policy = evaluateDeploymentPolicy(profile, { note, override, reason: overrideReason, }); await audit.append("deployment.requested", { repository: current.fullName, profileId, sha, note: policy.note, overridden: policy.overridden, overrideReason: policy.reason, }); const operation = profile?.provider === "ssh-unraid" ? await unraid.deploy({ repository: current, profileId, sha }) : await deployments.deploy({ repository: current, profileId, sha }); if (operation?.id) await store.addOperation({ ...operation, releaseNote: policy.note, policyOverride: policy.overridden ? { reason: policy.reason, violations: policy.violations } : null, }); return operation; }, ); register( "deployment:rollback", async ({ repository, profileId, targetSha }) => { const current = await resolveRepository(repository); const profile = store.getDeploymentProfile(current.fullName, profileId); if (profile?.provider === "ssh-unraid") return unraid.rollback({ repository: current, profileId, targetSha }); return deployments.rollback({ repository: current, profileId, targetSha, }); }, ); register("deployment:link-server-workload", async ({ repository, serverId, workloadId, deploymentMode = "server-git", remoteFolder = "" }) => { const current = await resolveRepository(repository); const result = await unraid.linkServerWorkload({ repository: current, serverId, workloadId, deploymentMode, remoteFolder, }); return { ...result, state: store.getPublicState() }; }); register("deployment:configure-server-git-access", async ({ repository, profileId }) => { const current = await resolveRepository(repository); const result = await unraid.configureServerGitAccess({ repository: current, profileId }); await audit.append("deployment.server-git-access-configured", { repository: current.fullName, profileId, keyFingerprint: result.keyFingerprint, hostFingerprint: result.hostFingerprint, }); return { ...result, state: store.getPublicState() }; }); register("deployment:verify-server-git-profile", async ({ repository, profileId }) => { const current = await resolveRepository(repository); const result = await unraid.verifyServerGitProfile({ repository: current, profileId }); await audit.append("deployment.server-git-access-verified", { repository: current.fullName, profileId, readiness: result.readiness, ready: result.ready, checkedAt: result.checkedAt, }); return result; }); register("deployment:deploy-key-inventory", async ({ repository, profileId }) => { const current = await resolveRepository(repository); return deployKeys.inventory({ repository: current, profileId }); }); register("deployment:plan-deploy-key-rotation", async ({ repository, profileId }) => { const current = await resolveRepository(repository); return deployKeys.planRotation({ repository: current, profileId }); }); register("deployment:apply-deploy-key-rotation", async ({ repository, profileId, planId }) => { const current = await resolveRepository(repository); const result = await deployKeys.rotate({ repository: current, profileId, expectedPlanId: planId }); return { ...result, state: store.getPublicState() }; }); register("deployment:plan-deploy-key-revocation", async ({ repository, profileId }) => { const current = await resolveRepository(repository); return deployKeys.planRevocation({ repository: current, profileId }); }); register("deployment:apply-deploy-key-revocation", async ({ repository, profileId, planId }) => { const current = await resolveRepository(repository); const result = await deployKeys.revoke({ repository: current, profileId, expectedPlanId: planId }); return { ...result, state: store.getPublicState() }; }); register("deployment:restore-deploy-key", async ({ repository, profileId }) => { const current = await resolveRepository(repository); const result = await deployKeys.restore({ repository: current, profileId }); return { ...result, state: store.getPublicState() }; }); register("deployment:discover-server-workloads", async () => { const repositoryList = await repositories.refresh(); const remoteRepositories = repositoryList.filter( (repository) => repository.owner?.login !== "local", ); const results = []; for (const server of store.data.servers || []) { try { results.push( await unraid.discoverServerWorkloads(server.id, remoteRepositories), ); } catch (error) { results.push({ serverId: server.id, serverName: server.name, detected: 0, adopted: 0, verified: 0, linked: 0, unmatched: 0, needsReview: 0, capabilities: {}, warnings: [], workloads: [], error: error.message, }); } } return results; }); register("deployment:plan-server-reconciliation", async ({ serverId }) => { const repositoryList = await repositories.refresh(); const remoteRepositories = repositoryList.filter((repository) => repository.owner?.login !== "local"); const result = await unraid.planServerInventoryReconciliation(serverId, remoteRepositories, { autoLink: true }); await audit.append("deployment.server-reconciliation-planned", { serverId, planId: result.plan.id, summary: result.plan.summary, }); return result; }); register("deployment:apply-server-reconciliation", async ({ serverId, planId }) => { const repositoryList = await repositories.refresh(); const remoteRepositories = repositoryList.filter((repository) => repository.owner?.login !== "local"); const result = await unraid.reconcileServerInventory(serverId, remoteRepositories, { autoLink: true, expectedPlanId: planId }); await audit.append("deployment.server-reconciliation-applied", { serverId, planId, adopted: result.adopted, refreshed: result.refreshed, retired: result.retired, recoverySnapshot: result.recoverySnapshot?.filePath || null, }); return { ...result, state: store.getPublicState() }; }); register("deployment:plan-inventory-review", async ({ serverId, workloadId, action, reason = "", repositoryFullName = null }) => { const repositoryList = await repositories.refresh(); const inventory = await unraid.scanServerInventory(serverId, repositoryList.filter((item) => item.owner?.login !== "local")); const workload = inventory.workloads.find((item) => item.workloadId === workloadId); if (!workload) throw Object.assign(new Error("The workload changed or disappeared. Rescan before reviewing it."), { code: "INVENTORY_REVIEW_WORKLOAD_STALE" }); return inventoryReviews.preview({ serverId, workload, action, reason, repositoryFullName }); }); register("deployment:apply-inventory-review", async ({ serverId, workloadId, action, reason = "", repositoryFullName = null, planId }) => { const repositoryList = await repositories.refresh(); const inventory = await unraid.scanServerInventory(serverId, repositoryList.filter((item) => item.owner?.login !== "local")); const workload = inventory.workloads.find((item) => item.workloadId === workloadId); if (!workload) throw Object.assign(new Error("The workload changed or disappeared. Rescan before applying the review."), { code: "INVENTORY_REVIEW_WORKLOAD_STALE" }); const plan = inventoryReviews.preview({ serverId, workload, action, reason, repositoryFullName }); const result = await inventoryReviews.apply({ plan, expectedPlanId: planId }); return { ...result, inventory: await unraid.scanServerInventory(serverId, repositoryList.filter((item) => item.owner?.login !== "local")), state: store.getPublicState() }; }); register("deployment:profile-state", async ({ fullName, profileId }) => { const profile = store.getDeploymentProfile(fullName, profileId); if (profile?.provider === "ssh-unraid") { let giteaSha = null; try { const [owner, repo] = String(fullName || "").split("/"); const branch = await gitea.getBranch(owner, repo, profile.branch); giteaSha = branch?.commit?.id || branch?.commit?.sha || null; } catch {} return unraid.refreshProfileState(fullName, profileId, giteaSha); } return deployments.refreshProfileState(fullName, profileId); }); register( "deployment:apply-dockerman-metadata", async ({ repository, profileId }) => { const current = await resolveRepository(repository); return unraid.applyDockerManMetadata({ repository: current, profileId }); }, ); register("deployment:reconcile", async ({ fullName, profileId }) => { const profile = store.getDeploymentProfile(fullName, profileId); if (profile?.provider !== "ssh-unraid") return deployments.refreshProfileState(fullName, profileId); const [owner, repo] = String(fullName || "").split("/"); const branch = await gitea.getBranch(owner, repo, profile.branch); const giteaSha = branch?.commit?.id || branch?.commit?.sha || branch?.commit?.commit?.id || null; const state = await unraid.refreshProfileState( fullName, profileId, giteaSha, ); const operations = store.data.operations.filter( (item) => item.profileId === profileId && item.provider === "ssh-unraid" && !["success", "failed", "cancelled", "rolled-back"].includes( item.status, ), ); for (const operation of operations) await unraid.refreshOperation(operation.id); return { state, operations: await unraid.reconcileRecordedOperations(profileId, state), }; }); } module.exports = { registerDeploymentIpc };