@goodfellow-cms/broker 0.8.0 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +11 -7
- package/site/assets/{content-repository-setup-0zqQHkZ9.js → content-repository-setup-CzHqy87S.js} +1 -1
- package/site/assets/{dist-C2zb_90U.js → dist-BgSqMIdW.js} +1 -1
- package/site/assets/dist-D1ZOk-UP.js +6 -0
- package/site/assets/dist-pDBJlXWC.js +21 -0
- package/site/assets/index-BXiri33U.js +234 -0
- package/site/assets/{index-DrAt6GVO.css → index-fBFd9gqV.css} +1 -1
- package/site/assets/preload-helper-CEqbogAV.js +1 -0
- package/site/assets/{setup-host-BAQmd0y1.js → setup-host-D55O8ui4.js} +1 -1
- package/site/assets/store-BxUMMiN8.js +1 -0
- package/site/files.json +9 -9
- package/site/index.html +4 -4
- package/site/assets/dist-86wrqcsN.js +0 -6
- package/site/assets/dist-DJGm2ktT.js +0 -21
- package/site/assets/index-C1mWwm_b.js +0 -234
- package/site/assets/preload-helper-9CpHFPb-.js +0 -1
- package/site/assets/store-BJ3bMnko.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light dark;--bg:var(--lightningcss-light,#fff)var(--lightningcss-dark,#14161a);--fg:var(--lightningcss-light,#1b1f24)var(--lightningcss-dark,#e8eaed);--muted:var(--lightningcss-light,#5b6470)var(--lightningcss-dark,#a3aab4);--line:var(--lightningcss-light,#d9dde3)var(--lightningcss-dark,#343a42);--accent:var(--lightningcss-light,#1e3a8a)var(--lightningcss-dark,#93b4ff);--accent-fg:var(--lightningcss-light,#fff)var(--lightningcss-dark,#0b1530);--error:var(--lightningcss-light,#a3221b)var(--lightningcss-dark,#ff9a92);font-family:system-ui,sans-serif}@media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial}}*{box-sizing:border-box}html,body{background:var(--bg);height:100%;color:var(--fg);margin:0}#broker{flex-direction:column;height:100%;display:flex}.broker-note,.broker-sign-in{max-width:32rem;margin:4rem auto;padding:0 1rem;line-height:1.5}.broker-sign-in{flex-direction:column;gap:.75rem;display:flex}.broker-sign-in h1{margin:0;font-size:1.5rem}.broker-sign-in h2{margin:1rem 0 0;font-size:1rem}input[type=password]{border:1px solid var(--line);background:var(--bg);width:100%;color:var(--fg);font:inherit;border-radius:.375rem;padding:.5rem}button{border:1px solid var(--line);background:var(--bg);color:var(--fg);font:inherit;cursor:pointer;border-radius:.375rem;padding:.4rem .9rem}.broker-primary,button[type=submit]{background:var(--accent);border-color:var(--accent);color:var(--accent-fg)}a{color:var(--accent)}.broker-error{color:var(--error);min-height:1lh;margin:0}.broker-check{align-items:center;gap:.25rem;display:flex}.broker-bar{border-bottom:1px solid var(--line);color:var(--muted);justify-content:flex-end;align-items:center;gap:.75rem;padding:.25rem .75rem;font-size:.875rem;display:flex}.broker-origin{overflow-wrap:anywhere;margin-inline-end:auto}.broker-bar button{padding:.15rem .6rem}.broker-frame{border:0;flex:1;width:100%}.broker-dialog{border:1px solid var(--line);background:var(--bg);max-width:34rem;color:var(--fg);border-radius:.5rem;line-height:1.5}.broker-dialog::backdrop{background:#0006}.broker-dialog label{margin-top:.5rem;display:block}.broker-actions{justify-content:flex-end;gap:.5rem;margin-top:1rem;display:flex}
|
|
1
|
+
:root{--lightningcss-light:initial;--lightningcss-dark: ;color-scheme:light dark;--bg:var(--lightningcss-light,#fff)var(--lightningcss-dark,#14161a);--fg:var(--lightningcss-light,#1b1f24)var(--lightningcss-dark,#e8eaed);--muted:var(--lightningcss-light,#5b6470)var(--lightningcss-dark,#a3aab4);--line:var(--lightningcss-light,#d9dde3)var(--lightningcss-dark,#343a42);--accent:var(--lightningcss-light,#1e3a8a)var(--lightningcss-dark,#93b4ff);--accent-fg:var(--lightningcss-light,#fff)var(--lightningcss-dark,#0b1530);--error:var(--lightningcss-light,#a3221b)var(--lightningcss-dark,#ff9a92);font-family:system-ui,sans-serif}@media (prefers-color-scheme:dark){:root{--lightningcss-light: ;--lightningcss-dark:initial}}*{box-sizing:border-box}html,body{background:var(--bg);height:100%;color:var(--fg);margin:0}#broker{flex-direction:column;height:100%;display:flex}.broker-note,.broker-sign-in{max-width:32rem;margin:4rem auto;padding:0 1rem;line-height:1.5}.broker-sign-in{flex-direction:column;gap:.75rem;display:flex}.broker-sign-in h1{margin:0;font-size:1.5rem}.broker-sign-in h2{margin:1rem 0 0;font-size:1rem}input[type=password]{border:1px solid var(--line);background:var(--bg);width:100%;color:var(--fg);font:inherit;border-radius:.375rem;padding:.5rem}button{border:1px solid var(--line);background:var(--bg);color:var(--fg);font:inherit;cursor:pointer;border-radius:.375rem;padding:.4rem .9rem}.broker-primary,button[type=submit]{background:var(--accent);border-color:var(--accent);color:var(--accent-fg)}a{color:var(--accent)}.broker-warning{border-inline-start:3px solid var(--error);padding-inline-start:.75rem}.broker-error{color:var(--error);min-height:1lh;margin:0}.broker-check{align-items:center;gap:.25rem;display:flex}.broker-bar{border-bottom:1px solid var(--line);color:var(--muted);justify-content:flex-end;align-items:center;gap:.75rem;padding:.25rem .75rem;font-size:.875rem;display:flex}.broker-origin{overflow-wrap:anywhere;margin-inline-end:auto}.broker-bar button{padding:.15rem .6rem}.broker-frame{border:0;flex:1;width:100%}.broker-dialog{border:1px solid var(--line);background:var(--bg);max-width:34rem;color:var(--fg);border-radius:.5rem;line-height:1.5}.broker-dialog::backdrop{background:#0006}.broker-dialog label{margin-top:.5rem;display:block}.broker-actions{justify-content:flex-end;gap:.5rem;margin-top:1rem;display:flex}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=/^[a-z0-9](?:[a-z0-9-]{0,62}[a-z0-9])?$/;function t(e){let t=e.trim(),n=/\sdata-api\s*=\s*["']([^"'<>\s]+)["']/i.exec(t)?.[1]??/\ssrc\s*=\s*["']([^"'<>\s]+)\/embed\.js["']/i.exec(t)?.[1]??(/^[^\s<>"']+$/.test(t)?t:void 0);if(!n)return;let r;try{r=new URL(n)}catch{return}let i=r.hostname===`localhost`||r.hostname===`127.0.0.1`;if((r.protocol===`https:`||r.protocol===`http:`&&i)&&!(/^[a-z]+:\/\/[^/]*@/i.test(n)||/(^|\.)disqus\.com$/i.test(r.hostname)))return r.origin}var n=/^[A-Za-z0-9-]+\/[A-Za-z0-9._-]+$/,r=/^[A-Za-z0-9_-]+$/,i=class extends Error{problem;link;name=`CommentsError`;constructor(e,t,n){super(t),this.problem=e,this.link=n}},a=`https://github.com/apps/giscus`,o=(function(){let e=typeof document<`u`&&document.createElement(`link`).relList;return e&&e.supports&&e.supports(`modulepreload`)?`modulepreload`:`preload`})(),s=function(e,t){return new URL(e,t).href},c={},l=function(e){return e.pathname.endsWith(`.css`)},u=function(e,t,n){if(t in e)return e[t];let r=n();if(!r){e[t]=void 0;return}let i=r.then(()=>{e[t]=void 0},n=>{throw e[t]=void 0,n});return e[t]=i,i},d=function(e,t,n){let r=Promise.resolve();if(t&&t.length>0){let e,i=document.querySelector(`meta[property=csp-nonce]`),a=i?.nonce||i?.getAttribute(`nonce`);function d(e){return Promise.all(e.map(e=>Promise.resolve(e).then(e=>({status:`fulfilled`,value:e}),e=>({status:`rejected`,reason:e}))))}function f(e){return import.meta.resolve?new URL(import.meta.resolve(e)):new URL(e,import.meta.url)}r=d(t.map(t=>{t=s(t,n);let r=f(t),i=l(r);return u(c,r.href,()=>{if(e===void 0){e={all:new Set,styles:new Set};let t=document.getElementsByTagName(`link`);for(let n=t.length-1;n>=0;n--){let r=t[n];e.all.add(r.href),r.rel===`stylesheet`&&e.styles.add(r.href)}}if((i?e.styles:e.all).has(r.href))return;let t=document.createElement(`link`);if(t.rel=i?`stylesheet`:o,i||(t.as=`script`),t.crossOrigin=``,t.href=r.href,a&&t.setAttribute(`nonce`,a),document.head.appendChild(t),i)return new Promise((e,n)=>{t.addEventListener(`load`,e),t.addEventListener(`error`,()=>n(Error(`Unable to preload CSS for ${r}`)))})})}).filter(e=>e!==void 0))}function i(e){let t=new Event(`vite:preloadError`,{cancelable:!0});if(t.payload=e,window.dispatchEvent(t),!t.defaultPrevented)throw e}return r.then(t=>{for(let e of t||[])e.status===`rejected`&&i(e.reason);return e().catch(i)})};export{e as a,i,r as n,a as o,n as r,t as s,d as t};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e}from"./store-
|
|
1
|
+
import{a as e}from"./store-BxUMMiN8.js";function t(e){let t=/^[\^~=v]*(\d+)\.(\d+)\.(\d+)$/.exec(e.trim());return t?[Number(t[1]),Number(t[2]),Number(t[3])]:void 0}function n(e,t){return e[0]-t[0]||e[1]-t[1]||e[2]-t[2]}function r(e,r){let i=t(e),a=t(r);return i&&a?n(i,a):0}function i(e){return t(e)?.join(`.`)}function a(e){try{let{dependencies:t={},devDependencies:n={}}=JSON.parse(e),r=t[`@goodfellow-cms/react`]??n[`@goodfellow-cms/react`];return r?i(r):void 0}catch{return}}var o=`goodfellow-update `;function s(e){let t=e.split(`
|
|
2
2
|
`);for(let e=t.length-1;e>=0;e--){let n=t[e]??``,r=n.indexOf(o);if(r!==-1)try{let e=JSON.parse(n.slice(r+18).trim());if([`up-to-date`,`updated`,`failed`].includes(e.state)&&typeof e.from==`string`)return e}catch{}}}var c=`GOODFELLOW_NIGHTLY`,l=[`changed`,`always`,`off`];function u(e){let t=e?.trim().toLowerCase();return l.includes(t)?t:`changed`}var d=class extends Error{problem;name=`UpdatesError`;constructor(e,t){super(t),this.problem=e}},f=/^[a-z0-9]{8,40}$/,p=`goodfellow-task-`,m=`goodfellow-task-result.json`,h=`plugin-task.yml`,g=`plugin-task`,_=`goodfellow-plugin-task`;function v(e){return f.test(e)}function y(e){let{id:t,plugin:n,task:r,input:i,key:a}=e;if(![t,n,r,i,a].every(e=>typeof e==`string`))return`That isn't a task's request.`;if(!v(e.id))return`The request's id isn't one the admin panel makes.`;if(!/^[a-z0-9][a-z0-9._-]*(--[a-z0-9][a-z0-9._-]*)?$/.test(e.plugin))return`That isn't a plugin's id.`;if(!/^[a-z0-9][a-z0-9-]*$/.test(e.task))return`That isn't a task's id.`;if(e.input.length>32e3)return`The task's input is too long.`;try{JSON.parse(e.input);let t=JSON.parse(e.key);if(t.kty!==`EC`||t.crv!==`P-256`||t.d!==void 0)return`The answer's key isn't a public key.`}catch{return`The task's input or key isn't JSON.`}}var b=class extends Error{problem;name=`PluginTaskError`;constructor(e,t){super(t),this.problem=e}},x=3e5,S=4e3,C=`goodfellow-draft-`,w=/^[a-z0-9][a-z0-9-]{0,39}$/;function T(e){return w.test(e)}var E=class extends Error{name=`DraftError`;problem;constructor(e,t){super(t),this.problem=e}};function D(e){if(!T(e))throw new E(`not-found`,`"${e}" isn't a draft's name.`);return`${C}${e}`}function O(t,n){async function r(e){try{await n.closeReview(e)}catch{}}function i(i,a){let o=n.branchStore(a);async function s(){let e=await n.mergeBase(a);return o.changedPaths(e,await o.revision())}async function c(){let e=[];for(let t of await s())if(t.startsWith(`public/media/`)){let n=await o.readBytes(t);e.push(n?{path:t,bytes:n}:{path:t,delete:!0})}else{let n=await o.read(t);e.push(n===void 0?{path:t,delete:!0}:{path:t,content:n})}return e}return{name:i,store:o,changes:c,paths:s,async publish(i){let o=await n.mergeBase(a),s=await c(),l=s.length>0?await e(t,s,{message:i,expectedRevision:o}):{revision:await t.revision()};return await r(a),await n.deleteBranch(a),l},async submitForReview({title:e,description:t=``,reviewers:r}){return n.openReview({branch:a,title:e,description:t,...r?.length&&{reviewers:r}})},async discard(){await r(a),await n.deleteBranch(a)}}}return{async create(e,r){let a=D(e);return await n.createBranch(a,r?.from??await t.revision()),i(e,a)},async open(e){let t=D(e);return await n.mergeBase(t),i(e,t)},async list(){return(await n.listBranches(C)).map(e=>e.slice(17)).filter(T).sort().reverse()},async reviews(){return(await n.listReviews(C)).map(e=>({name:e.branch.slice(17),url:e.url,title:e.title})).filter(e=>T(e.name)).sort((e,t)=>t.name.localeCompare(e.name))}}}var k=class extends Error{problem;name=`EditorsError`;constructor(e,t){super(t),this.problem=e}},A=3,j=class extends Error{name=`RateLimitError`;status;resetsAt;constructor(e,t,n){super(`${n} is limiting how many requests this sign-in can make${t?` until ${t.toISOString()}`:` for now`}.`),this.status=e,t&&(this.resetsAt=t)}};function M(e,t=Date.now()){let n=e.get(`retry-after`);if(n){let e=Number(n);if(Number.isFinite(e))return Math.max(0,e*1e3);let r=Date.parse(n);if(Number.isFinite(r))return Math.max(0,r-t)}let r=e.get(`ratelimit-reset`)??e.get(`x-ratelimit-reset`);if(r&&/^\d+$/.test(r))return Math.max(0,Number(r)*1e3-t)}function N(e){return e.status===429||e.status===403&&(e.headers.has(`retry-after`)||e.headers.get(`x-ratelimit-remaining`)===`0`)}function P(e,t){let n=t.sleep??(e=>new Promise(t=>globalThis.setTimeout(t,e))),r=t.now??Date.now,i=e=>typeof e?.getReader==`function`;return(async(a,o)=>{let s=!i(o?.body)&&!i(a?.body);for(let i=0;;i++){let c=await e(a,o);if(!s||!N(c))return c;let l=M(c.headers,r()),u=Math.max(l??5e3*2**i,1e3);if(i>=A||u>6e4)throw new j(c.status,l===void 0?void 0:new Date(r()+l),t.host);await c.body?.cancel().catch(()=>{}),await n(u)}})}var F=class extends Error{problem;link;name=`SetupError`;constructor(e,t,n){super(t),this.problem=e,this.link=n}};export{r as _,O as a,a as b,_ as c,m as d,x as f,d as g,c as h,E as i,g as l,y as m,P as n,b as o,h as p,k as r,p as s,F as t,S as u,s as v,u as y};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var e=`content`,t=`content/pages`,n=`content/site.json`,r=`content/menus.json`,i=`content/styles/theme.json`,a=`content/permissions.json`,o=`public/media`,s=`content/collections`,c=`blocks/installed`,l=`plugins/installed`,u=`plugins/installed/installed.json`,d=`components`,f=`hooks`,p=`content-repository`,m=`_collection.json`,h=/^[a-z0-9]+(?:-[a-z0-9]+)*$/,g=class extends Error{name=`InvalidPathError`};function _(e){if(!e.startsWith(`/`))throw new g(`Page addresses must start with "/" (got "${e}").`);let t=e.split(`/`).filter(e=>e!==``);for(let e of t)if(!h.test(e))throw new g(`"${e}" can't be part of a page address. Use lowercase letters, numbers and hyphens only.`);return t}function v(e){return`/${_(e).join(`/`)}`}function y(e){let n=`${t}/`;if(!e.startsWith(n)||!e.endsWith(`.json`))throw new g(`${e} is not a page file. Pages are .json files in ${t}/.`);let r=e.slice(n.length,-5).split(`/`);return r.at(-1)===`index`&&r.pop(),v(`/${r.join(`/`)}`)}var b=`{slug}`;function x(e){if(!e.startsWith(`/`))return`must start with "/".`;let t=e.split(`/`).filter(e=>e!==``);if(t.filter(e=>e===`{slug}`).length!==1)return`must contain ${b} exactly once, such as /videos/${b}.`;let n=t.find(e=>e!==`{slug}`&&!h.test(e));if(n!==void 0)return`can't contain "${n}". Use lowercase letters, numbers and hyphens only.`}var S=class extends Error{name=`ConflictError`;constructor(e=`The site changed since it was loaded.`){super(e)}},C=[e,o,c,d,`lib`,f,l];function w(e){return e.startsWith(`/`)||e.includes(`\\`)||e.includes(`\0`)||e.split(`/`).some(e=>e===``||e===`.`||e===`..`)?!1:C.some(t=>e.startsWith(`${t}/`))}async function T(e,t,n){let r=n.expectedRevision,i=new Set(t.map(e=>e.path));for(let a=0;;a++)try{return await e.write(t,{...n,expectedRevision:r})}catch(t){if(!(t instanceof S)||!e.changedPaths||a===2)throw t;let o=await e.revision();if(o===r)throw t;let s=await e.changedPaths(n.expectedRevision,o).catch(()=>void 0);if(!s||s.some(e=>i.has(e)))throw t;r=o}}var E=[e,o];function D(e){return w(e)&&E.some(t=>e.startsWith(`${t}/`))}var O=class extends Error{name=`CodeChangeError`;constructor(e){super(`${e} is part of the site's code, which is kept in a repository of its own, not the content repository.`)}};function k(e){let t=e.find(e=>!D(e.path));if(t)throw new O(t.path)}export{T as a,p as c,r as d,a as f,y as g,x as h,D as i,u as l,i as m,C as n,s as o,n as p,k as r,m as s,S as t,o as u};
|
package/site/files.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": [
|
|
3
3
|
"_headers",
|
|
4
|
-
"assets/content-repository-setup-
|
|
4
|
+
"assets/content-repository-setup-CzHqy87S.js",
|
|
5
5
|
"assets/deploy-keys-DAj2oX-N-DRd_HmOG.js",
|
|
6
|
-
"assets/dist-
|
|
7
|
-
"assets/dist-
|
|
8
|
-
"assets/dist-
|
|
6
|
+
"assets/dist-BgSqMIdW.js",
|
|
7
|
+
"assets/dist-D1ZOk-UP.js",
|
|
8
|
+
"assets/dist-pDBJlXWC.js",
|
|
9
9
|
"assets/git-eGyMXUIu.js",
|
|
10
|
-
"assets/index-
|
|
11
|
-
"assets/index-
|
|
12
|
-
"assets/preload-helper-
|
|
10
|
+
"assets/index-BXiri33U.js",
|
|
11
|
+
"assets/index-fBFd9gqV.css",
|
|
12
|
+
"assets/preload-helper-CEqbogAV.js",
|
|
13
13
|
"assets/scheduled-builds-BPfDaBYt.js",
|
|
14
|
-
"assets/setup-host-
|
|
15
|
-
"assets/store-
|
|
14
|
+
"assets/setup-host-D55O8ui4.js",
|
|
15
|
+
"assets/store-BxUMMiN8.js",
|
|
16
16
|
"broker.example.json",
|
|
17
17
|
"index.html",
|
|
18
18
|
"vercel.json"
|
package/site/index.html
CHANGED
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
/>
|
|
10
10
|
<meta name="referrer" content="no-referrer" />
|
|
11
11
|
<title>Sign in</title>
|
|
12
|
-
<script type="module" crossorigin src="./assets/index-
|
|
13
|
-
<link rel="modulepreload" crossorigin href="./assets/
|
|
14
|
-
<link rel="modulepreload" crossorigin href="./assets/
|
|
15
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
12
|
+
<script type="module" crossorigin src="./assets/index-BXiri33U.js"></script>
|
|
13
|
+
<link rel="modulepreload" crossorigin href="./assets/preload-helper-CEqbogAV.js">
|
|
14
|
+
<link rel="modulepreload" crossorigin href="./assets/store-BxUMMiN8.js">
|
|
15
|
+
<link rel="stylesheet" crossorigin href="./assets/index-fBFd9gqV.css">
|
|
16
16
|
</head>
|
|
17
17
|
<body>
|
|
18
18
|
<div id="broker"></div>
|
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import{n as e,r as t,t as n}from"./store-BJ3bMnko.js";import{a as r,d as i,g as a,h as o,i as s,l as c,m as l,n as u,o as d,r as f,t as p,v as m}from"./setup-host-BAQmd0y1.js";import{i as h,n as ee,r as te}from"./content-repository-setup-0zqQHkZ9.js";import{n as g,o as _,r as v,s as y,t as b}from"./git-eGyMXUIu.js";import{t as x}from"./scheduled-builds-BPfDaBYt.js";async function S(e,t,n={}){let r,i=async i=>(r=await e.token(i?{refresh:i,...r!==void 0&&{stale:r}}:{}),e.fetch(`${e.apiUrl}${t}`,{method:n.method??`GET`,headers:{authorization:`Bearer ${r}`,...n.body!==void 0&&{"content-type":`application/json`}},body:n.body===void 0?void 0:JSON.stringify(n.body),cache:`no-store`})),a=await i(!1);if(a.status===401&&e.canRefresh&&(a=await i(!0)),a.status===401)throw new g(`invalid`,`GitLab didn't accept the sign-in. It may have expired.`);if(!a.ok&&!n.allow?.includes(a.status)){let e=await a.json().catch(()=>({})),t=typeof e.message==`string`?e.message:JSON.stringify(e.message??e.error??``);throw new b(a.status,`GitLab answered ${a.status}: ${t||a.statusText}`)}return a}async function C(e,t,n){return await(await S(e,t,n)).json()}var w=30,T=40,ne=`member:`,E=`invitation:`,re=/^[^\s@]+@[^\s@]+\.[^\s@]+$/,ie=/^[\w][\w.-]*$/;function D(e){return e>=T?`owner`:e>=w?`editor`:`viewer`}function O(e){return e===`owner`?T:w}function k(e){throw e instanceof b&&(e.status===401||e.status===403)?new f(`not-allowed`,`Changing editors on GitLab needs the Maintainer role in the project.`):e}function ae(e,t,n,r){let i=`/projects/${encodeURIComponent(t)}`,a=`${i}/protected_branches/${encodeURIComponent(n)}`;async function o(t){let n=[];for(let r=1;r<=10;r++){let i=await C(e,`${t}${t.includes(`?`)?`&`:`?`}per_page=100&page=${r}`);if(n.push(...i),i.length<100)break}return n}return{invitesByEmail:!0,async list(){let[t,n]=await Promise.all([o(`${i}/members/all`),o(`${i}/members`)]),s=new Set(n.map(e=>e.id)),c=t.find(e=>e.username.toLowerCase()===r.toLowerCase()),l=(c?.access_level??0)>=T,u=l?await o(`${i}/invitations`).catch(()=>[]):[],d=await S(e,a,{allow:[404]}),f=d.ok?(await d.json()).push_access_levels??[]:[],p=!d.ok||f.some(e=>e.access_level!==null&&e.access_level<=w);return{editors:[...t.map(e=>({id:`${ne}${e.id}`,login:e.username,name:e.name,avatarUrl:e.avatar_url,role:D(e.access_level),...!s.has(e.id)&&{inherited:!0},...e.id===c?.id&&{self:!0}})),...u.map(e=>({id:`${E}${e.invite_email}`,email:e.invite_email,role:D(e.access_level),invited:!0}))],manage:l?`yes`:`no`,editorsCanPublish:p}},async invite(t,n){let r=t.trim().replace(/^@/,``);if(r.includes(`@`)){if(!re.test(r))throw new f(`invalid`,`That isn't an email address.`);let t=await C(e,`${i}/invitations`,{method:`POST`,body:{email:r,access_level:O(n)}}).catch(k);if(t.status!==`success`){let e=typeof t.message==`string`?t.message:Object.values(t.message??{})[0];throw/already/i.test(e??``)?new f(`already`,`They've already been invited.`):new f(`invalid`,`GitLab didn't accept the invitation: ${e??t.status}`)}return}if(!ie.test(r))throw new f(`invalid`,`That isn't a GitLab username or email address.`);let[a]=await C(e,`/users?${new URLSearchParams({username:r})}`);if(!a)throw new f(`not-found`,`There's no GitLab account named ${r}.`);try{await S(e,`${i}/members`,{method:`POST`,body:{user_id:a.id,access_level:O(n)}})}catch(e){if(e instanceof b&&e.status===409)throw new f(`already`,`${r} already edits the site.`);k(e)}},async setRole(t,n){await S(e,t.id.startsWith(E)?`${i}/invitations/${encodeURIComponent(t.id.slice(11))}`:`${i}/members/${t.id.slice(7)}`,{method:`PUT`,body:{access_level:O(n)}}).catch(k)},async remove(t){await S(e,t.id.startsWith(E)?`${i}/invitations/${encodeURIComponent(t.id.slice(11))}`:`${i}/members/${t.id.slice(7)}`,{method:`DELETE`}).catch(k)},async letEditorsPublish(){let t=t=>S(e,`${i}/protected_branches`,{method:`POST`,body:{name:n,push_access_level:t,merge_access_level:t,allow_force_push:!1}});await S(e,a,{method:`DELETE`,allow:[404]}).catch(k);try{await t(w)}catch(e){await t(T).catch(()=>void 0),k(e)}}}}var oe=`35.185.44.232`,A=`2600:1901:0:7b8a::`;function j(e,{apex:t,www:n}){return t&&n?[e,`www.${e}`]:[e]}function M(e,t,n,r){let i=`${(e.split(`/`)[0]??``).toLowerCase()}.gitlab.io`,a=n.apex?[{type:`A`,name:t,value:oe,purpose:`site`},{type:`AAAA`,name:t,value:A,purpose:`site`,optional:!0}]:[{type:`CNAME`,name:t,value:i,purpose:`site`}],o=n.apex&&n.www?[{type:`CNAME`,name:`www.${t}`,value:i,purpose:`www`,optional:!0}]:[],s=j(t,n).flatMap(e=>{let n=r[e];if(!n)return[];let i=n.startsWith(`gitlab-pages-verification-code=`)?n:`gitlab-pages-verification-code=${n}`;return[{type:`TXT`,name:`_gitlab-pages-verification-code.${e}`,value:i,purpose:`verification`,optional:e!==t}]});return[...a,...o,...s]}function se(e,t){let n=`/projects/${encodeURIComponent(t)}/pages`,r=e=>`${n}/domains/${encodeURIComponent(e)}`;function i(e){throw e instanceof b&&(e.status===401||e.status===403)?new h(`not-allowed`,`Connecting a domain on GitLab needs the Maintainer role in the project.`):e}async function a(){let t=await S(e,n,{allow:[404]}).catch(i);return t.ok?await t.json():void 0}async function o(t){let n=await Promise.all(t.map(async t=>{let n=await S(e,r(t),{allow:[404]});return n.ok?[t,(await n.json()).verification_code??``]:[t,``]}));return Object.fromEntries(n)}async function s(t){let n=await C(e,r(t)).catch(i);if(n.verified)return n;let a=await S(e,`${r(t)}/verify`,{method:`PUT`,allow:[400,404,422]});return a.ok?await a.json():n}return{severalDomains:!0,async site(){let t=await a();if(!t)return;let r=(await C(e,`${n}/domains`).catch(()=>[])).map(e=>e.domain),i=(t.primary_domain&&r.includes(t.primary_domain)?t.primary_domain:void 0)??r.sort((e,t)=>e.length-t.length)[0];return{url:t.url,domain:i}},async connect(s,c){let l=await a();l&&l.is_unique_domain_enabled===!1&&await S(e,n,{method:`PATCH`,body:{pages_unique_domain_enabled:!0}}).catch(i);for(let t of j(s,c))try{await S(e,`${n}/domains`,{method:`POST`,body:{domain:t,auto_ssl_enabled:!0}})}catch(n){if(n instanceof b&&n.status===400){if(/taken/i.test(n.message)){if((await S(e,r(t),{allow:[404]})).ok)continue;throw new h(`taken`,`Another GitLab Pages site already uses this domain.`)}throw new h(`invalid`,`GitLab Pages doesn't accept this domain.`)}i(n)}return M(t,s,c,await o(j(s,c)))},async records(e,n){return M(t,e,n,await o(j(e,n)))},async status(t){let n=await s(t),i=await S(e,r(`www.${t}`),{allow:[404]});i.ok&&!(await i.json()).verified&&await s(`www.${t}`);let o=await a();return{verified:n.verified,certificate:n.certificate&&!n.certificate.expired?`ready`:`pending`,httpsOnly:o?.force_https===!0,primary:o?.primary_domain===void 0||o.primary_domain===t}},async secure(t,{primary:a=!0}={}){let o=await C(e,r(t)).catch(i);if(!o.verified||!o.certificate)throw new h(`not-ready`,`The domain's certificate isn't ready yet.`);if(!a){await S(e,n,{method:`PATCH`,body:{pages_https_only:!0}}).catch(i);return}try{await S(e,n,{method:`PATCH`,body:{pages_https_only:!0,pages_primary_domain:t}})}catch(t){t instanceof b&&t.status===400||i(t),await S(e,n,{method:`PATCH`,body:{pages_https_only:!0}}).catch(i)}},async disconnect(t){for(let n of[t,`www.${t}`])await S(e,r(n),{method:`DELETE`,allow:[404]}).catch(i)}}}var N=`Goodfellow: build the site for a scheduled change at `,P=`GOODFELLOW_SCHEDULED_CHANGE`;function F(e){throw e instanceof b&&(e.status===401||e.status===403)?new x(`not-allowed`,`Adding pipeline schedules on GitLab needs the Developer role, with permission to merge to the main branch.`):e}function ce(e){return`${e.getUTCMinutes()} ${e.getUTCHours()} ${e.getUTCDate()} ${e.getUTCMonth()+1} *`}function le(e){return`${e.toISOString().slice(0,16)}Z`}function ue(e,t,n,r,i=()=>new Date){let a=`/projects/${encodeURIComponent(t)}/pipeline_schedules`;return{async timing(){return await r()===void 0?`none`:`exact`},async sync(t){let r=i(),o=new Map;for(let e of[...t].filter(e=>e>r).sort((e,t)=>e.getTime()-t.getTime())){if(o.size>=50)break;o.set(le(e),e)}let s=[];for(let t=1;t<=10;t++){let n=await C(e,`${a}?per_page=100&page=${t}`).catch(F);if(s.push(...n),n.length<100)break}let c=new Map;for(let e of s)e.description?.startsWith(`Goodfellow: build the site for a scheduled change at `)&&c.set(e.description.slice(53),e);for(let[t,n]of c)o.has(t)||await S(e,`${a}/${n.id}`,{method:`DELETE`,allow:[403,404]});for(let[t,r]of o){if(c.has(t))continue;let i=await C(e,a,{method:`POST`,body:{description:`${N}${t}`,ref:n,cron:ce(r),cron_timezone:`UTC`,active:!0}}).catch(F);try{await S(e,`${a}/${i.id}/variables`,{method:`POST`,body:{key:P,value:t,variable_type:`env_var`}})}catch(t){await S(e,`${a}/${i.id}`,{method:`DELETE`,allow:[403,404]}).catch(()=>{}),F(t)}}}}}function de(e,t,n,r,a={}){let o=`/projects/${encodeURIComponent(t)}`,s=a.wait??(e=>new Promise(t=>setTimeout(t,e))),u=async()=>(await r().catch(()=>void 0)??``).includes(`$GOODFELLOW_TASK_PLUGIN`);return{supported:u,secretsPlace:async()=>({kind:`gitlab`,url:`${e.apiUrl.replace(/\/api\/v4\/?$/,``)}/${t}/-/settings/ci_cd#js-cicd-variables-settings`}),async run(t){let r=l(t);if(r)throw new d(`failed`,r);if(!await u())throw new d(`missing`,`The site's setup files don't run plugins' tasks: .gitlab-ci.yml needs the plugin-task job.`);let f=(e,t)=>({key:e,variable_type:`env_var`,value:t}),p;try{p=await C(e,`${o}/pipeline`,{method:`POST`,body:{ref:n,variables:[f(`GOODFELLOW_TASK_REQUEST`,t.id),f(`GOODFELLOW_TASK_PLUGIN`,t.plugin),f(`GOODFELLOW_TASK_NAME`,t.task),f(`GOODFELLOW_TASK_INPUT`,t.input),f(`GOODFELLOW_TASK_KEY`,t.key)]}})}catch(e){throw e instanceof b&&(e.status===403||e.status===401)?new d(`not-allowed`,`Running plugins' tasks needs a sign-in that can publish to the site.`):e}let m=Date.now()+(a.timeoutMs??3e5);for(;;){let t=(await C(e,`${o}/pipelines/${p.id}/jobs?per_page=100`)).find(e=>e.name===c);if(t?.status===`success`){let n=await S(e,`${o}/jobs/${t.id}/artifacts/${i}`,{allow:[404]});if(n.ok)return await n.text();throw new d(`failed`,`The site's build service ran the task but left no answer.`)}if(t&&[`failed`,`canceled`,`skipped`].includes(t.status))throw new d(`failed`,`The site's build service couldn't run the task.`);if(Date.now()>=m)throw new d(`timeout`,`The site's build service didn't answer in time.`);await s(a.pollMs??4e3)}}}}var I=`.gitlab-ci.yml`,L=`17 4 * * *`;function R(e){throw e instanceof b&&(e.status===401||e.status===403)?new a(`not-allowed`,`Setting up updates on GitLab needs the Maintainer role in the project.`):e}function z(e,t,n,r,i=`pages`){let s=`/projects/${encodeURIComponent(t)}`;async function c(){return C(e,`${s}/pipeline_schedules`)}async function l(){return(await c()).find(e=>(e.ref===n||e.ref===`refs/heads/${n}`)&&!e.description?.startsWith(`Goodfellow: build the site for a scheduled change at `))}return{async setup(){if(!(await r(I))?.includes(`update --publish`))return`missing`;try{let[t,r]=await Promise.all([C(e,s),c()]),i=r.some(e=>(e.ref===n||e.ref===`refs/heads/${n}`)&&(e.active||!e.description?.startsWith(`Goodfellow: build the site for a scheduled change at `)));return t.ci_push_repository_for_job_token_allowed&&i?`ready`:`needs-setup`}catch(e){if(e instanceof b&&e.status===403)return`needs-setup`;throw e}},async enable(){await S(e,s,{method:`PUT`,body:{ci_push_repository_for_job_token_allowed:!0}}).catch(R),await l().catch(R)||await S(e,`${s}/pipeline_schedules`,{method:`POST`,body:{description:`Rebuild the site and install Goodfellow's fixes each night`,ref:n,cron:L,cron_timezone:`UTC`,active:!0}}).catch(R)},async lastRun(){let t=await C(e,`${s}/pipelines?${new URLSearchParams({ref:n,per_page:`20`})}`);for(let n of t){if(n.source!==`schedule`&&n.source!==`api`)continue;let t={date:n.created_at,detailsUrl:n.web_url};if([`created`,`pending`,`running`,`waiting_for_resource`,`preparing`].includes(n.status))return{state:`running`,...t};let r=(await C(e,`${s}/pipelines/${n.id}/jobs?per_page=100`)).find(e=>e.name===i||e.name===`update`);if(!r)continue;let a=await S(e,`${s}/jobs/${r.id}/trace`,{allow:[403,404]}),o=a.ok?m(await a.text()):void 0;if(o)return{state:o.state,result:o,...t}}},async start(t){await S(e,`${s}/pipeline`,{method:`POST`,body:{ref:n,variables:[{key:`GOODFELLOW_UPDATE`,variable_type:`env_var`,value:t}]}}).catch(R)},nightly:{async supported(){return(await r(I))?.includes(`nightly`)??!1},async get(){try{let t=await l();return t?t.active?(await C(e,`${s}/pipeline_schedules/${t.id}`)).variables?.find(e=>e.key===`GOODFELLOW_NIGHTLY`)?.value===`always`?`always`:`changed`:`off`:void 0}catch(e){if(e instanceof b&&e.status===403)return;throw e}},async set(t){let n=await l().catch(R);if(!n)throw new a(`missing`,`The site has no nightly schedule yet: turn on updates first.`);let r=`${s}/pipeline_schedules/${n.id}`;if(await S(e,r,{method:`PUT`,body:{active:t!==`off`}}).catch(R),t===`always`){let t={key:o,value:`always`};(await S(e,`${r}/variables/GOODFELLOW_NIGHTLY`,{method:`PUT`,body:t,allow:[404]}).catch(R)).status===404&&await S(e,`${r}/variables`,{method:`POST`,body:t}).catch(R)}else t===`changed`&&await S(e,`${r}/variables/${o}`,{method:`DELETE`,allow:[404]}).catch(R)}},async rebuild(){await S(e,`${s}/pipeline`,{method:`POST`,body:{ref:n,variables:[{key:`GOODFELLOW_REBUILD`,variable_type:`env_var`,value:`true`}]}}).catch(R)}}}function B(e){return e instanceof b&&(e.status===403||e.status===404)}function V(e){let{api:t,project:n}=e,r,i=()=>(r??=C(t,`/projects/${encodeURIComponent(n)}`).then(e=>e.default_branch),r.catch(()=>{r=void 0}),r),a=async()=>e.open(await i()),o=async e=>{let t=await a();return t.readAt(e,await t.revision())},s=async()=>z(t,n,await i(),o,`update`);return{code:{repo:n,webUrl:`${e.webUrl}/${n}`,read:o,history:async(e,t)=>(await a()).history(e,t),readAt:async(e,t)=>(await a()).readAt(e,t)},async setup(){try{return await(await s()).setup()}catch(e){if(B(e))return`no-access`;throw e}},async enable(){await(await s()).enable?.()},async lastRun(){try{return await(await s()).lastRun()}catch(e){if(B(e))return;throw e}},async start(e){await(await s()).start(e)},async rebuild(){await(await s()).rebuild?.()}}}var H=100,fe=1e3,pe=10,U=50,me=RegExp(`\x1B\\[[\\d;]*[A-Za-z]`,`g`);async function he(e){let t=new TextEncoder().encode(`blob ${e.length}\0`),n=new Uint8Array(t.length+e.length);return n.set(t),n.set(e,t.length),[...new Uint8Array(await crypto.subtle.digest(`SHA-1`,n))].map(e=>e.toString(16).padStart(2,`0`)).join(``)}function W(e){return e.name!==`rebuild`&&e.name!==`update`&&e.name!==`lockfile`}function G(e,t){let n=`${t}/`;return[...e.keys()].filter(e=>e.startsWith(n)).sort()}var K=class i{user;pages;editors;updates;drafts;scheduledBuilds;tasks;contentOnly;options;api;project;branch;onSignOut;pinned;caches;trees;blobs;constructor(e){if(this.options=e,this.api=e.api,this.project=encodeURIComponent(e.project),this.branch=e.branch,this.user=e.user,this.onSignOut=e.onSignOut,this.pinned=e.revision,this.caches=e.caches??{trees:new Map,blobs:new Map},this.trees=this.caches.trees,this.blobs=this.caches.blobs,this.pages=se(this.api,e.project),this.editors=ae(this.api,e.project,this.branch,this.user.login),this.contentOnly=e.contentOnly===!0,!this.contentOnly)this.updates=z(this.api,e.project,this.branch,async e=>this.readAt(e,this.pinned??await this.revision()));else if(e.code){let t=e.code;this.updates=V({api:this.api,project:t.project,webUrl:t.webUrl,open:e=>new i({api:this.api,project:t.project,branch:e,user:this.user,onSignOut:()=>{}})})}this.drafts=r(this,this.draftHost()),this.scheduledBuilds=ue(this.api,e.project,this.branch,async()=>this.readAt(`.gitlab-ci.yml`,this.pinned??await this.revision())),this.tasks=de(this.api,e.project,this.branch,async()=>this.readAt(`.gitlab-ci.yml`,this.pinned??await this.revision()),e.tasks)}async repositoryVisibility(){let{visibility:e}=await C(this.api,`/projects/${this.project}`);return e===`public`||e===`internal`?e:`private`}draftHost(){let e=`/projects/${this.project}`,t=t=>C(this.api,`${e}/merge_requests?${new URLSearchParams({source_branch:t,state:`opened`})}`),n=async(t,n)=>{let r=[];for(let e of n){let[t]=await C(this.api,`/users?${new URLSearchParams({username:e})}`).catch(()=>[]);t&&r.push(t.id)}for(let n of r.length>1?[r,r.slice(0,1)]:[r])if(n.length===0||(await S(this.api,`${e}/merge_requests/${t}`,{method:`PUT`,body:{reviewer_ids:n},allow:[400,403,404,422]})).ok)return};return{liveBranch:this.branch,branchStore:e=>new i({...this.options,branch:e,caches:this.caches}),createBranch:async(e,t)=>{if((await S(this.api,this.repo(`/branches?${new URLSearchParams({branch:e,ref:t})}`),{method:`POST`,allow:[400]})).status===400)throw new s(`exists`,`There's already a draft called ${e}.`)},deleteBranch:async e=>{await S(this.api,this.repo(`/branches/${encodeURIComponent(e)}`),{method:`DELETE`,allow:[404]})},mergeBase:async e=>{let t=new URLSearchParams;t.append(`refs[]`,this.branch),t.append(`refs[]`,e);let n=await S(this.api,this.repo(`/merge_base?${t}`),{allow:[400,404]});if(!n.ok)throw new s(`not-found`,`There's no draft ${e}.`);return(await n.json()).id},listBranches:async e=>{let t=new URLSearchParams({search:`^${e}`});return(await this.everyPage(this.repo(`/branches?${t}`))).map(e=>e.name).filter(t=>t.startsWith(e))},openReview:async({branch:r,title:i,description:a,reviewers:o=[]})=>{let c=await S(this.api,`${e}/merge_requests`,{method:`POST`,body:{source_branch:r,target_branch:this.branch,title:i,description:a,remove_source_branch:!0},allow:[403,404,409]}),l;if(c.ok)l=await c.json();else if(c.status!==409)throw new s(`no-reviews`,`This sign-in can't open merge requests on the site's project.`);else if([l]=await t(r),!l)throw new b(409,`GitLab couldn't open the merge request.`);return await n(l.iid,o),{url:l.web_url}},listReviews:async t=>(await this.everyPage(`${e}/merge_requests?state=opened`)).filter(e=>e.source_branch.startsWith(t)).map(e=>({branch:e.source_branch,url:e.web_url,title:e.title})),closeReview:async n=>{for(let r of await t(n))await S(this.api,`${e}/merge_requests/${r.iid}`,{method:`PUT`,body:{state_event:`close`},allow:[403,404]})}}}repo(e){return`/projects/${this.project}/repository${e}`}async revision(){return this.pinned=await this.head(),this.pinned}async head(){return(await C(this.api,this.repo(`/branches/${encodeURIComponent(this.branch)}`))).commit.id}async everyPage(e){let t=[];for(let n=1;n<=pe;n++){let r=await C(this.api,`${e}&per_page=${H}&page=${n}`);if(t.push(...r),r.length<H)break}return t}async listFolder(e,t){let n=[];for(let r=1;;r++){let i=new URLSearchParams({ref:e,path:t,recursive:`true`,per_page:String(H),page:String(r)}),a=await S(this.api,this.repo(`/tree?${i}`),{allow:[404]});if(a.status===404)return n;let o=await a.json();for(let e of o)e.type===`blob`&&n.push([e.path,e.id]);if(o.length<H)return n}}tree(t){let n=this.trees.get(t);return n||(n=Promise.all(e.map(e=>this.listFolder(t,e))).then(e=>new Map(e.flat())),n.catch(()=>this.trees.delete(t)),this.trees.set(t,n)),n}async currentTree(){return this.tree(this.pinned??await this.revision())}async read(e){return this.readFrom(await this.currentTree(),e)}readFrom(e,t){let n=e.get(t);if(!n)return Promise.resolve(void 0);let r=this.blobs.get(n);return r||(r=S(this.api,this.repo(`/blobs/${n}/raw`)).then(e=>e.text()),r.catch(()=>this.blobs.delete(n)),this.blobs.set(n,r)),r}async readFiles(e){let t=this.pinned??await this.revision();return this.readFilesFrom(t,await this.tree(t),e)}async readFilesFrom(e,t,n){let r=n.filter(e=>t.has(e)),i=r.filter(e=>!this.blobs.has(t.get(e)??``));for(let n=0;n<i.length;n+=U){let r=i.slice(n,n+U),a=await C(this.api,`/../graphql`,{method:`POST`,body:{query:`query ($project: ID!, $ref: String!, $paths: [String!]!) {
|
|
2
|
-
project(fullPath: $project) { repository { blobs(ref: $ref, paths: $paths) { nodes { path rawTextBlob } } } }
|
|
3
|
-
}`,variables:{project:decodeURIComponent(this.project),ref:e,paths:r}}});for(let e of a.data?.project?.repository?.blobs?.nodes??[]){let n=t.get(e.path);n&&typeof e.rawTextBlob==`string`&&this.blobs.set(n,Promise.resolve(e.rawTextBlob))}}let a=new Map;for(let e of r){let n=await this.readFrom(t,e);n!==void 0&&a.set(e,n)}return a}async readBytes(e){return this.bytesFrom(await this.currentTree(),e)}async bytesFrom(e,t){let n=e.get(t);if(!n)return;let r=await S(this.api,this.repo(`/blobs/${n}/raw`));return new Uint8Array(await r.arrayBuffer())}async list(e){return G(await this.currentTree(),e)}filesAt(e){return{read:async t=>this.readFrom(await this.tree(e),t),readFiles:async t=>this.readFilesFrom(e,await this.tree(e),t),readBytes:async t=>this.bytesFrom(await this.tree(e),t),list:async t=>G(await this.tree(e),t)}}async fileSizes(e){let t=await this.list(e),n=this.pinned??await this.revision(),r=new Map;for(let e=0;e<t.length;e+=U){let i=await C(this.api,`/../graphql`,{method:`POST`,body:{query:`query ($project: ID!, $ref: String!, $paths: [String!]!) {
|
|
4
|
-
project(fullPath: $project) { repository { blobs(ref: $ref, paths: $paths) { nodes { path size } } } }
|
|
5
|
-
}`,variables:{project:decodeURIComponent(this.project),ref:n,paths:t.slice(e,e+U)}}});for(let e of i.data?.project?.repository?.blobs?.nodes??[]){let t=Number(e.size);Number.isFinite(t)&&r.set(e.path,t)}}return r}async lastCommitFor(e,t){return(await C(this.api,this.repo(`/files/${encodeURIComponent(e)}?ref=${t}`))).last_commit_id}async existsAt(t,n,r){return e.some(e=>n.startsWith(`${e}/`))?t.has(n):this.lastCommitFor(n,r).then(()=>!0,e=>{if(e instanceof b&&e.status===404)return!1;throw e})}async write(e,{message:r,expectedRevision:i}){if(this.contentOnly&&t(e),await this.revision()!==i)throw new n;let a=await this.tree(i),o=(await Promise.all(e.map(async e=>{let t=await this.existsAt(a,e.path,i);if(`delete`in e)return t?{action:`delete`,file_path:e.path,last_commit_id:await this.lastCommitFor(e.path,i)}:void 0;let n=`bytes`in e?{content:_(e.bytes),encoding:`base64`}:{content:e.content};return t?{action:`update`,file_path:e.path,...n,last_commit_id:await this.lastCommitFor(e.path,i)}:{action:`create`,file_path:e.path,...n}}))).filter(e=>e!==void 0);if(o.length===0)return{revision:i};try{let t=await C(this.api,this.repo(`/commits`),{method:`POST`,body:{branch:this.branch,commit_message:r,actions:o,...this.options.author&&{author_name:this.options.author.name,author_email:this.options.author.email}}});return this.pinned=t.id,t.parent_ids?.length===1&&t.parent_ids[0]===i&&await this.carryTree(a,t.id,e).catch(()=>{}),{revision:t.id}}catch(e){throw e instanceof b?e.status===403?new g(`cant-publish`,`This GitLab account can't publish to the site.`):e.status===400&&/already exists|changed since/i.test(e.message)||await this.revision()!==i?new n:e:e}}async carryTree(t,n,r){if(this.trees.has(n)||!globalThis.crypto?.subtle)return;let i=new Map(t);for(let t of r){if(!e.some(e=>t.path.startsWith(`${e}/`)))continue;if(`delete`in t){i.delete(t.path);continue}let n=await he(`bytes`in t?t.bytes:new TextEncoder().encode(t.content));i.set(t.path,n),`content`in t&&!this.blobs.has(n)&&this.blobs.set(n,Promise.resolve(t.content))}this.trees.set(n,Promise.resolve(i))}async history(e,{page:t=1,perPage:n=20}={}){let r=new URLSearchParams({ref_name:this.pinned??await this.revision(),path:e,per_page:String(n),page:String(t)});return(await C(this.api,this.repo(`/commits?${r}`))).map(e=>({revision:e.id,date:e.authored_date??e.committed_date??``,author:e.author_name||void 0,message:e.title}))}async readAt(e,t){let n=await S(this.api,this.repo(`/files/${encodeURIComponent(e)}/raw?${new URLSearchParams({ref:t})}`),{allow:[404]});return n.ok?n.text():void 0}async changedPaths(e,t){let n=(await C(this.api,this.repo(`/compare?${new URLSearchParams({from:e,to:t,straight:`true`})}`))).diffs??[];if(n.length>=fe)throw new b(0,`More files changed between ${e} and ${t} than GitLab lists.`);return[...new Set(n.flatMap(e=>[e.old_path,e.new_path]))]}async deployStatus(e){try{let t=await this.statuses(e),n=t.filter(W);if(t.length>0&&n.length===0)return{state:`unknown`};if(n.length===0){if((await C(this.api,`/projects/${this.project}/pipelines?per_page=1`)).length>0)return{state:`building`};let{parent_ids:t=[]}=await C(this.api,this.repo(`/commits/${e}`));return{state:(t[0]?(await this.statuses(t[0])).filter(W):[]).length>0?`building`:`unknown`}}let r=n.find(e=>e.status===`failed`)??n.find(e=>e.status===`canceled`);if(r?.status===`canceled`){let t=await this.head();if(t!==e)return this.deployStatus(t)}if(r){let t=await this.jobProblem(e).catch(()=>void 0);return{state:`failed`,detailsUrl:r.target_url??void 0,...t&&{problem:t}}}return n.every(e=>e.status===`success`||e.status===`skipped`)?{state:`live`,detailsUrl:n[0]?.target_url??void 0}:{state:`building`,detailsUrl:n[0]?.target_url??void 0}}catch(e){if(e instanceof b)return{state:`unknown`};throw e}}statuses(e){return C(this.api,this.repo(`/commits/${e}/statuses`))}async jobProblem(e){let[t]=await C(this.api,`/projects/${this.project}/pipelines?${new URLSearchParams({sha:e,per_page:`1`})}`);if(!t)return;let n=(await C(this.api,`/projects/${this.project}/pipelines/${t.id}/jobs?per_page=100`)).find(e=>e.status===`failed`);if(!n)return;let r=n.failure_reason??``,i=`${n.name}: ${r}`;if(r===`ci_quota_exceeded`)return{step:`not-started`,detail:i};if(/runner_system|stuck_or_timeout|scheduler|api_failure|data_integrity|job_execution_timeout/.test(r))return{step:`host`,detail:i};if(n.name===`pages:deploy`)return{step:`deploy`,detail:i};let a=await S(this.api,`/projects/${this.project}/jobs/${n.id}/trace`,{allow:[403,404]}),o=a.ok?await a.text():``,s=te(o),c=o.split(`
|
|
6
|
-
`).map(e=>e.replace(me,``).replace(/^.*\r/,``)).filter(e=>e.startsWith(`$ `)).at(-1);return{step:s?`build`:(c?ee(c):void 0)??`build`,detail:i,...s&&{cause:s}}}signOut(){this.onSignOut()}};function q(e){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}function J(e=32){return q(crypto.getRandomValues(new Uint8Array(e)))}async function Y(e){let t=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(e));return q(new Uint8Array(t))}function X(e,t,n=Date.now()){return{type:`oauth`,access:e.access_token,refresh:e.refresh_token,expiresAt:n+(e.expires_in??7200)*1e3,verifier:t}}function Z(e){let t=new URL(e);return`${t.origin}${t.pathname.replace(/\/?$/,`/`)}`}var Q=`main`;function ge(){return{href:()=>window.location.href,assign:e=>window.location.assign(e),replace:e=>window.history.replaceState(window.history.state,``,e)}}function $(e={}){let t=(e.url??`https://gitlab.com`).replace(/\/$/,``),n=`${t}/api/v4`,r=e.fetch??((e,t)=>globalThis.fetch(e,t)),i=v(`goodfellow:gitlab-setup:pending`,e.storage),a=()=>e.location??ge();async function o(e){let n=await r(`${t}/oauth/token`,{method:`POST`,headers:{"content-type":`application/x-www-form-urlencoded`},body:new URLSearchParams(e)});if(!n.ok)throw new g(`invalid`,`GitLab didn't accept the sign-in (${n.status}).`);return await n.json()}async function s(t){let i=t,s={apiUrl:n,token:async({refresh:t}={})=>{if(i.type===`token`)return i.token;if(t||i.expiresAt-6e4<Date.now()){let{verifier:t}=i;i=X(await o({client_id:e.clientId??``,refresh_token:i.refresh,grant_type:`refresh_token`,redirect_uri:Z(a().href()),code_verifier:t}),t)}return i.access},canRefresh:i.type===`oauth`,fetch:r},c=await C(s,`/user`);async function l(e,t){return(await S(s,`/projects/${encodeURIComponent(`${e.path}/${t}`)}`,{allow:[404]})).status===404}async function u(e){let t=e=>`/projects/${encodeURIComponent(e)}`;try{let n=new Map;for(let r of[`code`,`content`])n.set(r,(await C(s,t(e[r]))).id);for(let{reader:r,read:i}of e.links.reads)await S(s,`${t(e[i])}/job_token_scope/allowlist`,{method:`POST`,body:{target_project_id:n.get(r)}});e.links.updates&&await S(s,t(e[e.links.updates]),{method:`PUT`,body:{ci_push_repository_for_job_token_allowed:!0}});for(let n of e.links.nightly)await S(s,`${t(e[n])}/pipeline_schedules`,{method:`POST`,body:{description:n===e.links.updates?`Rebuild the site and install Goodfellow's fixes each night`:`Rebuild the site each night`,ref:Q,cron:L,cron_timezone:`UTC`,active:!0}});return!0}catch(e){if(e instanceof b&&[400,403,404].includes(e.status))return!1;throw e}}return{user:{login:c.username,name:c.name,avatarUrl:c.avatar_url},async owners(){let e=(await C(s,`/namespaces?per_page=100`)).map(e=>({path:e.full_path,name:e.kind===`user`?c.name??e.name:e.name,kind:e.kind===`user`?`personal`:`organization`,id:e.id}));return[...e.filter(e=>e.kind===`personal`),...e.filter(e=>e.kind!==`personal`)]},isAvailable:l,async createSite(e,t){if(t?.(`repository`),!await l(e.owner,e.name))throw new p(`name-taken`,`There's already a project called ${e.owner.path}/${e.name}.`);let n;try{n=await C(s,`/projects`,{method:`POST`,body:{name:e.name,path:e.name,namespace_id:e.owner.id,visibility:e.private?`private`:`public`,description:e.description,...e.pages&&{pages_access_level:e.private?`public`:`enabled`}}})}catch(t){throw t instanceof b&&t.status===400?new p(`name-invalid`,`GitLab can't use "${e.name}" as a project name.`):t instanceof b&&(t.status===403||t.status===404)?new p(`not-allowed`,`This sign-in can't create projects in ${e.owner.path}.`):t}let r=[];e.link&&(t?.(`connect`),await u(e.link)||r.push(`connect-unavailable`));let i;if(e.pages&&e.domain){t?.(`pages`);try{await S(s,`/projects/${n.id}/pages/domains`,{method:`POST`,body:{domain:e.domain,auto_ssl_enabled:!0}}),i=`https://${e.domain}/`}catch(e){if(!(e instanceof b)||![400,403,404,409,422].includes(e.status))throw e;r.push(`domain-unavailable`)}}return t?.(`files`),await S(s,`/projects/${n.id}/repository/commits`,{method:`POST`,body:{branch:Q,commit_message:e.message,actions:e.files.flatMap(e=>`delete`in e?[]:`content`in e?[{action:`create`,file_path:e.path,content:e.content}]:[{action:`create`,file_path:e.path,content:_(e.bytes),encoding:`base64`}])}}),{repo:n.path_with_namespace,webUrl:n.web_url,...i&&{siteUrl:i},buildsUrl:`${n.web_url}/-/pipelines`,pagesUrl:e.pages?`${n.web_url}/pages`:void 0,warnings:r}}}}return{name:`GitLab`,canRedirect:!!e.clientId,tokenLinks:[{url:`${t}/-/user_settings/personal_access_tokens?${new URLSearchParams({name:`Goodfellow site setup`,scopes:`api`})}`,label:`signIn.token.create`}],async restore(){let t=new URL(a().href()),n=t.searchParams.get(`code`),r=t.searchParams.get(`error`);if(!n&&!r)return null;let c=i.load();if(!c)return null;i.clear();let l=JSON.parse(c),u=t.searchParams.get(`state`);for(let e of[`code`,`state`,`error`,`error_description`])t.searchParams.delete(e);if(a().replace(t.toString()),r||!n||u!==l.state)throw new g(`redirect-failed`,`Signing in with GitLab was cancelled or didn't finish.`);return s(X(await o({client_id:e.clientId??``,code:n,grant_type:`authorization_code`,redirect_uri:Z(t.toString()),code_verifier:l.verifier}),l.verifier))},async signInWithToken(e){let t=e.trim();if(!t)throw new g(`invalid`,`Paste a token to sign in.`);return s({type:`token`,token:t})},async startRedirect(){if(!e.clientId)throw Error(`gitlabSetup({ clientId }) is needed to sign in with GitLab.`);let n={state:J(16),verifier:J(48)};i.save(JSON.stringify(n),!1);let r=new URLSearchParams({client_id:e.clientId,redirect_uri:Z(a().href()),response_type:`code`,state:n.state,scope:`api`,code_challenge:await Y(n.verifier),code_challenge_method:`S256`});a().assign(`${t}/oauth/authorize?${r}`)}}}var _e=30;function ve(){return{href:()=>window.location.href,assign:e=>window.location.assign(e),replace:e=>window.history.replaceState(window.history.state,``,e)}}function ye(e){let t=(e.url??`https://gitlab.com`).replace(/\/$/,``),n=`${t}/api/v4`,r=u(e.fetch??((e,t)=>globalThis.fetch(e,t)),{host:`GitLab`}),i=v(`goodfellow:gitlab:${t}:${e.project}`,e.storage),a=v(`goodfellow:gitlab:pending:${e.project}`,e.storage),o=()=>e.location??ve();async function s(e){let n=await r(`${t}/oauth/token`,{method:`POST`,headers:{"content-type":`application/x-www-form-urlencoded`},body:new URLSearchParams(e)});if(!n.ok)throw new g(`invalid`,`GitLab didn't accept the sign-in (${n.status}).`);return await n.json()}async function c(a,c){let l=a,u,d=t=>u??=(async()=>(l=X(await s({client_id:e.clientId??``,refresh_token:t.refresh,grant_type:`refresh_token`,redirect_uri:Z(o().href()),code_verifier:t.verifier}),t.verifier),i.save(JSON.stringify(l),c),l.access))().finally(()=>{u=void 0}),f={apiUrl:n,token:async({refresh:e,stale:t}={})=>l.type===`token`?l.token:u||(e&&t!==void 0&&t!==l.access?l.access:e||l.expiresAt-6e4<Date.now()?d(l):l.access),canRefresh:l.type===`oauth`,fetch:r},p=await C(f,`/user`),m;try{m=await C(f,`/projects/${encodeURIComponent(e.project)}`)}catch(t){throw t instanceof b&&(t.status===404||t.status===403)?new g(`no-access`,`The GitLab account ${p.username} can't see ${e.project}.`):t}if(Math.max(m.permissions?.project_access?.access_level??0,m.permissions?.group_access?.access_level??0)<_e)throw new g(`cant-publish`,`The GitLab account ${p.username} can see ${e.project} but can't publish to it.`);return i.save(JSON.stringify(l),c),new K({api:f,project:e.project,branch:e.branch??m.default_branch,...e.contentOnly&&{contentOnly:!0},...e.contentOnly&&e.code&&{code:{project:e.code,webUrl:t}},user:{login:p.username,name:p.name,avatarUrl:p.avatar_url},onSignOut:()=>i.clear()})}async function l(){let t=new URL(o().href()),n=t.searchParams.get(`code`),r=t.searchParams.get(`state`),i=t.searchParams.get(`error`);if(!n&&!i)return null;for(let e of[`code`,`state`,`error`,`error_description`])t.searchParams.delete(e);let l=a.load();if(l&&(t.hash=JSON.parse(l).hash),o().replace(t.toString()),!l)return null;a.clear();let u=JSON.parse(l);if(i||!n||r!==u.state)throw new g(`redirect-failed`,`Signing in with GitLab was cancelled or didn't finish.`);return c(X(await s({client_id:e.clientId??``,code:n,grant_type:`authorization_code`,redirect_uri:Z(t.toString()),code_verifier:u.verifier}),u.verifier),u.remember)}function d({token:t}){let i={apiUrl:n,token:async()=>typeof t==`string`?t:t(),canRefresh:!1,fetch:r},a,o=()=>(a??=e.branch?Promise.resolve(e.branch):C(i,`/projects/${encodeURIComponent(e.project)}`).then(e=>e.default_branch),a.catch(()=>{a=void 0}),a),s=async(t,n)=>new K({api:i,project:e.project,branch:await o(),...e.contentOnly&&{contentOnly:!0},user:{login:n?.name??e.project,...n&&{name:n.name}},onSignOut:()=>{},...t&&{revision:t},...n&&{author:n}});return{...e.contentOnly&&{contentOnly:!0},async revision(){return(await s()).revision()},at:s}}return{name:`GitLab`,source:y(`@goodfellow-cms/gitlab`,`gitlab`,e,[`fetch`,`storage`,`location`]),canRedirect:!!e.clientId,setup:()=>$({...e.url&&{url:e.url},...e.fetch&&{fetch:e.fetch},...e.storage&&{storage:e.storage},...e.location&&{location:e.location}}),redirectAddressesListed:!!e.clientId,tokenLinks:[{url:`${t}/-/user_settings/personal_access_tokens?${new URLSearchParams({name:`Goodfellow admin`,scopes:`api`})}`,label:`signIn.token.create`}],async restore(){let e=await l();if(e)return e;let t=i.load();if(!t)return null;try{return await c(JSON.parse(t),i.remembered())}catch(e){throw e instanceof g&&i.clear(),e}},async signInWithToken(e,t){let n=e.trim();if(!n)throw new g(`invalid`,`Paste a token to sign in.`);return c({type:`token`,token:n},t)},async startRedirect(n){if(!e.clientId)throw Error(`gitlab({ clientId }) is needed to sign in with GitLab.`);let r=J(48),i=J(16),s=new URL(o().href()),c={state:i,verifier:r,remember:n,hash:s.hash};a.save(JSON.stringify(c),!1);let l=new URLSearchParams({client_id:e.clientId,redirect_uri:Z(s.toString()),response_type:`code`,state:i,scope:`api`,code_challenge:await Y(r),code_challenge_method:`S256`});o().assign(`${t}/oauth/authorize?${l}`)},server:d}}export{K as GitLabBackend,ye as gitlab,M as gitlabPagesRecords,$ as gitlabSetup,Z as redirectUri};
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./deploy-keys-DAj2oX-N-DRd_HmOG.js","./git-eGyMXUIu.js"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{r as e,t}from"./store-BJ3bMnko.js";import{a as n,i as r,t as i}from"./preload-helper-9CpHFPb-.js";import{_ as a,a as o,b as s,c,d as l,g as u,h as d,i as f,m as p,n as m,o as h,p as g,r as _,s as v,t as y,y as b}from"./setup-host-BAQmd0y1.js";import{i as x,n as S,t as C}from"./content-repository-setup-0zqQHkZ9.js";import{a as ee,i as w,n as T,o as E,r as D,s as te,t as O}from"./git-eGyMXUIu.js";async function k({apiUrl:e,token:t,fetch:n},r,i={}){let a=async a=>n(`${e}${r}`,{method:i.method??`GET`,headers:{accept:i.accept??`application/vnd.github+json`,authorization:`Bearer ${typeof t==`string`?t:await t({refresh:a})}`,"x-github-api-version":`2022-11-28`,...i.body!==void 0&&{"content-type":`application/json`}},body:i.body===void 0?void 0:JSON.stringify(i.body),cache:`no-store`}),o=await a(!1);if(o.status===401&&typeof t!=`string`&&(o=await a(!0)),o.status===401)throw new T(`invalid`,`GitHub didn't accept the sign-in. It may have expired.`);if(!o.ok&&!i.allow?.includes(o.status)){let e=await o.json().catch(()=>({}));throw new O(o.status,`GitHub answered ${o.status}: ${e.message??o.statusText}`)}return o}async function A(e,t,n){return await(await k(e,t,n)).json()}function j(e){return e.split(`/`).map(e=>encodeURIComponent(e)).join(`/`)}var ne=20,re=50,ie=50,ae={spam:`SPAM`,abuse:`ABUSE`,"off-topic":`OFF_TOPIC`},oe=`announcements`,se=`id url bodyText createdAt isMinimized minimizedReason author { login url avatarUrl }`,ce=`query ($owner: String!, $name: String!, $category: ID!, $after: String) {
|
|
3
|
-
repository(owner: $owner, name: $name) {
|
|
4
|
-
discussions(first: ${ne}, after: $after, categoryId: $category, orderBy: { field: UPDATED_AT, direction: DESC }) {
|
|
5
|
-
pageInfo { hasNextPage endCursor }
|
|
6
|
-
nodes {
|
|
7
|
-
id title url locked updatedAt
|
|
8
|
-
comments(first: ${re}) {
|
|
9
|
-
nodes { ${se} replies(first: ${ie}) { nodes { ${se} } } }
|
|
10
|
-
}
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
}
|
|
14
|
-
}`,le=`query ($owner: String!, $name: String!) {
|
|
15
|
-
repository(owner: $owner, name: $name) {
|
|
16
|
-
discussionCategories(first: 25) { nodes { id name slug } }
|
|
17
|
-
}
|
|
18
|
-
}`;function M(e){return{id:e.id,author:{login:e.author?.login??`ghost`,url:e.author?.url??`https://github.com/ghost`,...e.author?.avatarUrl&&{avatarUrl:e.author.avatarUrl}},text:e.bodyText,createdAt:e.createdAt,url:e.url,hidden:e.isMinimized,...e.isMinimized&&e.minimizedReason&&{hiddenReason:e.minimizedReason.toLowerCase()},replies:(e.replies?.nodes??[]).map(M)}}function ue(e){return`${n}/installations/new/permissions?target_id=${e}`}function N(e){return e instanceof T||e instanceof O&&[403,404].includes(e.status)}function P(e,t){return{url:`${e}/settings/tokens/new?${new URLSearchParams({scopes:`public_repo`,description:`Goodfellow comments for ${t}`})}`,label:`comments.token.create`}}function de(e,t,n){let i,a=()=>i??e;async function o(e,t){let n=await A(a(),`/graphql`,{method:`POST`,body:{query:e,variables:t}}).catch(e=>{throw N(e)?new r(`no-access`,`GitHub refused the sign-in for comments.`):e}),i=n.errors?.[0];if(i)throw i.type===`FORBIDDEN`||i.type===`NOT_FOUND`||/not have permission|resource not accessible/i.test(i.message)?new r(`no-access`,i.message):Error(i.message);return n.data}async function s(e){let[t=``,n=``]=e.full_name.split(`/`),i=[];for(let e=0;e<3&&(i=(await o(le,{owner:t,name:n})).repository?.discussionCategories.nodes??[],!(i.length>0));e++)await new Promise(t=>setTimeout(t,500*(e+1)));let a=i.find(e=>e.slug===oe)??i[0];if(!a)throw new r(`no-category`,`The repository's Discussions have no categories yet.`,`${e.html_url}/discussions`);return{repo:e.full_name,repoId:e.node_id,category:a.name,categoryId:a.id,webUrl:e.html_url,installUrl:ue(e.owner.id)}}async function c(e){if(e.has_discussions)return e;if(e.permissions?.admin===!1)throw new r(`no-discussions`,`Discussions are off.`,`${e.html_url}/settings`);return A(a(),`/repos/${j(e.full_name)}`,{method:`PATCH`,body:{has_discussions:!0}}).catch(t=>{throw N(t)?new r(`no-discussions`,`Discussions are off.`,`${e.html_url}/settings`):t})}async function l(e,t){await o(`mutation ($input: ${e}Input!) { ${e[0]?.toLowerCase()}${e.slice(1)}(input: $input) { clientMutationId } }`,{input:t})}return{access:{tokenLink:n,get active(){return i!==void 0},async applyToken(t){let n={...e,token:t.trim()};try{await A(n,`/user`)}catch(e){throw N(e)?new r(`no-access`,`GitHub didn't accept this token.`):e}i=n},forget(){i=void 0}},async create(e,n){let i=e.trim();if(!/^[\w.-]+$/.test(i)||/^\.+$/.test(i))throw new r(`name-invalid`,`That can't be a repository's name.`);let o=await A(a(),`/user`).catch(e=>{throw N(e)?new r(`no-access`,`GitHub refused the sign-in for comments.`):e}),l=t.split(`/`)[0]??``,u=l.toLowerCase()===o.login.toLowerCase()?`/user/repos`:`/orgs/${encodeURIComponent(l)}/repos`;return s(await c(await A(a(),u,{method:`POST`,body:{name:i,description:n,private:!1,has_discussions:!0,has_issues:!1,has_projects:!1,has_wiki:!1,auto_init:!0}}).catch(e=>{throw e instanceof O&&e.status===422?new r(`name-taken`,`There's already a repository with that name.`):N(e)?new r(`no-access`,`This sign-in can't create repositories there.`):e})))},async find(e){let t=e.trim().replace(/^https:\/\/github\.com\//i,``).replace(/\/+$/,``);if(!/^[\w.-]+\/[\w.-]+$/.test(t))throw new r(`not-found`,`That isn't a repository's name.`);let n=await A(a(),`/repos/${j(t)}`).catch(e=>{throw N(e)?new r(`not-found`,`GitHub has no such repository for this sign-in.`):e});if(n.private)throw new r(`not-public`,`The repository is private.`,`${n.html_url}/settings`);return s(await c(n))},async threads(e,t){let[n=``,i=``]=e.repo.split(`/`),a=await o(ce,{owner:n,name:i,category:e.categoryId,after:t??null});if(!a.repository)throw new r(`not-found`,`GitHub has no such repository for this sign-in.`);let{pageInfo:s,nodes:c}=a.repository.discussions;return{threads:c.map(e=>({id:e.id,title:e.title,url:e.url,locked:e.locked,updatedAt:e.updatedAt,comments:e.comments.nodes.map(M)})),...s.hasNextPage&&s.endCursor&&{next:s.endCursor}}},async hide(e,t){await l(`MinimizeComment`,{subjectId:e,classifier:ae[t]})},async show(e){await l(`UnminimizeComment`,{subjectId:e})},async remove(e){await l(`DeleteDiscussionComment`,{id:e})},async lock(e){await l(`LockLockable`,{lockableId:e})},async unlock(e){await l(`UnlockLockable`,{lockableId:e})}}}var fe=/^[a-z\d](?:[a-z\d]|-(?=[a-z\d])){0,38}$/i,F=`invitation:`;function pe(e){return e?.admin?`owner`:e?.maintain||e?.push?`editor`:`viewer`}function me(e){return e===`admin`?`owner`:e===`write`||e===`maintain`?`editor`:`viewer`}function I(e){return e instanceof O&&(e.status===403||e.status===404)}function he(e,t,n,r){let i=`/repos/${n}`;function a(){let e=t();if(!e)throw new _(`not-allowed`,`Changing editors on GitHub needs an owner token.`);return e}async function o(e){try{await e(a())}catch(e){throw I(e)?new _(`not-allowed`,`This token can't change the site's editors.`):e}}async function s(e,t){let n=[];for(let r=1;r<=10;r++){let a=await A(e,`${i}/${t}?per_page=100&page=${r}`);if(n.push(...a),a.length<100)break}return n}function c(e){return s(e,`collaborators`)}return{invitesByEmail:!1,async list(){let n=t()??e,i=await c(n),a;try{a=await s(n,`invitations`)}catch(e){if(!I(e))throw e}let o=[...i.map(e=>({id:e.login,login:e.login,avatarUrl:e.avatar_url,role:pe(e.permissions),...e.login.toLowerCase()===r.toLowerCase()&&{self:!0}})),...(a??[]).flatMap(e=>e.invitee?[{id:`${F}${e.id}`,login:e.invitee.login,avatarUrl:e.invitee.avatar_url,role:me(e.permissions),invited:!0}]:[])],l=o.some(e=>e.self&&e.role===`owner`);return{editors:o,manage:a?`yes`:l?`token`:`no`,editorsCanPublish:!0}},async invite(e,t){let n=e.trim().replace(/^@/,``);if(!fe.test(n))throw new _(`invalid`,`That isn't a GitHub username.`);let r=a();try{await k(r,`${i}/collaborators/${encodeURIComponent(n)}`,{method:`PUT`,body:{permission:t===`owner`?`admin`:`push`}})}catch(e){throw e instanceof O&&e.status===404&&(await k(r,`/users/${encodeURIComponent(n)}`,{allow:[404]})).status===404?new _(`not-found`,`There's no GitHub account named ${n}.`):I(e)?new _(`not-allowed`,`This token can't change the site's editors.`):e instanceof O&&e.status===422?new _(`invalid`,`GitHub didn't accept the invitation: ${e.message}`):e}},async setRole(e,t){await o(async n=>{e.id.startsWith(F)?await k(n,`${i}/invitations/${e.id.slice(11)}`,{method:`PATCH`,body:{permissions:t===`owner`?`admin`:`write`}}):await k(n,`${i}/collaborators/${encodeURIComponent(e.id)}`,{method:`PUT`,body:{permission:t===`owner`?`admin`:`push`}})})},async remove(e){await o(t=>k(t,e.id.startsWith(F)?`${i}/invitations/${e.id.slice(11)}`:`${i}/collaborators/${encodeURIComponent(e.id)}`,{method:`DELETE`}))}}}function ge(e,t,n,r){let i,a,o,s;return{access:{tokenLink:n,get active(){return i!==void 0},get problem(){return s},...r&&{async startRedirect(e){s=void 0,await r(e)}},async applyToken(n){let r={...e,token:n.trim()};try{if(!(await A(r,`/repos/${t}`)).permissions?.admin)throw new _(`not-allowed`,`This token's account isn't an owner of the site.`);await A(r,`/repos/${t}/invitations?per_page=1`)}catch(e){throw e instanceof _?e:e instanceof T||I(e)?new _(`not-allowed`,`This token can't change the site's editors.`):e}i=r,a=r,s=void 0},forget(){i=void 0,a=void 0,o?.(),o=void 0}},api:()=>i,codeApi:()=>a,useSignIn(t,n,r){i={...e,token:t},a=r?{...e,token:r}:void 0,o=n,s=void 0},failed(e){s=e}}}var _e=[`185.199.108.153`,`185.199.109.153`,`185.199.110.153`,`185.199.111.153`],ve=[`2606:50c0:8000::153`,`2606:50c0:8001::153`,`2606:50c0:8002::153`,`2606:50c0:8003::153`],ye=new Set([`approved`,`issued`,`uploaded`]),be=new Set([`errored`,`bad_authz`,`authorization_revoked`]);function L(e,t,{apex:n,www:r}){let i=`${(e.split(`/`)[0]??``).toLowerCase()}.github.io`;return n?[..._e.map(e=>({type:`A`,name:t,value:e,purpose:`site`})),...ve.map(e=>({type:`AAAA`,name:t,value:e,purpose:`site`,optional:!0})),...r?[{type:`CNAME`,name:`www.${t}`,value:i,purpose:`www`,optional:!0}]:[]]:[{type:`CNAME`,name:t,value:i,purpose:`site`}]}function xe(e,t){let n=`/repos/${t}/pages`;async function r(){let t=await k(e(),n,{allow:[404]});return t.status===404?void 0:await t.json()}async function i(t){try{await k(e(),n,{method:`PUT`,body:t})}catch(e){throw e instanceof O&&(e.status===403||e.status===404)?new x(`not-allowed`,`This sign-in can't change the site's GitHub Pages settings.`):e instanceof O&&(e.status===400||e.status===422)?/taken|already/i.test(e.message)?new x(`taken`,`Another GitHub Pages site already uses this domain.`):`https_enforced`in t?new x(`not-ready`,`The domain's certificate isn't ready yet.`):new x(`invalid`,`GitHub Pages doesn't accept this domain.`):e}}return{severalDomains:!1,async site(){let e=await r();return e&&{url:e.html_url,domain:e.cname??void 0}},async connect(e,n){return await i({cname:e}),L(t,e,n)},async records(e,n){return L(t,e,n)},async status(t){let r=await A(e(),n),i=r.https_certificate?.state??``;return{verified:!0,certificate:ye.has(i)?`ready`:be.has(i)?`failed`:`pending`,httpsOnly:r.https_enforced===!0,primary:r.cname===t}},async secure(){await i({https_enforced:!0})},async disconnect(){await i({cname:null})}}}var Se=`.github/workflows/scheduled.yml`,Ce=[`.github/workflows/deploy.yml`,`.github/workflows/rebuild.yml`];function we(e){return{async timing(){let[t,...n]=await Promise.all([Se,...Ce].map(e));return t&&/\bdue\b/.test(t)&&/\bschedule:/.test(t)?`hourly`:n.some(e=>e&&/\bschedule:/.test(e))?`nightly`:`none`}}}function Te(e){let t=new URL(e);return t.hostname===`api.github.com`?`https://github.com`:`${t.origin}${t.pathname.replace(/\/api\/v3\/?$/,``)}`.replace(/\/+$/,``)}function Ee(e,t,n,r={}){let i=r.wait??(e=>new Promise(t=>setTimeout(t,e))),a=(n,r)=>k(e,`/repos/${t}/contents/${n}?ref=${encodeURIComponent(r)}`,{allow:[404]}),o=async()=>(await a(`.github/workflows/${g}`,n)).ok;return{supported:o,secretsPlace:async()=>({kind:`github`,url:`${Te(e.apiUrl)}/${t}/settings/secrets/actions/new`}),async run(n){let s=p(n);if(s)throw new h(`failed`,s);if(!await o())throw new h(`missing`,`The site's setup files don't run plugins' tasks: it needs plugin-task.yml.`);try{await k(e,`/repos/${t}/dispatches`,{method:`POST`,body:{event_type:c,client_payload:{request:n.id,plugin:n.plugin,task:n.task,input:n.input,key:n.key}}})}catch(e){throw e instanceof O&&(e.status===403||e.status===404)?new h(`not-allowed`,`Running plugins' tasks needs a sign-in that can publish to the site.`):e}let u=`${v}${n.id}`,d=Date.now()+(r.timeoutMs??3e5);for(;;){let n=await a(l,u);if(n.ok){let{content:r=``}=await n.json();return await k(e,`/repos/${t}/git/refs/heads/${encodeURIComponent(u)}`,{method:`DELETE`,allow:[404,422]}).catch(()=>{}),new TextDecoder().decode(w(r.replace(/\s/g,``)))}if(Date.now()>=d)throw new h(`timeout`,`The site's build service didn't answer in time.`);await i(r.pollMs??4e3)}}}}var De=`deploy.yml`,Oe=`update.yml`,ke=`publish-update`;function R(e,t,n,r,i,o=De){let c=`/repos/${n}/actions/workflows/${o}`,l=`.github/workflows/${o}`;return{async setup(){let e=await i.read(l);return e&&/update --(publish|commit)\b/.test(e)?`ready`:`missing`},async lastRun(){let t=await k(e,`${c}/runs?branch=${encodeURIComponent(r)}&per_page=20`,{allow:[403,404]});if(!t.ok)return;let{workflow_runs:o=[]}=await t.json();for(let t of o.filter(e=>[`schedule`,`workflow_dispatch`].includes(e.event))){let r={date:t.created_at,detailsUrl:t.html_url};if(t.status!==`completed`)return{state:`running`,...r};let{jobs:o=[]}=await A(e,`/repos/${n}/actions/runs/${t.id}/jobs`),c=o.find(e=>e.name===`update`);if(!c||c.conclusion===`skipped`)continue;if(c.conclusion!==`success`)return{state:`failed`,...r};let l=o.find(e=>e.name===ke);if(l&&l.conclusion!==`success`&&l.conclusion!==`skipped`)return{state:`failed`,...r};let u=s(await i.readAt(`package.json`,t.head_sha)??``),d=s(await i.read(`package.json`)??``);if(!u||!d||u===d)return{state:`up-to-date`,...r};let f=a(d,u)<0;return{state:`updated`,...r,result:{state:`updated`,from:u,to:d,...f&&{rollback:f}}}}},nightly:Ae(e,t,n,()=>i.read(l)),async rebuild(){await d({})},async start(e){await d({update:e})}};async function d(n){try{await k(t()??e,`${c}/dispatches`,{method:`POST`,body:{ref:r,inputs:n}})}catch(e){throw e instanceof O&&(e.status===403||e.status===401)?new u(`not-allowed`,`Running the site's build needs a token that can run its workflows.`):e instanceof O&&(e.status===404||e.status===422)?new u(`missing`,`The site's GitHub Pages workflow doesn't update Goodfellow.`):e}}}function Ae(e,t,n,r){let i=`/repos/${n}/actions/variables`,a=e=>{throw e instanceof O&&(e.status===401||e.status===403)?new u(`not-allowed`,`Changing when the site rebuilds needs GitHub's Variables permission.`):e};return{async supported(){return(await r())?.includes(`GOODFELLOW_NIGHTLY`)??!1},async get(){let n=await k(t()??e,`${i}/${d}`,{allow:[403,404]});if(n.status===404)return`changed`;if(n.ok)return b((await n.json()).value)},async set(n){let r=t()??e;if(n===`changed`){await k(r,`${i}/${d}`,{method:`DELETE`,allow:[404]}).catch(a);return}let o={name:d,value:n};(await k(r,`${i}/GOODFELLOW_NIGHTLY`,{method:`PATCH`,body:o,allow:[404]}).catch(a)).status===404&&await k(r,i,{method:`POST`,body:o}).catch(a)}}}function z(e){return e instanceof T&&e.problem===`no-access`||e instanceof O&&(e.status===403||e.status===404)}function je(e){let{read:t}=e,n=j(e.repo),r,i=e=>(r??=A(e,`/repos/${n}`).then(e=>e.default_branch),r.catch(()=>{r=void 0}),r);async function a(){if(!t)throw new T(`no-access`,`This sign-in has no access to ${e.repo}.`);return e.open(t,await i(t))}async function o(e){let t=await a();return t.readAt(e,await t.revision())}async function s(){if(!t)throw new T(`no-access`,`This sign-in has no access to ${e.repo}.`);let r=await i(t);return R(t,e.manage,n,r,{read:o,readAt:async(e,t)=>(await a()).readAt(e,t)},Oe)}return{code:{repo:e.repo,webUrl:`${e.webUrl}/${e.repo}`,read:o,history:async(e,t)=>(await a()).history(e,t),readAt:async(e,t)=>(await a()).readAt(e,t)},async setup(){try{return await(await s()).setup()}catch(e){if(z(e))return`no-access`;throw e}},async lastRun(){try{return await(await s()).lastRun()}catch(e){if(z(e))return;throw e}},async start(e){await(await s()).start(e)},async rebuild(){await(await s()).rebuild?.()}}}var B=/cloudflare/i,V=100,Me=300,Ne=10,Pe=`mutation ($input: CreateCommitOnBranchInput!) {
|
|
19
|
-
createCommitOnBranch(input: $input) { commit { oid } }
|
|
20
|
-
}`;function H(e,t){let n=`${t}/`;return[...e.keys()].filter(e=>e.startsWith(n)).sort()}var U=class n{user;pages;editors;ownerAccess;updates;drafts;scheduledBuilds;tasks;comments;contentOnly;options;api;repo;branch;onSignOut;author;owner;pinned;trees=new Map;treeSizes=new Map;blobs=new Map;constructor(e){this.options=e,this.api=e.api,this.repo=j(e.repo),this.branch=e.branch,this.user=e.user,this.onSignOut=e.onSignOut,this.author=e.author,this.pinned=e.revision;let t=ge(this.api,this.repo,e.ownerTokenLink,e.ownerRedirect);this.owner=t,this.ownerAccess=t.access,this.pages=xe(()=>t.api()??this.api,this.repo),this.editors=he(this.api,t.api,this.repo,this.user.login),this.contentOnly=e.contentOnly===!0,this.contentOnly?e.code&&(this.updates=je({repo:e.code.repo,webUrl:e.code.webUrl,read:e.code.api,manage:t.codeApi,open:(t,r)=>new n({api:t,repo:e.code?.repo??``,branch:r,user:this.user,onSignOut:()=>{},ownerTokenLink:e.ownerTokenLink})})):this.updates=R(this.api,t.api,this.repo,this.branch,this),this.drafts=o(this,this.draftHost()),this.scheduledBuilds=we(e=>this.read(e)),this.tasks=Ee(this.api,this.repo,this.branch,e.tasks),this.comments=de(this.api,e.repo,e.commentsTokenLink??P(`https://github.com`,e.repo))}async repositoryVisibility(){let e=await A(this.api,`/repos/${this.repo}`);return e.visibility===`internal`?`internal`:e.private===!1||e.visibility===`public`?`public`:`private`}draftHost(){let e=`/repos/${this.repo}`,t=t=>`${e}/git/refs/heads/${encodeURIComponent(t)}`,r=t=>{let n=decodeURIComponent(this.repo).split(`/`)[0],r=new URLSearchParams({head:`${n}:${t}`,state:`open`});return A(this.api,`${e}/pulls?${r}`)};return{liveBranch:this.branch,branchStore:e=>new n({...this.options,branch:e}),createBranch:async(t,n)=>{if((await k(this.api,`${e}/git/refs`,{method:`POST`,body:{ref:`refs/heads/${t}`,sha:n},allow:[422]})).status===422)throw new f(`exists`,`There's already a draft called ${t}.`)},deleteBranch:async e=>{await k(this.api,t(e),{method:`DELETE`,allow:[404,422]})},mergeBase:async t=>{let n=await k(this.api,`${e}/compare/${encodeURIComponent(this.branch)}...${encodeURIComponent(t)}`,{allow:[404]});if(n.status===404)throw new f(`not-found`,`There's no draft ${t}.`);return(await n.json()).merge_base_commit.sha},listBranches:async t=>(await A(this.api,`${e}/git/matching-refs/heads/${encodeURIComponent(t)}`)).map(e=>e.ref.replace(/^refs\/heads\//,``)),openReview:async({branch:t,title:n,description:i,reviewers:a=[]})=>{let o=await k(this.api,`${e}/pulls`,{method:`POST`,body:{title:n,head:t,base:this.branch,body:i},allow:[403,404,422]}),s;if(o.ok)s=await o.json();else if(o.status!==422)throw new f(`no-reviews`,`This sign-in can't open pull requests on the site's repository.`);else if([s]=await r(t),!s)throw new O(422,`GitHub couldn't open the pull request.`);for(let t of a)await k(this.api,`${e}/pulls/${s.number}/requested_reviewers`,{method:`POST`,body:{reviewers:[t]},allow:[403,404,422]});return{url:s.html_url}},listReviews:async t=>{let n=[];for(let t=1;t<=Ne;t++){let r=new URLSearchParams({state:`open`,per_page:`100`,page:String(t)}),i=await A(this.api,`${e}/pulls?${r}`);if(n.push(...i),i.length<100)break}let r=decodeURIComponent(this.repo).toLowerCase();return n.filter(e=>e.head.ref.startsWith(t)&&(e.head.repo?.full_name??r).toLowerCase()===r).map(e=>({branch:e.head.ref,url:e.html_url,title:e.title}))},closeReview:async t=>{for(let n of await r(t))await k(this.api,`${e}/pulls/${n.number}`,{method:`PATCH`,body:{state:`closed`},allow:[403,404,422]})}}}async revision(){return this.pinned=await this.head(),this.pinned}async head(){return(await A(this.api,`/repos/${this.repo}/git/ref/heads/${encodeURIComponent(this.branch)}`)).object.sha}tree(e){let t=this.trees.get(e);return t||(t=A(this.api,`/repos/${this.repo}/git/trees/${e}?recursive=1`).then(t=>{if(t.truncated)throw new O(413,`The repository has too many files for GitHub to list at once.`);let n=t.tree.filter(e=>e.type===`blob`);return this.treeSizes.set(e,new Map(n.flatMap(e=>e.size===void 0?[]:[[e.path,e.size]]))),new Map(n.map(e=>[e.path,e.sha]))}),t.catch(()=>this.trees.delete(e)),this.trees.set(e,t)),t}async currentTree(){return this.tree(this.pinned??await this.revision())}async read(e){return this.readFrom(await this.currentTree(),e)}readFrom(e,t){let n=e.get(t);if(!n)return Promise.resolve(void 0);let r=this.blobs.get(n);return r||(r=k(this.api,`/repos/${this.repo}/git/blobs/${n}`,{accept:`application/vnd.github.raw+json`}).then(e=>e.text()),r.catch(()=>this.blobs.delete(n)),this.blobs.set(n,r)),r}async readFiles(e){return this.readFilesFrom(await this.currentTree(),e)}async readFilesFrom(e,t){let n=t.flatMap(t=>{let n=e.get(t);return n?[[t,n]]:[]}),r=[...new Set(n.map(([,e])=>e).filter(e=>!this.blobs.has(e)))],[i,a]=decodeURIComponent(this.repo).split(`/`);for(let e=0;e<r.length;e+=V){let t=r.slice(e,e+V),n=t.map((e,t)=>`f${t}: object(oid: "${e}") { ... on Blob { text isBinary } }`),o=await A(this.api,`/graphql`,{method:`POST`,body:{query:`query ($owner: String!, $name: String!) { repository(owner: $owner, name: $name) { ${n.join(` `)} } }`,variables:{owner:i,name:a}}});t.forEach((e,t)=>{let n=o.data?.repository?.[`f${t}`];n&&!n.isBinary&&typeof n.text==`string`&&this.blobs.set(e,Promise.resolve(n.text))})}let o=new Map;for(let[t]of n){let n=await this.readFrom(e,t);n!==void 0&&o.set(t,n)}return o}async readBytes(e){return this.bytesFrom(await this.currentTree(),e)}async bytesFrom(e,t){let n=e.get(t);if(!n)return;let r=await k(this.api,`/repos/${this.repo}/git/blobs/${n}`,{accept:`application/vnd.github.raw+json`});return new Uint8Array(await r.arrayBuffer())}async list(e){return H(await this.currentTree(),e)}filesAt(e){return{read:async t=>this.readFrom(await this.tree(e),t),readFiles:async t=>this.readFilesFrom(await this.tree(e),t),readBytes:async t=>this.bytesFrom(await this.tree(e),t),list:async t=>H(await this.tree(e),t)}}async fileSizes(e){let t=`${e}/`;await this.currentTree();let n=this.treeSizes.get(this.pinned??``)??new Map;return new Map([...n].filter(([e])=>e.startsWith(t)))}useOwnerSignIn(e,t,n){this.owner.useSignIn(e,t,n)}ownerSignInFailed(e){this.owner.failed(e)}async write(t,n){return this.contentOnly&&e(t),this.author?this.writeCommit(t,n,this.author):this.writeGraphQL(t,n)}async writeCommit(e,{message:n,expectedRevision:r},i){let a=await this.tree(r),o=`/repos/${this.repo}`,s=[];try{for(let t of e)if(`delete`in t)a.has(t.path)&&s.push({path:t.path,mode:`100644`,type:`blob`,sha:null});else if(`bytes`in t){let e=await A(this.api,`${o}/git/blobs`,{method:`POST`,body:{content:E(t.bytes),encoding:`base64`}});s.push({path:t.path,mode:`100644`,type:`blob`,sha:e.sha})}else s.push({path:t.path,mode:`100644`,type:`blob`,content:t.content});if(s.length===0)return{revision:r};let c=await A(this.api,`${o}/git/commits/${r}`),l=await A(this.api,`${o}/git/trees`,{method:`POST`,body:{base_tree:c.tree.sha,tree:s}}),u=await A(this.api,`${o}/git/commits`,{method:`POST`,body:{message:n,tree:l.sha,parents:[r],author:{...i,date:new Date().toISOString()}}});if((await k(this.api,`${o}/git/refs/heads/${encodeURIComponent(this.branch)}`,{method:`PATCH`,body:{sha:u.sha,force:!1},allow:[422]})).status===422)throw await this.revision()===r?new O(422,`GitHub couldn't save the changes.`):new t;return this.pinned=u.sha,{revision:u.sha}}catch(e){throw e instanceof O&&(e.status===403||e.status===404)?new T(`cant-publish`,`This sign-in can't publish to the site.`):e}}async writeGraphQL(e,{message:n,expectedRevision:r}){let i=await this.tree(r),a=e.flatMap(e=>`delete`in e?[]:[{path:e.path,contents:`bytes`in e?E(e.bytes):ee(e.content)}]),o=e.flatMap(e=>`delete`in e&&i.has(e.path)?[{path:e.path}]:[]);if(a.length===0&&o.length===0)return{revision:r};let s=await A(this.api,`/graphql`,{method:`POST`,body:{query:Pe,variables:{input:{branch:{repositoryNameWithOwner:decodeURIComponent(this.repo),branchName:this.branch},message:{headline:n},expectedHeadOid:r,fileChanges:{additions:a,deletions:o}}}}}),c=s.data?.createCommitOnBranch?.commit?.oid;if(c)return this.pinned=c,{revision:c};if(await this.revision()!==r)throw new t;let l=s.errors?.[0];throw l?.type===`FORBIDDEN`?new T(`cant-publish`,`This GitHub account can't publish to the site.`):new O(422,`GitHub couldn't save the changes: ${l?.message??`unknown error`}`)}async history(e,{page:t=1,perPage:n=20}={}){let r=new URLSearchParams({sha:this.pinned??await this.revision(),path:e,per_page:String(n),page:String(t)});return(await A(this.api,`/repos/${this.repo}/commits?${r}`)).map(e=>({revision:e.sha,date:e.commit.author?.date??``,author:e.commit.author?.name||e.author?.login||void 0,message:e.commit.message.split(`
|
|
21
|
-
`)[0]??``}))}async readAt(e,t){return this.readFrom(await this.tree(t),e)}async changedPaths(e,t){let n=(await A(this.api,`/repos/${this.repo}/compare/${e}...${t}`)).files??[];if(n.length>=Me)throw new O(0,`More files changed between ${e} and ${t} than GitHub lists.`);return[...new Set(n.flatMap(e=>[e.filename,e.previous_filename??[]].flat()))]}async deployStatus(e){try{let t=(await A(this.api,`/repos/${this.repo}/deployments?sha=${e}&per_page=5`))[0];if(t){let[n]=await A(this.api,`/repos/${this.repo}/deployments/${t.id}/statuses?per_page=1`),r=n?.log_url||n?.target_url||void 0;switch(n?.state){case`success`:case`inactive`:return{state:`live`,detailsUrl:r};case`failure`:case`error`:{let t=await this.workflowRun(e);return{state:`failed`,detailsUrl:r,problem:t?await this.runProblem(t):{step:`deploy`}}}default:return{state:`building`,detailsUrl:r}}}let n=await this.cloudflareBuild(e);if(n)return n;let r=await this.workflowRun(e);if(r?.status===`completed`&&r.conclusion===`cancelled`){let t=await this.head();if(t!==e)return this.deployStatus(t)}if(r?.status===`completed`&&r.conclusion!==`success`&&r.conclusion!==`skipped`)return{state:`failed`,detailsUrl:r.html_url,problem:await this.runProblem(r)};if(r)return{state:`building`,detailsUrl:r.html_url};if((await A(this.api,`/repos/${this.repo}/deployments?per_page=1`)).length>0)return{state:`building`};let i=await this.parentOf(e);return{state:i&&await this.cloudflareBuild(i)?`building`:`unknown`}}catch(e){if(e instanceof O)return{state:`unknown`};throw e}}async cloudflareBuild(e){let t=await k(this.api,`/repos/${this.repo}/commits/${e}/check-runs?per_page=50`,{allow:[403,404]});if(t.ok){let{check_runs:e=[]}=await t.json(),n=e.find(e=>B.test(`${e.app?.slug??``} ${e.name}`));if(n){let e=n.details_url??n.html_url??void 0;return n.status===`completed`?n.conclusion===`success`||n.conclusion===`neutral`||n.conclusion===`skipped`?{state:`live`,detailsUrl:e}:{state:`failed`,detailsUrl:e,problem:{step:`build`,detail:n.output?.title??void 0}}:{state:`building`,detailsUrl:e}}}let n=await k(this.api,`/repos/${this.repo}/commits/${e}/statuses?per_page=50`,{allow:[403,404]});if(!n.ok)return;let r=(await n.json()).find(e=>B.test(e.context));if(!r)return;let i=r.target_url??void 0;return r.state===`success`?{state:`live`,detailsUrl:i}:r.state===`pending`?{state:`building`,detailsUrl:i}:{state:`failed`,detailsUrl:i,problem:{step:`build`,detail:r.description??void 0}}}async parentOf(e){let t=await k(this.api,`/repos/${this.repo}/commits/${e}`,{allow:[403,404,422]});if(t.ok)return(await t.json()).parents?.[0]?.sha}async workflowRun(e){let t=await k(this.api,`/repos/${this.repo}/actions/runs?head_sha=${e}&per_page=20`,{allow:[403,404]});if(!t.ok)return;let{workflow_runs:n=[]}=await t.json(),r=n.filter(e=>!e.path?.endsWith(`/${C}.yml`));return r.find(e=>/deploy|pages/i.test(`${e.path??``} ${e.name??``}`))??r[0]}async runProblem(e){let t=await k(this.api,`/repos/${this.repo}/actions/runs/${e.id}/jobs?per_page=50`,{allow:[403,404]}),n=(t.ok?(await t.json()).jobs??[]:[]).find(e=>e.conclusion===`failure`);if(!n)return{step:e.conclusion===`startup_failure`?`not-started`:`host`,detail:e.conclusion??void 0};let r=n.steps?.find(e=>e.conclusion===`failure`);return r?{step:S(r.name)??(/deploy/i.test(n.name)?`deploy`:`build`),detail:`${n.name}: ${r.name}`}:{step:`not-started`,detail:n.name}}signOut(){this.ownerAccess.forget(),this.comments.access.forget(),this.onSignOut()}},Fe={invalid:`invalid`,"no-access":`no-access`,"cant-publish":`cant-publish`,cancelled:`redirect-failed`,"not-installed":`not-installed`,"no-address":`no-address`,"wrong-address":`wrong-address`,"local-address":`local-address`,"not-owner":`not-owner`};function W(e){let t=Fe[String(e.problem)]??`unavailable`,n=typeof e.installUrl==`string`&&/^https:\/\//.test(e.installUrl)?e.installUrl:void 0;return new T(t,`The sign-in service said: ${String(e.problem??`no answer`)}.`,n)}function G(e){let t;try{t=new URL(e).hostname.toLowerCase()}catch{return!0}return t===`localhost`||t.endsWith(`.localhost`)||t===`0.0.0.0`||t===`[::1]`||/^127(\.\d{1,3}){3}$/.test(t)}function K(e){let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)}async function q(){let e=K(crypto.getRandomValues(new Uint8Array(32))),t=await crypto.subtle.digest(`SHA-256`,new TextEncoder().encode(e));return{verifier:e,challenge:K(new Uint8Array(t))}}function J(){if(typeof window<`u`)return{href:()=>window.location.href,assign:e=>window.location.assign(e),replace:e=>window.history.replaceState(window.history.state,``,e)}}var Y=`goodfellow_sign_in`,X=`goodfellow_sign_in_error`,Ie=class{url;fetcher;constructor(e,t){this.url=e.replace(/\/$/,``),this.fetcher=t}async answer(e,t){let n;try{n=await this.fetcher(`${this.url}${e}`,t)}catch(e){throw new T(`unavailable`,`Couldn't reach the sign-in service: ${e.message}`)}let r=await n.json().catch(()=>({}));if(!n.ok)throw W(r);return r}post(e,t){return this.answer(e,{method:`POST`,headers:{"content-type":`text/plain`},body:JSON.stringify(t)})}async postAnswer(e,t){let n;try{n=await this.fetcher(`${this.url}${e}`,{method:`POST`,headers:{"content-type":`text/plain`},body:JSON.stringify(t)})}catch(e){throw new T(`unavailable`,`Couldn't reach the sign-in service: ${e.message}`)}return{ok:n.ok,body:await n.json().catch(()=>({}))}}async health(){if((await this.answer(`/health`)).ok!==!0)throw new T(`unavailable`,`The sign-in service isn't set up.`)}async check(e,t){await this.answer(`/github/check?${new URLSearchParams({repo:e,purpose:t})}`)}startUrl(e){let t=new URLSearchParams({purpose:e.purpose,...e.repo&&{repo:e.repo},return:e.back,challenge:e.challenge,remember:e.remember?`1`:`0`,...e.install&&{install:`1`}});return`${this.url}/github/start?${t}`}session(e,t,n){return this.post(`/github/session`,{grant:e,verifier:t,...n&&{code:n}})}token(e,t){return this.post(`/github/token`,{session:e,...t&&{code:t}})}};function Z(e,t,n,r){let i=t,a;async function o({refresh:t=!1}={}){return(t||Date.parse(i.expiresAt)-3e5<Date.now())&&(a??=e.token(i.session,r).finally(()=>{a=void 0}),i=await a,n(i)),i.token}return{current:()=>i,token:o,async codeToken(e){if(await o(e),!i.code)throw new T(`no-access`,`The sign-in service gave no token for the code repository.`);return i.code.token}}}var Q=`main`;function Le(e=`https://github.com`){let t=new URLSearchParams({name:`Goodfellow site setup`,description:`Create a Goodfellow site. It can be deleted once the site is created.`,expires_in:`7`,administration:`write`,contents:`write`,workflows:`write`,pages:`write`,secrets:`write`}),n=new URLSearchParams({scopes:`repo,workflow`,description:`Goodfellow site setup`});return{fineGrained:`${e}/settings/personal-access-tokens/new?${t}`,classic:`${e}/settings/tokens/new?${n}`}}function Re(e){let t=new Map;async function n(e,t){if(t.default_branch===Q)return;let n=`/repos/${j(t.full_name)}`,r=await A(e,`${n}/git/ref/heads/${t.default_branch}`);await k(e,`${n}/git/refs`,{method:`POST`,body:{ref:`refs/heads/${Q}`,sha:r.object.sha}}),await k(e,n,{method:`PATCH`,body:{default_branch:Q}}),await k(e,`${n}/git/refs/heads/${t.default_branch}`,{method:`DELETE`})}async function r(e,t){try{return(await A(e,`/repos/${j(t.full_name)}/pages`,{method:`POST`,body:{build_type:`workflow`}})).html_url}catch(e){if(e instanceof O&&[403,404,409,422].includes(e.status))return;throw e}}async function a(e,t,n){try{return await k(e,`/repos/${j(t.full_name)}/pages`,{method:`PUT`,body:{cname:n}}),!0}catch(e){if(e instanceof O&&[400,403,404,409,422].includes(e.status))return!1;throw e}}async function o(t,n,r){let i=`/repos/${j(n.full_name)}`,a=[];for(let e of r.files){if(`delete`in e)continue;if(`content`in e){a.push({path:e.path,mode:`100644`,type:`blob`,content:e.content});continue}let n=await A(t,`${i}/git/blobs`,{method:`POST`,body:{content:E(e.bytes),encoding:`base64`}});a.push({path:e.path,mode:`100644`,type:`blob`,sha:n.sha})}try{let n=await A(t,`${i}/git/trees`,{method:`POST`,body:{tree:a}}),o=await A(t,`${i}/git/commits`,{method:`POST`,body:{message:r.message,tree:n.sha,parents:[],...e.author&&{author:{...e.author,date:new Date().toISOString()}}}});await k(t,`${i}/git/refs/heads/${Q}`,{method:`PATCH`,body:{sha:o.sha,force:!0}})}catch(e){throw e instanceof O&&(e.status===403||e.status===404)?new y(`not-allowed`,`This sign-in can't write the site's files, or its build setup.`):e}}async function s(e,t){return(await k(e,`/repos/${j(t.full_name)}/rulesets`,{method:`POST`,body:{name:`Protect the published history`,target:`branch`,enforcement:`active`,conditions:{ref_name:{include:[`~DEFAULT_BRANCH`],exclude:[]}},rules:[{type:`non_fast_forward`},{type:`deletion`}]},allow:[403,404,422]})).ok}async function c(e){if(!e.private)return!0;let{newDeployKey:n,sealSecret:r}=await i(()=>import(`./deploy-keys-DAj2oX-N-DRd_HmOG.js`).then(e=>e.t),__vite__mapDeps([0,1]),import.meta.url);try{for(let{reader:i,read:a,secret:o}of e.links.reads){if(!o)continue;let s=e[i],c=e[a],l=t.get(s.toLowerCase()),u=t.get(c.toLowerCase());if(!l||!u)throw Error(`${s} and ${c} have to be created first.`);let d=await n(`goodfellow-${o.toLowerCase()}`);await k(u,`/repos/${j(c)}/keys`,{method:`POST`,body:{title:`${s}'s builds`,key:d.publicKey,read_only:!0}});let f=`/repos/${j(s)}/actions/secrets`,p=await A(l,`${f}/public-key`),m=await r(d.privateKey,w(p.key));await k(l,`${f}/${o}`,{method:`PUT`,body:{encrypted_value:E(m),key_id:p.key_id}})}return!0}catch(e){if(e instanceof O&&[403,404,422].includes(e.status))return!1;throw e}}return{user:e.user,owners:()=>e.owners(),isAvailable:(t,n)=>e.isAvailable(t,n),async createSite(i,l){let u=[];l?.(`repository`);let{repo:d,api:f,signInInstallUrl:p}=await e.create(i),m=async e=>(l?.(`connect`),c(e));await n(f,d);let h;return i.pages&&(l?.(`pages`),h=await r(f,d),h?i.domain&&(await a(f,d,i.domain)?h=`https://${i.domain}/`:u.push(`domain-unavailable`)):u.push(`pages-unavailable`)),t.set(d.full_name.toLowerCase(),f),i.link&&!await m(i.link)&&u.push(`connect-unavailable`),l?.(`files`),await o(f,d,i),l?.(`protection`),await s(f,d)||u.push(`protection-unavailable`),p&&u.push(`sign-in-not-installed`),{repo:d.full_name,webUrl:d.html_url,siteUrl:h,buildsUrl:`${d.html_url}/actions`,pagesUrl:i.pages?`${d.html_url}/settings/pages`:void 0,...p&&{signInInstallUrl:p},warnings:u}}}}async function ze(e){let t=await A(e,`/user`);async function n(t,n){return(await k(e,`/repos/${j(`${t.path}/${n}`)}`,{allow:[404]})).status===404}return{user:{login:t.login,name:t.name??void 0,avatarUrl:t.avatar_url},async owners(){let n={path:t.login,name:t.name||t.login,kind:`personal`},r=[];try{for(let t=1;t<=10;t++){let n=await A(e,`/user/orgs?per_page=100&page=${t}`);if(r.push(...n),n.length<100)break}}catch{}return[n,...r.map(e=>({path:e.login,name:e.login,kind:`organization`}))]},isAvailable:n,async create(t){let r=t.owner.kind===`personal`?`/user/repos`:`/orgs/${encodeURIComponent(t.owner.path)}/repos`;if(!await n(t.owner,t.name))throw new y(`name-taken`,`There's already a repository called ${t.owner.path}/${t.name}.`);try{return{repo:await A(e,r,{method:`POST`,body:{name:t.name,private:t.private,description:t.description,auto_init:!0}}),api:e}}catch(e){throw e instanceof O&&e.status===422?new y(`name-invalid`,`GitHub can't use "${t.name}" as a repository name.`):e instanceof O&&(e.status===403||e.status===404)?new y(`not-allowed`,`This sign-in can't create repositories in ${t.owner.path}.`):e}}}}function Be(e,t,n,r){let i=r.session;async function a(t,n){let r=await e.postAnswer(t,{session:i,...n});if(typeof r.body.session==`string`&&(i=r.body.session),!r.ok)throw Ve(r.body);return r.body}let{user:o}=r;return{user:{login:o.login,name:o.name,avatarUrl:o.avatarUrl},author:{name:o.name||o.login,email:o.email},async owners(){let e=await a(`/github/setup/owners`,{});return(e.owners??[]).map(({installed:t,...n})=>({...n,...!t&&e.installUrl&&{installUrl:e.installUrl}}))},async isAvailable(e,t){return(await a(`/github/setup/available`,{owner:e.path,name:t})).available===!0},async create(e){if(e.owner.installUrl)throw new y(`not-installed`,`Goodfellow isn't installed on ${e.owner.path}.`,e.owner.installUrl);let r=await a(`/github/setup/repository`,{owner:e.owner.path,name:e.name,private:e.private,description:e.description,...e.more&&{more:!0}});if(!r.repo||!r.token)throw new T(`unavailable`,`The sign-in service didn't answer.`);return{repo:r.repo,api:{apiUrl:t,token:r.token,fetch:n},...r.editInstallUrl&&{signInInstallUrl:r.editInstallUrl}}}}}function Ve(e){switch(e.problem){case`name-taken`:return new y(`name-taken`,`There's already a repository with that name.`);case`name-invalid`:return new y(`name-invalid`,`GitHub can't use that as a repository name.`);case`not-allowed`:return new y(`not-allowed`,`This sign-in can't create repositories there.`);case`not-installed`:return new y(`not-installed`,`Goodfellow isn't installed there.`,e.installUrl);default:return W(e)}}function He(e={}){let t=(e.apiUrl??`https://api.github.com`).replace(/\/$/,``),n=Le(e.webUrl),r=e.fetch??((e,t)=>globalThis.fetch(e,t)),i=e.location??J(),a=e.signIn,o=a&&i&&!G(i.href())?new Ie(a,r):void 0,s=D(`goodfellow:github:setup:pending`,e.storage);return{name:`GitHub`,canRedirect:o!==void 0,tokenLinks:[{url:n.fineGrained,label:`signIn.token.create`},{url:n.classic,label:`signIn.token.createBroad`,hint:`signIn.token.createBroadHint`}],async restore(){if(!i)return null;let e=new URL(i.href()),n=e.searchParams.get(Y),a=e.searchParams.get(X);if(!n&&!a)return null;e.searchParams.delete(Y),e.searchParams.delete(X),i.replace(e.toString());let c=s.load();if(s.clear(),a||!n||!c||!o)throw W({problem:a??`cancelled`});let l=await o.session(n,c);return Re(Be(o,t,r,l))},async signInWithToken(e){let n=e.trim();if(!n)throw new T(`invalid`,`Paste a token to sign in.`);return Re(await ze({apiUrl:t,token:n,fetch:r}))},async startRedirect({install:e}={}){if(!o||!i)throw new T(`unavailable`,`Signing in with GitHub isn't available here.`);await o.health();let{verifier:t,challenge:n}=await q();s.save(t,!1),i.assign(o.startUrl({purpose:`setup`,back:i.href(),challenge:n,remember:!1,install:e}))}}}function Ue(e){return e instanceof T&&e.problem!==`unavailable`}function $(e,t=`https://github.com`){let[n=``]=e.split(`/`),r=new URLSearchParams({name:`Goodfellow admin`,description:`Edit ${e} in its admin panel`,target_name:n,expires_in:`90`,contents:`write`,deployments:`read`,actions:`read`,statuses:`read`}),i=new URLSearchParams({scopes:`repo`,description:`Goodfellow admin for ${e}`}),a=new URLSearchParams({name:`Goodfellow owner`,description:`Manage the editors, domain and updates of ${e}`,target_name:n,expires_in:`1`,administration:`write`,pages:`write`,actions:`write`,variables:`write`});return{fineGrained:`${t}/settings/personal-access-tokens/new?${r}`,classic:`${t}/settings/tokens/new?${i}`,owner:`${t}/settings/personal-access-tokens/new?${a}`,comments:P(t,e).url}}function We(e){if(!/^[\w.-]+\/[\w.-]+$/.test(e.repo))throw Error(`github({ repo }) must look like "owner/name" (got "${e.repo}").`);if(e.code!==void 0&&!/^[\w.-]+\/[\w.-]+$/.test(e.code))throw Error(`github({ code }) must look like "owner/name" (got "${e.code}").`);let t=(e.apiUrl??`https://api.github.com`).replace(/\/$/,``),n=(e.webUrl??`https://github.com`).replace(/\/$/,``),r=t=>e.contentOnly&&e.code?{code:{repo:e.code,webUrl:n,...t&&{api:t}}}:{},i=$(e.repo,e.webUrl),a=D(`goodfellow:github:${e.repo}`,e.storage),o=D(`goodfellow:github:pending:${e.repo}`,e.storage),s=m(e.fetch??((e,t)=>globalThis.fetch(e,t)),{host:`GitHub`}),c=e.location??J(),l=e.signIn,u=l&&c&&!G(c.href())?new Ie(l,s):void 0,d=()=>e.contentOnly?e.code:void 0;function f(e,t){a.save(e.type===`token`?e.token:JSON.stringify(e),t)}function p(){let e=a.load();if(e){try{let t=JSON.parse(e);if(t.type===`worker`||t.type===`token`)return t}catch{}return{type:`token`,token:e}}}async function h(t,n,{install:r}={}){if(!u||!c)throw new T(`unavailable`,`Signing in with GitHub isn't available here.`);r||await u.check(e.repo,t);let{verifier:i,challenge:a}=await q();o.save(JSON.stringify({verifier:i,purpose:t,remember:n}),!1),c.assign(u.startUrl({purpose:t,repo:e.repo,back:c.href(),challenge:a,remember:n,install:r}))}async function g(n,o){let c=Z(u,n,e=>f({type:`worker`,session:e.session},o),e.code);f({type:`worker`,session:n.session},o);let l={apiUrl:t,token:c.token,fetch:s},d=await A(l,`/repos/${j(e.repo)}`),{user:p}=n;return new U({api:l,repo:e.repo,branch:e.branch??d.default_branch,...e.contentOnly&&{contentOnly:!0},...r({apiUrl:t,token:c.codeToken,fetch:s}),user:{login:p.login,name:p.name,avatarUrl:p.avatarUrl},author:{name:p.name||p.login,email:p.email},onSignOut:()=>{a.clear(),v(c.current())},ownerTokenLink:{url:i.owner,label:`owner.token.create`},commentsTokenLink:{url:i.comments,label:`comments.token.create`},ownerRedirect:e=>h(`owner`,!1,e)})}function _(e){k({apiUrl:t,token:e,fetch:s},`/installation/token`,{method:`DELETE`}).catch(()=>{})}function v(e){_(e.token),e.code&&_(e.code.token)}async function y(e,t,n){let r=u;try{let i=Z(r,await r.session(t,n,d()),()=>{},d());e.useOwnerSignIn(i.token,()=>v(i.current()),d()?i.codeToken:void 0)}catch(t){e.ownerSignInFailed(t)}}async function b(){if(!c)return;let e=new URL(c.href()),t=e.searchParams.get(Y),n=e.searchParams.get(X);if(!t&&!n)return;e.searchParams.delete(Y),e.searchParams.delete(X),c.replace(e.toString());let r=o.load();o.clear();let i=r?JSON.parse(r):void 0;if(!i||!u)throw new T(`redirect-failed`,`Signing in with GitHub didn't finish in this tab.`);if(i.purpose===`owner`){let e=await x();if(!e)throw new T(`redirect-failed`,`Sign in again, then sign in as an owner.`);return n?e.ownerSignInFailed(W({problem:n})):t&&await y(e,t,i.verifier),e}if(n||!t)throw W({problem:n});return g(await u.session(t,i.verifier,d()),i.remember)}async function x(){let e=p();if(!e)return null;try{return e.type===`token`?await S(e.token):u?await g(await u.token(e.session,d()),a.remembered()):(a.clear(),null)}catch(e){throw Ue(e)&&a.clear(),e}}async function S(n){let o={apiUrl:t,token:n,fetch:s},c=await A(o,`/user`),l;try{l=await A(o,`/repos/${j(e.repo)}`)}catch(t){throw t instanceof O&&(t.status===404||t.status===403)?new T(`no-access`,`The GitHub account ${c.login} can't see ${e.repo}.`):t}if(l.permissions?.push===!1)throw new T(`cant-publish`,`The GitHub account ${c.login} can see ${e.repo} but can't publish to it.`);return new U({api:o,repo:e.repo,branch:e.branch??l.default_branch,...e.contentOnly&&{contentOnly:!0},...r(o),user:{login:c.login,name:c.name??void 0,avatarUrl:c.avatar_url},onSignOut:()=>a.clear(),ownerTokenLink:{url:i.owner,label:`owner.token.create`},commentsTokenLink:{url:i.comments,label:`comments.token.create`},...u&&{ownerRedirect:e=>h(`owner`,!1,e)}})}function C({token:n}){let r={apiUrl:t,token:typeof n==`string`?n:()=>n(),fetch:s},a,o=()=>(a??=e.branch?Promise.resolve(e.branch):A(r,`/repos/${j(e.repo)}`).then(e=>e.default_branch),a.catch(()=>{a=void 0}),a),c=async(t,n)=>new U({api:r,repo:e.repo,branch:await o(),...e.contentOnly&&{contentOnly:!0},user:{login:n?.name??e.repo,...n&&{name:n.name}},onSignOut:()=>{},ownerTokenLink:{url:i.owner,label:`owner.token.create`},commentsTokenLink:{url:i.comments,label:`comments.token.create`},...t&&{revision:t},...n&&{author:n}});return{...e.contentOnly&&{contentOnly:!0},async revision(){return(await c()).revision()},at:c}}return{name:`GitHub`,source:te(`@goodfellow-cms/github`,`github`,e,[`fetch`,`storage`,`location`]),canRedirect:u!==void 0,setup:()=>He({...e.apiUrl&&{apiUrl:e.apiUrl},...e.webUrl&&{webUrl:e.webUrl},...e.fetch&&{fetch:e.fetch},...e.storage&&{storage:e.storage},...e.location&&{location:e.location},signIn:!1}),tokenLinks:[{url:i.fineGrained,label:`signIn.token.create`},{url:i.classic,label:`signIn.token.createBroad`,hint:`signIn.token.createBroadHint`}],async restore(){let e=await b();return e===void 0?x():e},async signInWithToken(e,t){let n=e.trim();if(!n)throw new T(`invalid`,`Paste a token to sign in.`);let r=await S(n);return f({type:`token`,token:n},t),r},startRedirect(e,t){return h(`edit`,e,t)},server:C}}export{U as GitHubBackend,We as github,L as githubPagesRecords,He as githubSetup,Le as githubSetupTokenLinks,$ as githubTokenLinks};
|