diff --git a/static/scripts/fetch-manifest.ts b/static/scripts/fetch-manifest.ts index e39bc08..aa5f467 100644 --- a/static/scripts/fetch-manifest.ts +++ b/static/scripts/fetch-manifest.ts @@ -24,15 +24,12 @@ export class ManifestFetcher { } const repos = await this._octokit.repos.listForOrg({ org }); const manifestCache = this.checkManifestCache(); - function makeUrl(org: string, repo: string, file: string) { - return `https://raw.githubusercontent.com/${org}/${repo}/development/${file}`; - } for (const repo of repos.data) { - const manifestUrl = makeUrl(org, repo.name, "manifest.json"); - const manifest = await this.fetchActionManifest(manifestUrl); + const manifestUrl = this.createGithubRawEndpoint(org, repo.name, "development", "manifest.json"); + const manifest = await this.fetchPluginManifest(manifestUrl); const decoded = this.decodeManifestFromFetch(manifest); - const readme = await this._fetchPluginReadme(makeUrl(org, repo.name, "README.md")); + const readme = await this.fetchPluginReadme(this.createGithubRawEndpoint(org, repo.name, "development", "README.md")); if (decoded) { manifestCache[manifestUrl] = { ...decoded, readme }; @@ -61,9 +58,9 @@ export class ManifestFetcher { } } - createActionEndpoint(owner: string, repo: string, branch: string) { + createGithubRawEndpoint(owner: string, repo: string, branch: string, path: string) { // no endpoint so we fetch the raw content from the owner/repo/branch - return `https://raw.githubusercontent.com/${owner}/${repo}/refs/heads/${branch}/manifest.json`; + return `https://raw.githubusercontent.com/${owner}/${repo}/refs/heads/${branch}/${path}`; } captureActionUrls(config: string) { @@ -92,33 +89,7 @@ export class ManifestFetcher { return officialPluginConfig; } - async fetchWorkerManifest(workerUrl: string) { - const url = workerUrl + "/manifest.json"; - try { - const response = await fetch(url, { - headers: { - "Content-Type": "application/json", - }, - method: "GET", - }); - return await response.json(); - } catch (e) { - let error = e; - try { - const res = await fetch(url.replace(/development/g, "main")); - return await res.json(); - } catch (e) { - error = e; - } - console.error(error); - if (error instanceof Error) { - return { workerUrl, error: error.message }; - } - return { workerUrl, error: String(error) }; - } - } - - async fetchActionManifest(actionUrl: string) { + async fetchPluginManifest(actionUrl: string) { try { const response = await fetch(actionUrl); return await response.json(); @@ -131,24 +102,36 @@ export class ManifestFetcher { } } - private async _fetchPluginReadme(pluginUrl: string) { + async fetchPluginReadme(pluginUrl: string) { + async function handle404(result: string, octokit?: Octokit | null) { + if (result.includes("404: Not Found")) { + const [owner, repo] = pluginUrl.split("/").slice(3, 5); + const readme = await octokit?.repos.getContent({ + owner, + repo, + path: "README.md", + }); + + if (readme && "content" in readme.data) { + return atob(readme.data.content); + } else { + return "No README.md found"; + } + } + + return result; + } try { - const response = await fetch(pluginUrl, { - headers: { - "Content-Type": "application/json", - }, - method: "GET", - }); - return await response.text(); + const response = await fetch(pluginUrl, { signal: new AbortController().signal }); + return await handle404(await response.text(), this._octokit); } catch (e) { let error = e; try { - const res = await fetch(pluginUrl.replace(/development/g, "main")); - return await res.text(); + const res = await fetch(pluginUrl.replace(/development/g, "main"), { signal: new AbortController().signal }); + return await handle404(await res.text(), this._octokit); } catch (e) { error = e; } - console.error(error); if (error instanceof Error) { return error.message; } diff --git a/static/scripts/rendering/input-parsing.ts b/static/scripts/rendering/input-parsing.ts index 5cc341c..0f36331 100644 --- a/static/scripts/rendering/input-parsing.ts +++ b/static/scripts/rendering/input-parsing.ts @@ -70,12 +70,15 @@ export function parseConfigInputs( if (expectedType === "boolean") { value = (input as HTMLInputElement).checked; } else if (expectedType === "object" || expectedType === "array") { - try { - value = JSON.parse((input as HTMLTextAreaElement).value); - } catch (e) { - console.error(e); - throw new Error(`Invalid JSON input for ${expectedType} at key "${key}": ${input.value}`); - } + if (!input.value) { + value = expectedType === "object" ? {} : []; + } else + try { + value = JSON.parse((input as HTMLTextAreaElement).value); + } catch (e) { + console.error(e); + throw new Error(`Invalid JSON input for ${expectedType} at key "${key}": ${input.value}`); + } } else { value = (input as HTMLInputElement).value; } @@ -85,7 +88,12 @@ export function parseConfigInputs( if (validate(config)) { const missing = []; for (const key of required) { - if (!(config[key] || config[key] === "undefined" || config[key] === "null")) { + const isBoolean = schema.properties && schema.properties[key] && schema.properties[key].type === "boolean"; + if ((isBoolean && config[key] === false) || config[key] === true) { + continue; + } + + if (!config[key] || config[key] === "undefined" || config[key] === "null") { missing.push(key); } } diff --git a/static/scripts/rendering/write-add-remove.ts b/static/scripts/rendering/write-add-remove.ts index ea792e1..775a358 100644 --- a/static/scripts/rendering/write-add-remove.ts +++ b/static/scripts/rendering/write-add-remove.ts @@ -38,20 +38,15 @@ export function writeNewConfig(renderer: ManifestRenderer, option: "add" | "remo } renderer.configParser.loadConfig(); - - const officialPluginConfig: Record = getOfficialPluginConfig(); - - const pluginName = pluginManifest.name; - // this relies on the manifest matching the repo name - const normalizedPluginName = normalizePluginName(pluginName); - + const normalizedPluginName = normalizePluginName(pluginManifest.name); + const officialPluginConfig: Record = getOfficialPluginConfig(); const pluginUrl = Object.keys(officialPluginConfig).find((url) => { return url.includes(normalizedPluginName); }); if (!pluginUrl) { - toastNotification(`No plugin URL found for ${pluginName}.`, { + toastNotification(`No plugin URL found for ${normalizedPluginName}.`, { type: "error", shouldAutoDismiss: true, });