import axios , { AxiosError , AxiosResponse } from "axios" ; import { Cookie , CONSTS , roles , Framework } from "../utils" ; import * as t from "io-ts" ; import { pipe } from "fp-ts/function" ; import { fold } from "fp-ts/Either" ; export type { AxiosError } from "axios" ; const { DEFAULT_BASE } = CONSTS ; param path { string } param token { string } param base { string } returns function toAuthUrl ( path , token , base = DEFAULT_BASE ) { const url = new URL ( base ) ; url . hostname = `auth.${ url . hostname }` ; url . pathname = path ; url . searchParams . set ( "token" , token ) ; return url . toString ( ) ; } export async function refreshSession ( cookies , base ? ) { const token = Cookie . parsePrismicAuthToken ( cookies ) ; const url = toAuthUrl ( "refreshtoken" , token , base ) ; return axios . get < string > ( url ) . then ( ( res ) => res . data ) ; } export type RepoData = Record < string , { role : roles . Roles | Record < string , roles . Roles > ; dbid : string ; } > ; const RepoDataValidator = t . record ( t . string , t . type ( { role : roles . RolesValidator , dbid : t . string , } ) ) ; export type UserInfo = { email : string ; type : string ; repositories : RepoData ; } ; export function maybeParseRepoData ( repos ? ) { if ( ! repos ) throw new Error ( "Did not receive repository data" ) ; if ( typeof repos === "string" ) { return pipe ( RepoDataValidator . decode ( JSON . parse ( repos ) ) , fold < t . Errors , RepoData , RepoData > ( ( ) => { throw new Error ( "Can't parse repo data" ) ; } , ( f ) => { return f ; } ) ) ; } return repos ; } export async function validateSession ( cookies , base ? ) { const token = Cookie . parsePrismicAuthToken ( cookies ) ; const url = toAuthUrl ( "validate" , token , base ) ; return axios . get < { email : string ; type : string ; repositories ? : string ; } > ( url ) . then ( ( res ) => { const repositories = maybeParseRepoData ( res . data . repositories ) ; return { ... res . data , repositories , } ; } ) ; } export async function listRepositories ( token , base = DEFAULT_BASE ) { return validateSession ( token , base ) . then ( ( data ) => { return data . repositories ; } ) ; } export async function validateRepositoryName ( name ? , base = DEFAULT_BASE , existingRepo = false ) { if ( ! name ) return Promise . reject ( new Error ( "repository name is required" ) ) ; const domain = name . trim ( ) ; const errors = [ ] ; const startsWithLetter = /^[a-zA-Z]/ . test ( domain ) ; if ( ! startsWithLetter ) errors . push ( "Must start with a letter." ) ; const acceptedChars = /^[a-z0-9-]+$/ . test ( domain ) ; if ( ! acceptedChars ) errors . push ( "Must contain only lowercase letters, numbers and hyphens." ) ; const fourCharactersOrMore = domain . length >= 4 ; if ( ! fourCharactersOrMore ) errors . push ( "Must have four or more alphanumeric characters and/or hyphens." ) ; const endsWithALetterOrNumber = /[a-z0-9]$/ . test ( domain ) ; if ( ! endsWithALetterOrNumber ) errors . push ( "Must end in a letter or a number." ) ; const thirtyCharacterOrLess = domain . length <= 30 ; if ( ! thirtyCharacterOrLess ) errors . push ( "Must be 30 characters or less" ) ; if ( errors . length > 0 ) { const errorString = errors . map ( ( d , i ) => `(${ i + 1 }: ${ d }` ) . join ( " " ) ; const msg = `Validation errors: ${ errorString }` ; return Promise . reject ( new Error ( msg ) ) ; } const addr = new URL ( base ) ; addr . pathname = `/app/dashboard/repositories/${ domain }/exists` ; const url = addr . toString ( ) ; return axios . get < boolean > ( url ) . then ( ( res ) => res . data ) . then ( ( res ) => { if ( ! res && ! existingRepo ) throw new Error ( `${ domain } is already in use` ) ; if ( res && existingRepo ) throw new Error ( `${ domain } does not exist` ) ; return domain ; } ) ; } export type CreateRepositoryResponse = Promise < AxiosResponse < { domain : string ; } > > ; export async function createRepository ( domain , cookies , framework = Framework . FrameworkEnum . vanillajs , base = DEFAULT_BASE ) { const data = { domain , framework , plan : "personal" , isAnnual : "false" , role : "developer" , } ; const address = new URL ( base ) ; address . pathname = "/authentication/newrepository" ; address . searchParams . append ( "app" , "slicemachine" ) ; return axios . post < { domain : string ; framework : string ; plan : string ; isAnnual : string ; role : string ; } , AxiosResponse < { domain : string ; } > > ( address . toString ( ) , data , { headers : { Cookie : cookies , "User-Agent" : "prismic-cli/sm" , } , } ) . catch ( ( error ) => { if ( axios . isAxiosError ( error ) && error . response ) { const message = `[${ error . response . status }]: ${ error . response . statusText }` ; throw new Error ( message ) ; } throw error ; } ) ; }