writeSourceConfig = async (options, source, spinner) => {
	const secrets = getSecretOptions(options);
	const safes = getSafeOptions(options);

	const safesFileString = [
		`# This file was automatically generated`,
		yaml.stringify({ ...source, options: safes, dir: undefined })
	]
		.join('\n')
		.replace(
			'buildOptions:',
			[`# Advanced Options, you probably don't want to change this`, `buildOptions:`].join('\n')
		);

	const secretsFileString = [
		`# This file was automatically generated`,
		`# Do not edit this file manually; instead use npx evidence-sdk sources edit`,
		``,
		`# It should *not* be source controlled, as it likely contain credentials or other sensitive configuration values.`,
		`# Values in this file are base64 encoded; https://it-tools.tech/base64-string-converter has an excellent encoder / decoder tool.`,
		`# Base64 is NOT encryption, and should not be treated as secure`,
		yaml.stringify(encodeBase64Deep(secrets))
	].join('\n');

	if (
		!source.dir ||
		!path.dirname(source.dir).startsWith(sourcesDirectory) ||
		!path.isAbsolute(source.dir)
	) {
		source.dir = path.join(sourcesDirectory, source.name);
	}

	const safesPath = path.join(source.dir, 'connection.yaml');
	const secretsPath = path.join(source.dir, 'connection.options.yaml');

	await fs.mkdir(source.dir, { recursive: true });

	spinner?.start(`Saving ${source.name}`);
	await fs.writeFile(safesPath, safesFileString);
	await fs.writeFile(secretsPath, secretsFileString);
	spinner?.stop(`Finished saving ${source.name}`);

	return /** @type {import("./schemas/datasource.schema.js").DatasourceSpec & { dir: string }} */ (
		source
	);
}
@param {import("./cli/edit/Options.js").OptionsObj} options
@param {import("./schemas/datasource.schema.js").DatasourceSpec & { dir?: string }} source
@param {import('../../lib/flows.js').EvidenceLoadIndicator} [spinner]
@returns {Promise<import("./schemas/datasource.schema.js").DatasourceSpec & { dir: string }>} Source, with the directory attached if it was not previously