diff --git a/.cargo/config b/.cargo/config index 084e6db22..f68f95775 100644 --- a/.cargo/config +++ b/.cargo/config @@ -1,2 +1,3 @@ [alias] -lint = "clippy --all-features --all-targets" \ No newline at end of file +lint = "clippy --all-features --all-targets" +lint-fix = "clippy --fix --allow-dirty --allow-staged --all-targets --all-features -- -D warnings" diff --git a/src/commands/connect.rs b/src/commands/connect.rs index 50462f426..086b2bc47 100644 --- a/src/commands/connect.rs +++ b/src/commands/connect.rs @@ -1,11 +1,16 @@ use anyhow::bail; +use std::{collections::BTreeMap, fmt::Display}; use tokio::process::Command; use which::which; -use crate::controllers::variables::get_plugin_variables; -use crate::controllers::{environment::get_matched_environment, project::get_project}; +use crate::controllers::project::get_plugin_or_service; +use crate::controllers::{ + environment::get_matched_environment, + project::{get_project, PluginOrService}, + variables::get_plugin_or_service_variables, +}; use crate::errors::RailwayError; -use crate::util::prompt::{prompt_select, PromptPlugin}; +use crate::util::prompt::prompt_select; use super::{queries::project::PluginType, *}; @@ -13,13 +18,22 @@ use super::{queries::project::PluginType, *}; #[derive(Parser)] pub struct Args { /// The name of the plugin to connect to - plugin_name: Option, + service_name: Option, /// Environment to pull variables from (defaults to linked environment) #[clap(short, long)] environment: Option, } +impl Display for PluginOrService { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + PluginOrService::Plugin(plugin) => write!(f, "{} (legacy)", plugin.friendly_name), + PluginOrService::Service(service) => write!(f, "{}", service.name), + } + } +} + pub async fn command(args: Args, _json: bool) -> Result<()> { let configs = Configs::new()?; let client = GQLClient::new_authorized(&configs)?; @@ -31,46 +45,104 @@ pub async fn command(args: Args, _json: bool) -> Result<()> { let project = get_project(&client, &configs, linked_project.project.clone()).await?; - let plugin = match args.plugin_name { - Some(name) => { - &project - .plugins - .edges - .iter() - .find(|edge| edge.node.friendly_name == name) - .ok_or_else(|| RailwayError::PluginNotFound(name))? - .node - } - None => { - let plugins: Vec<_> = project - .plugins - .edges - .iter() - .map(|p| PromptPlugin(&p.node)) - .collect(); - if plugins.is_empty() { - return Err(RailwayError::ProjectHasNoPlugins.into()); + let plugin_or_service = args + .service_name + .clone() + .map(|name| get_plugin_or_service(&project, name)) + .unwrap_or_else(|| { + let mut nodes_to_prompt: Vec = Vec::new(); + for plugin in &project.plugins.edges { + nodes_to_prompt.push(PluginOrService::Plugin(plugin.node.clone())); + } + for service in &project.services.edges { + nodes_to_prompt.push(PluginOrService::Service(service.node.clone())); } - prompt_select("Select a plugin", plugins) - .context("No plugin selected")? - .0 - } - }; + + if nodes_to_prompt.is_empty() { + return Err(RailwayError::ProjectHasNoServicesOrPlugins.into()); + } + + prompt_select("Select service", nodes_to_prompt).context("No service selected") + })?; let environment_id = get_matched_environment(&project, environment)?.id; - let variables = get_plugin_variables( + let variables = get_plugin_or_service_variables( &client, &configs, linked_project.project, - environment_id, - plugin.id.clone(), + environment_id.clone(), + &plugin_or_service, ) .await?; + let plugin_type = plugin_or_service + .get_plugin_type(environment_id) + .ok_or_else(|| RailwayError::UnknownDatabaseType(plugin_or_service.get_name()))?; + + let (cmd_name, args) = get_connect_command(plugin_type, variables)?; + + if which(cmd_name.clone()).is_err() { + bail!("{} must be installed to continue", cmd_name); + } + + Command::new(cmd_name.as_str()) + .args(args) + .spawn()? + .wait() + .await?; + + Ok(()) +} + +impl PluginOrService { + pub fn get_name(&self) -> String { + match self { + PluginOrService::Plugin(plugin) => plugin.friendly_name.clone(), + PluginOrService::Service(service) => service.name.clone(), + } + } + + pub fn get_plugin_type(&self, environment_id: String) -> Option { + match self { + PluginOrService::Plugin(plugin) => Some(plugin.name.clone()), + PluginOrService::Service(service) => { + let service_instance = service + .service_instances + .edges + .iter() + .find(|si| si.node.environment_id == environment_id); + + service_instance + .and_then(|si| si.node.source.clone()) + .and_then(|source| source.image) + .map(|image: String| image.to_lowercase()) + .and_then(|image: String| { + if image.contains("postgres") { + Some(PluginType::postgresql) + } else if image.contains("redis") { + Some(PluginType::redis) + } else if image.contains("mongo") { + Some(PluginType::mongodb) + } else if image.contains("mysql") { + Some(PluginType::mysql) + } else { + None + } + }) + } + } + } +} + +fn get_connect_command( + plugin_type: PluginType, + variables: BTreeMap, +) -> Result<(String, Vec)> { let pass_arg; // Hack to get ownership of formatted string outside match let default = &"".to_string(); - let (cmd_name, args): (&str, Vec<&str>) = match &plugin.name { + + let (cmd_name, args): (&str, Vec<&str>) = match &plugin_type { PluginType::postgresql => ( "psql", vec![variables.get("DATABASE_URL").unwrap_or(default)], @@ -104,11 +176,8 @@ pub async fn command(args: Args, _json: bool) -> Result<()> { PluginType::Other(o) => bail!("Unsupported plugin type {}", o), }; - if which(cmd_name).is_err() { - bail!("{} must be installed to continue", cmd_name); - } - - Command::new(cmd_name).args(args).spawn()?.wait().await?; - - Ok(()) + Ok(( + cmd_name.to_string(), + args.iter().map(|s| s.to_string()).collect(), + )) } diff --git a/src/controllers/project.rs b/src/controllers/project.rs index a6d38ac44..21ba13c08 100644 --- a/src/controllers/project.rs +++ b/src/controllers/project.rs @@ -3,12 +3,22 @@ use reqwest::Client; use crate::{ client::post_graphql, commands::{ - queries::{self}, + queries::{ + self, + project::{ + ProjectProject, ProjectProjectPluginsEdgesNode, ProjectProjectServicesEdgesNode, + }, + }, Configs, }, errors::RailwayError, }; -use anyhow::Result; +use anyhow::{bail, Result}; + +pub enum PluginOrService { + Plugin(ProjectProjectPluginsEdgesNode), + Service(ProjectProjectServicesEdgesNode), +} pub async fn get_project( client: &Client, @@ -32,3 +42,30 @@ pub async fn get_project( Ok(project) } + +pub fn get_plugin_or_service( + project: &ProjectProject, + service_or_plugin_name: String, +) -> Result { + let service = project + .services + .edges + .iter() + .find(|edge| edge.node.name.to_lowercase() == service_or_plugin_name); + + let plugin = project + .plugins + .edges + .iter() + .find(|edge| edge.node.friendly_name.to_lowercase() == service_or_plugin_name); + + if let Some(service) = service { + return Ok(PluginOrService::Service(service.node.clone())); + } else if let Some(plugin) = plugin { + return Ok(PluginOrService::Plugin(plugin.node.clone())); + } + + bail!(RailwayError::ServiceOrPluginNotFound( + service_or_plugin_name + )) +} diff --git a/src/controllers/variables.rs b/src/controllers/variables.rs index 5a7246a4e..fa7a24d98 100644 --- a/src/controllers/variables.rs +++ b/src/controllers/variables.rs @@ -6,6 +6,8 @@ use anyhow::Result; use reqwest::Client; use std::collections::BTreeMap; +use super::project::PluginOrService; + pub async fn get_service_variables( client: &Client, configs: &Configs, @@ -71,3 +73,42 @@ pub async fn get_plugin_variables( Ok(variables) } + +pub async fn get_plugin_or_service_variables( + client: &Client, + configs: &Configs, + project_id: String, + environment_id: String, + plugin_or_service: &PluginOrService, +) -> Result> { + let variables = match plugin_or_service { + PluginOrService::Plugin(plugin) => { + let query = queries::variables_for_plugin::Variables { + project_id: project_id.clone(), + environment_id: environment_id.clone(), + plugin_id: plugin.id.clone(), + }; + + post_graphql::(client, configs.get_backboard(), query) + .await? + .variables + } + PluginOrService::Service(service) => { + let query = queries::variables_for_service_deployment::Variables { + project_id: project_id.clone(), + environment_id: environment_id.clone(), + service_id: service.id.clone(), + }; + + post_graphql::( + client, + configs.get_backboard(), + query, + ) + .await? + .variables_for_service_deployment + } + }; + + Ok(variables) +} diff --git a/src/errors.rs b/src/errors.rs index b382751a0..eceba63ed 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -41,8 +41,11 @@ pub enum RailwayError { #[error("Service \"{0}\" not found.\nRun `railway service` to connect to a service.")] ServiceNotFound(String), - #[error("Project has no plugins.\nRun `railway add` to add a plugin.")] - ProjectHasNoPlugins, + #[error("Service or plugin \"{0}\" not found.")] + ServiceOrPluginNotFound(String), + + #[error("Project has no services or plugins.")] + ProjectHasNoServicesOrPlugins, #[error("No service linked and no plugins found\nRun `railway service` to link a service")] NoServiceLinked, @@ -55,4 +58,7 @@ pub enum RailwayError { #[error("{0}")] FailedToUpload(String), + + #[error("Could not determine database type for service {0}")] + UnknownDatabaseType(String), } diff --git a/src/gql/queries/strings/Project.graphql b/src/gql/queries/strings/Project.graphql index 538267aa2..8191c6dd8 100644 --- a/src/gql/queries/strings/Project.graphql +++ b/src/gql/queries/strings/Project.graphql @@ -24,6 +24,20 @@ query Project($id: String!) { node { id name + + serviceInstances { + edges { + node { + id + serviceId + environmentId + source { + repo + image + } + } + } + } } } } diff --git a/src/gql/schema.graphql b/src/gql/schema.graphql index 23c773df4..e08d8c0e7 100644 --- a/src/gql/schema.graphql +++ b/src/gql/schema.graphql @@ -2,13 +2,30 @@ type AccessRule { disallowed: String } -""" -The aggregated usage of a single measurement. -""" +enum ActiveFeatureFlag { + GITHUB_REPO_FROM_URL + NEW_DASHBOARD_UI +} + +input AdminDeploymentListInput { + filter: String + status: DeploymentStatus +} + +type AdminStats { + deploysFailedLastHour: Int! + deploysInProgressHour: Int! + deploysSuccessfulLastHour: Int! + latestDeploys: [Deployment!]! + latestTeams: [Team!]! + numSubscribed: Int! + numTeams: Int! + totalPlatformUsage: TotalUsage +} + +"""The aggregated usage of a single measurement.""" type AggregatedUsage { - """ - The measurement that was aggregated. - """ + """The measurement that was aggregated.""" measurement: MetricMeasurement! """ @@ -16,9 +33,7 @@ type AggregatedUsage { """ tags: MetricTags! - """ - The aggregated value. - """ + """The aggregated value.""" value: Float! } @@ -55,9 +70,7 @@ The `BigInt` scalar type represents non-fractional signed whole numeric values. """ scalar BigInt -""" -The billing period for a customers subscription. -""" +"""The billing period for a customers subscription.""" type BillingPeriod { end: DateTime! start: DateTime! @@ -91,6 +104,35 @@ enum CertificateStatus { UNRECOGNIZED } +input ChangelogSendInput { + changelogId: String! + changelogSlug: String! + changelogTitle: String! + isTestEmail: Boolean! +} + +""" +[Experimental] A changeset represents a single change to a service, plugin or variable. +""" +type Changeset implements Node { + createdAt: DateTime! + id: ID! + mergedFrom: Environment + payload: JSON! + plugin: Plugin + service: Service + user: User +} + +""" +[Experimental] An accumulated set of changes calculated from comparing two environments. +""" +type ChangesetDiff { + payload: JSON! + plugin: Plugin + service: Service +} + type CnameCheck { link: String message: String! @@ -105,6 +147,39 @@ enum CnameCheckStatus { WAITING } +type CompositeScore { + accountScore: Float! + clashingSessionsScore: Float! + compositeScore: Float! + contributionsScore: Float! + flaggedRepos: [String!]! + networkScore: Float! + profileScore: Float! + repoScore: Float! + totalRepos: Int! +} + +type Container implements Node { + createdAt: DateTime! + deletedAt: DateTime + environmentId: String! + id: ID! + pluginId: String! +} + +type ContainerInfo { + host: String! + id: String! + image: String! + labels: [ContainerLabel!]! + status: String! +} + +type ContainerLabel { + key: String! + value: String! +} + type Credit implements Node { amount: Float! createdAt: DateTime! @@ -120,16 +195,18 @@ enum CreditType { CREDIT DEBIT STRIPE + WAIVED } type CustomDomain implements Domain { - cnameCheck: CnameCheck! + cnameCheck: CnameCheck! @deprecated(reason: "Use the `status` field instead.") createdAt: DateTime deletedAt: DateTime domain: String! environmentId: String! id: ID! serviceId: String! + status: CustomDomainStatus! updatedAt: DateTime } @@ -139,31 +216,53 @@ input CustomDomainCreateInput { serviceId: String! } +type CustomDomainStatus { + cdnProvider: CDNProvider + certificateStatus: CertificateStatus! + certificates: [CertificatePublicData!] + dnsRecords: [DNSRecords!]! +} + type Customer implements Node { appliedCredits: Float! billingEmail: String billingPeriod: BillingPeriod! creditBalance: Float! - credits( - after: String - before: String - first: Int - last: Int - ): CustomerCreditsConnection! + credits(after: String, before: String, first: Int, last: Int): CustomerCreditsConnection! defaultPaymentMethod: PaymentMethod defaultPaymentMethodId: String id: ID! invoices: [CustomerInvoice!]! + isPrepaying: Boolean! + isTrialing: Boolean! isUsageSubscriber: Boolean! remainingUsageCreditBalance: Float! state: SubscriptionState! stripeCustomerId: String! subscriptions: [CustomerSubscription!]! teamId: String - usageLimit: Float + usageLimit: UsageLimit userId: String } +input CustomerApplyCreditInput { + amountDollars: Int! + memo: String +} + +input CustomerAttachPaymentMethodInput { + paymentMethodId: String! + validateWithHold: Boolean +} + +input CustomerCreateBillingPortalInput { + redirectUrl: String! +} + +input CustomerCreateUsageSubscriptionInput { + paymentMethodId: String +} + type CustomerCreditsConnection { edges: [CustomerCreditsConnectionEdge!]! pageInfo: PageInfo! @@ -188,10 +287,22 @@ type CustomerInvoice { total: Int! } +input CustomerPurchaseCreditsInput { + amountDollars: Int! + paymentMethodId: String +} + +input CustomerRetryInvoiceInput { + invoiceId: String! + paymentMethodId: String! +} + type CustomerSubscription { billingCycleAnchor: DateTime! cancelAt: String + cancelAtPeriodEnd: Boolean! couponId: String + discounts: [SubscriptionDiscount!]! id: String! items: [SubscriptionItem!]! latestInvoiceId: String! @@ -200,6 +311,10 @@ type CustomerSubscription { status: String! } +input CustomerUpdateBillingEmailInput { + email: String! +} + enum DNSRecordPurpose { DNS_RECORD_PURPOSE_ACME_DNS01_CHALLENGE DNS_RECORD_PURPOSE_TRAFFIC_ROUTE @@ -239,6 +354,7 @@ A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the `dat scalar DateTime type Deployment implements Node { + canRedeploy: Boolean! canRollback: Boolean! createdAt: DateTime! creator: User @@ -249,12 +365,19 @@ type Deployment implements Node { projectId: String! service: Service! serviceId: String + snapshotId: String staticUrl: String status: DeploymentStatus! suggestAddServiceDomain: Boolean! url: String } +type DeploymentByDomain { + activeDeployment: Deployment + latestDeployment: Deployment + projectId: String +} + input DeploymentListInput { environmentId: String includeDeleted: Boolean @@ -277,6 +400,7 @@ enum DeploymentStatus { DEPLOYING FAILED INITIALIZING + QUEUED REMOVED REMOVING SKIPPED @@ -320,6 +444,10 @@ input DeploymentTriggerUpdateInput { rootDirectory: String } +type DiscordServerInfo { + presenceCount: String +} + interface Domain { createdAt: DateTime deletedAt: DateTime @@ -344,44 +472,35 @@ type DomainWithStatus { } type Environment implements Node { + """ + [Experimental] Returns the diff between this environment and its parent one. + """ + changes: [ChangesetDiff!]! createdAt: DateTime! deletedAt: DateTime - deploymentTriggers( - after: String - before: String - first: Int - last: Int - ): EnvironmentDeploymentTriggersConnection! - deployments( - after: String - before: String - first: Int - last: Int - ): EnvironmentDeploymentsConnection! + deploymentTriggers(after: String, before: String, first: Int, last: Int): EnvironmentDeploymentTriggersConnection! + deployments(after: String, before: String, first: Int, last: Int): EnvironmentDeploymentsConnection! id: ID! isEphemeral: Boolean! meta: EnvironmentMeta name: String! projectId: String! - serviceInstances( - after: String - before: String - first: Int - last: Int - ): EnvironmentServiceInstancesConnection! + serviceInstances(after: String, before: String, first: Int, last: Int): EnvironmentServiceInstancesConnection! + sourceEnvironment: Environment + unmergedChangesCount: Int updatedAt: DateTime! - variables( - after: String - before: String - first: Int - last: Int - ): EnvironmentVariablesConnection! + variables(after: String, before: String, first: Int, last: Int): EnvironmentVariablesConnection! } input EnvironmentCreateInput { ephemeral: Boolean name: String! projectId: String! + + """ + [Experimental] Specifying this field will create a new environment that is a fork of the specified environment. Changes made to forked environments will not affect other environments, and vice versa. + """ + sourceEnvironmentId: String } type EnvironmentDeploymentTriggersConnection { @@ -438,18 +557,12 @@ type EnvironmentVariablesConnectionEdge { node: Variable! } -""" -The estimated usage of a single measurement. -""" +"""The estimated usage of a single measurement.""" type EstimatedUsage { - """ - The estimated value. - """ + """The estimated value.""" estimatedValue: Float! - """ - The measurement that was estimated. - """ + """The measurement that was estimated.""" measurement: MetricMeasurement! projectId: String! } @@ -478,31 +591,31 @@ input EventTrackInput { ts: String! } -type ExecutionTime { - projectId: String! - - """ - The total number of minutes that the project has been actively running for. - """ - totalTimeMinutes: Float! -} - input ExplicitOwnerInput { - """ - The ID of the owner - """ + """The ID of the owner""" id: String! - """ - The type of owner - """ + """The type of owner""" type: ResourceOwnerType! } +input FeatureFlagAddInput { + flag: ActiveFeatureFlag! +} + +input FeatureFlagRemoveInput { + flag: ActiveFeatureFlag! +} + type GitHubBranch { name: String! } +type GitHubEvent { + createdAt: DateTime + type: String! +} + type GitHubRepo { defaultBranch: String! fullName: String! @@ -512,12 +625,30 @@ type GitHubRepo { name: String! } +input GitHubRepoDeployInput { + projectId: String! + repo: String! +} + input GitHubRepoUpdateInput { environmentId: String! projectId: String! serviceId: String! } +input GroupedUsageAnomaliesInput { + filters: GroupedUsageAnomaliesInputFilters! +} + +input GroupedUsageAnomaliesInputFilters { + needsAction: Boolean! +} + +type GroupedUsageAnomaly { + anomalies: [UsageAnomaly!]! + service: Service! +} + type HerokuApp { id: String! name: String! @@ -553,12 +684,7 @@ type Integration implements Node { type IntegrationAuth implements Node { id: ID! - integrations( - after: String - before: String - first: Int - last: Int - ): IntegrationAuthIntegrationsConnection! + integrations(after: String, before: String, first: Int, last: Int): IntegrationAuthIntegrationsConnection! provider: String! providerId: String! } @@ -617,37 +743,91 @@ enum KeyType { UNRECOGNIZED } +type LockdownStatus { + allProvisionsDisabledMsg: String + anonProvisionsDisabledMsg: String + freeProvisionsDisabledMsg: String + nonProProvisionsDisabledMsg: String + signupsDisabledMsg: String +} + +"""The result of a logs query.""" type Log { + """The attributes that were parsed from a structured log""" + attributes: [LogAttribute!]! + + """The contents of the log message""" message: String! + + """The severity of the log message (eg. err)""" severity: String + + """The tags that were associated with the log""" + tags: LogTags + + """The timestamp of the log message in format RFC3339 (nano)""" timestamp: String! } +"""The attributes associated with a structured log""" +type LogAttribute { + key: String! + value: String! +} + +"""The tags associated with a specific log""" +type LogTags { + deploymentId: String + deploymentInstanceId: String + environmentId: String + pluginId: String + projectId: String + serviceId: String + snapshotId: String +} + input LoginSessionAuthInput { code: String! hostname: String } -""" -A single sample of a metric. -""" +type Maintenance { + id: String! + message: String! + status: MaintenanceStatus! + url: String! +} + +enum MaintenanceStatus { + COMPLETED + INPROGRESS + NOTSTARTEDYET +} + +input MergeChange { + action: String! + name: String! + serviceId: String + type: String! + value: String! +} + +"""A single sample of a metric.""" type Metric { """ The timestamp of the sample. Represented has number of seconds since the Unix epoch. """ ts: Int! - """ - The value of the sample. - """ + """The value of the sample.""" value: Float! } -""" -A thing that can be measured on Railway. -""" +"""A thing that can be measured on Railway.""" enum MetricMeasurement { CPU_USAGE + DISK_USAGE_GB + EPHEMERAL_DISK_USAGE_GB MEASUREMENT_UNSPECIFIED MEMORY_USAGE_GB NETWORK_RX_GB @@ -655,37 +835,32 @@ enum MetricMeasurement { UNRECOGNIZED } -""" -A property that can be used to group metrics. -""" +"""A property that can be used to group metrics.""" enum MetricTag { DEPLOYMENT_ID + DEPLOYMENT_INSTANCE_ID ENVIRONMENT_ID KEY_UNSPECIFIED PLUGIN_ID PROJECT_ID SERVICE_ID UNRECOGNIZED + VOLUME_ID } -""" -The tags that were used to group the metric. -""" +"""The tags that were used to group the metric.""" type MetricTags { deploymentId: String environmentId: String pluginId: String projectId: String serviceId: String + volumeId: String } -""" -The result of a metrics query. -""" +"""The result of a metrics query.""" type MetricsResult { - """ - The measurement of the metric. - """ + """The measurement of the metric.""" measurement: MetricMeasurement! """ @@ -693,9 +868,7 @@ type MetricsResult { """ tags: MetricTags! - """ - The samples of the metric. - """ + """The samples of the metric.""" values: [Metric!]! } @@ -704,123 +877,133 @@ input MissingCommandAlertInput { text: String! } +"""A collection belonging to a MongoDB database""" +type MongoCollection { + data: JSON! + name: String! +} + type Mutation { - """ - Creates a new API token. - """ + """Delete the user with the provided userId""" + adminDelete(userId: String!): Boolean! + + """Creates a new API token.""" apiTokenCreate(input: ApiTokenCreateInput!): String! - """ - Deletes an API token. - """ + """Deletes an API token.""" apiTokenDelete(id: String!): Boolean! - """ - Sets the base environment override for a deployment trigger. - """ - baseEnvironmentOverride( - id: String! - input: BaseEnvironmentOverrideInput! - ): Boolean! + """Sets the base environment override for a deployment trigger.""" + baseEnvironmentOverride(id: String!, input: BaseEnvironmentOverrideInput!): Boolean! - """ - Creates a new custom domain. - """ + """Triggers an email with the changelog for the provided slug""" + changelogSend(input: ChangelogSendInput!): Boolean! + + """Creates a new refund support request""" + createRefundRequest(input: RefundFormInput!): Boolean! + + """Creates a new Talk To An Engineer support request""" + createTalkToAnEngineerRequest(input: TalkToAnEngineerFormInput!): Boolean! + + """Creates a new custom domain.""" customDomainCreate(input: CustomDomainCreateInput!): CustomDomain! - """ - Deletes a custom domain. - """ + """Deletes a custom domain.""" customDomainDelete(id: String!): Boolean! - """ - Cancels a deployment. - """ + """Issues a new certificate""" + customDomainIssueCertificate(id: String!): Boolean! + + """Apply a credit to a customer""" + customerApplyCredit(id: String!, input: CustomerApplyCreditInput!): Boolean! + + """Attach a payment method to a customer""" + customerAttachPaymentMethod(id: String!, input: CustomerAttachPaymentMethodInput!): JSON! + + """Create a Stripe billing portal for a customer""" + customerCreateBillingPortal(id: String!, input: CustomerCreateBillingPortalInput!): String! + + """Create a usage based subscription for a customer""" + customerCreateUsageSubscription(id: String!, input: CustomerCreateUsageSubscriptionInput!): JSON! + + """Migrate a customer to the hobby plan""" + customerMigrateToHobbyPlan(id: String!): Boolean! + + """Purchase credits for a Railway customer""" + customerPurchaseCredits(id: String!, input: CustomerPurchaseCreditsInput!): JSON! + + """Report all usage for a customer and the current billing period""" + customerReportUsage(customerId: String!): JSON! + + """Retry an invoice for a customer with a new payment method""" + customerRetryInvoice(id: String!, input: CustomerRetryInvoiceInput!): JSON! + + """Update a customer's billing email""" + customerUpdateBillingEmail(id: String!, input: CustomerUpdateBillingEmailInput!): Customer! + + """Cancels a deployment.""" deploymentCancel(id: String!): Boolean! - """ - Redeploys a deployment. - """ + """Redeploys a deployment.""" deploymentRedeploy(id: String!): Deployment! - """ - Removes a deployment. - """ + """Removes a deployment.""" deploymentRemove(id: String!): Boolean! - """ - Restarts a deployment. - """ + """Restarts a deployment.""" deploymentRestart(id: String!): Boolean! - """ - Rolls back to a deployment. - """ + """Rolls back to a deployment.""" deploymentRollback(id: String!): Boolean! - """ - Creates a deployment trigger. - """ - deploymentTriggerCreate( - input: DeploymentTriggerCreateInput! - ): DeploymentTrigger! + """Creates a deployment trigger.""" + deploymentTriggerCreate(input: DeploymentTriggerCreateInput!): DeploymentTrigger! - """ - Deletes a deployment trigger. - """ + """Deletes a deployment trigger.""" deploymentTriggerDelete(id: String!): Boolean! - """ - Updates a deployment trigger. - """ - deploymentTriggerUpdate( - id: String! - input: DeploymentTriggerUpdateInput! - ): DeploymentTrigger! + """Updates a deployment trigger.""" + deploymentTriggerUpdate(id: String!, input: DeploymentTriggerUpdateInput!): DeploymentTrigger! """ Change the User's account email if there is a valid change email request. """ emailChangeConfirm(nonce: String!): Boolean! - """ - Initiate an email change request for a user - """ + """Initiate an email change request for a user""" emailChangeInitiate(newEmail: String!): Boolean! - """ - Creates a new environment. - """ + """Creates a new environment.""" environmentCreate(input: EnvironmentCreateInput!): Environment! - """ - Deletes an environment. - """ + """Deletes an environment.""" environmentDelete(id: String!): Boolean! - """ - Deploys all connected triggers for an environment. - """ + """[Experimental] Merges the current environment with the parent one.""" + environmentMerge(changes: [MergeChange!], id: String!): Boolean! + + """Deploys all connected triggers for an environment.""" environmentTriggersDeploy(input: EnvironmentTriggersDeployInput!): Boolean! - """ - Track a batch of events for authenticated user - """ + """Track a batch of events for authenticated user""" eventBatchTrack(input: EventBatchTrackInput!): Boolean! - """ - Track event for authenticated user - """ + """Track event for authenticated user""" eventTrack(input: EventTrackInput!): Boolean! - """ - Agree to the fair use policy for the currently authenticated user - """ + """Agree to the fair use policy for the currently authenticated user""" fairUseAgree(agree: Boolean!): Boolean! - """ - Updates a GitHub repo through the linked template - """ + """Add a feature flag for a user""" + featureFlagAdd(input: FeatureFlagAddInput!): Boolean! + + """Remove a feature flag for a user""" + featureFlagRemove(input: FeatureFlagRemoveInput!): Boolean! + + """Deploys a GitHub repo""" + githubRepoDeploy(input: GitHubRepoDeployInput!): Boolean! + + """Updates a GitHub repo through the linked template""" githubRepoUpdate(input: GitHubRepoUpdateInput!): Boolean! """ @@ -828,443 +1011,472 @@ type Mutation { """ herokuImportVariables(input: HerokuImportVariablesInput!): Int! - """ - Create an integration for a project - """ + """Create an integration for a project""" integrationCreate(input: IntegrationCreateInput!): Integration! - """ - Delete an integration for a project - """ + """Delete an integration for a project""" integrationDelete(id: String!): Boolean! - """ - Update an integration for a project - """ + """Update an integration for a project""" integrationUpdate(id: String!, input: IntegrationUpdateInput!): Integration! - """ - Join a project using an invite code - """ + """Join a project using an invite code""" inviteCodeUse(code: String!): Project! - """ - Creates a new job application. - """ + """Creates a new job application.""" jobApplicationCreate(input: JobApplicationCreateInput!): Boolean! - """ - Auth a login session for a user - """ + """Auth a login session for a user""" loginSessionAuth(input: LoginSessionAuthInput!): Boolean! - """ - Cancel a login session - """ + """Cancel a login session""" loginSessionCancel(code: String!): Boolean! - """ - Get a token for a login session if it exists - """ + """Get a token for a login session if it exists""" loginSessionConsume(code: String!): String - """ - Start a CLI login session - """ + """Start a CLI login session""" loginSessionCreate: String! - """ - Verify if a login session is valid - """ + """Verify if a login session is valid""" loginSessionVerify(code: String!): Boolean! - """ - Deletes session for current user if it exists - """ + """Deletes session for current user if it exists""" logout: Boolean! - """ - Alert the team of a missing command palette command - """ + """Alert the team of a missing command palette command""" missingCommandAlert(input: MissingCommandAlertInput!): Boolean! - """ - Creates a new plugin. - """ + """Delete an entire collection from a MongoDB container""" + mongoDeleteCollection(database: String!, environmentId: String!, name: String!, pluginId: String, serviceId: String): Boolean! + + """Delete an entire collection from a MongoDB container""" + mongoDeleteDocument(database: String!, environmentId: String!, id: String!, name: String!, pluginId: String, serviceId: String): Boolean! + + """Generate dummy data for a MongoDB container""" + mongoDummyData(database: String!, environmentId: String!, pluginId: String, serviceId: String): Boolean! + + """Insert a document into a MongoDB container""" + mongoInsertDocument(data: JSON!, database: String!, environmentId: String!, name: String!, pluginId: String, serviceId: String): String! + + """Update a document in a MongoDB container""" + mongoUpdateDocument(data: JSON!, database: String!, environmentId: String!, id: String!, name: String!, pluginId: String, serviceId: String): Boolean! + + """Toggles the specified platform service on or off.""" + platformServiceToggle(input: TogglePlatformServiceInput!): Boolean! + + """Creates a new plugin.""" pluginCreate(input: PluginCreateInput!): Plugin! - """ - Deletes a plugin. - """ - pluginDelete(id: String!): Boolean! + """Deletes a plugin.""" + pluginDelete(environmentId: String, id: String!): Boolean! - """ - Reset envs and container for a plugin in an environment - """ + """Reset envs and container for a plugin in an environment""" pluginReset(id: String!, input: ResetPluginInput!): Boolean! - """ - Resets the credentials for a plugin in an environment - """ - pluginResetCredentials( - id: String! - input: ResetPluginCredentialsInput! - ): String! + """Resets the credentials for a plugin in an environment""" + pluginResetCredentials(id: String!, input: ResetPluginCredentialsInput!): String! - """ - Restarts a plugin. - """ + """Restarts a plugin.""" pluginRestart(id: String!, input: PluginRestartInput!): Plugin! - """ - Updates an existing plugin. - """ + """Force start a plugin""" + pluginStart(id: String!, input: PluginRestartInput!): Boolean! + + """Updates an existing plugin.""" pluginUpdate(id: String!, input: PluginUpdateInput!): Plugin! - """ - Update the email preferences for a user - """ + """Update the email preferences for a user""" preferencesUpdate(input: PreferencesUpdateData!): Preferences! - """ - Claims a project. - """ + """Create or get a private network.""" + privateNetworkCreateOrGet(input: PrivateNetworkCreateOrGetInput!): PrivateNetwork! + + """Create or get a private network endpoint.""" + privateNetworkEndpointCreateOrGet(input: PrivateNetworkEndpointCreateOrGetInput!): PrivateNetworkEndpoint! + + """Delete a private network endpoint.""" + privateNetworkEndpointDelete(id: String!): Boolean! + + """Rename a private network endpoint.""" + privateNetworkEndpointRename(dnsName: String!, id: String!, privateNetworkId: String!): Boolean! + + """Delete all private networks for an environment.""" + privateNetworksForEnvironmentDelete(environmentId: String!): Boolean! + + """Claims a project.""" projectClaim(id: String!): Project! - """ - Creates a new project. - """ + """Creates a new project.""" projectCreate(input: ProjectCreateInput!): Project! - """ - Deletes a project. - """ + """Deletes a project.""" projectDelete(id: String!): Boolean! - """ - Invite a user by email to a project - """ + """Invite a user by email to a project""" projectInviteUser(id: String!, input: ProjectInviteUserInput!): Boolean! - """ - Leave project as currently authenticated user - """ + """Leave project as currently authenticated user""" projectLeave(id: String!): Boolean! - """ - Remove user from a project - """ + """Remove user from a project""" projectMemberRemove(input: ProjectMemberRemoveInput!): [ProjectMember!]! - """ - Change the role for a user within a project - """ + """Change the role for a user within a project""" projectMemberUpdate(input: ProjectMemberUpdateInput!): ProjectMember! - """ - Create a token for a project that has access to a specific environment - """ + """Create a token for a project that has access to a specific environment""" projectTokenCreate(input: ProjectTokenCreateInput!): String! - """ - Delete a project token - """ + """Delete a project token""" projectTokenDelete(id: String!): Boolean! - """ - Confirm the transfer of project ownership - """ + """Confirm the transfer of project ownership""" projectTransferConfirm(input: ProjectTransferConfirmInput!): Boolean! - """ - Initiate the transfer of project ownership - """ + """Initiate the transfer of project ownership""" projectTransferInitiate(input: ProjectTransferInitiateInput!): Boolean! - """ - Transfer a project to a team - """ - projectTransferToTeam( - id: String! - input: ProjectTransferToTeamInput! - ): Boolean! + """Transfer a project to a team""" + projectTransferToTeam(id: String!, input: ProjectTransferToTeamInput!): Boolean! - """ - Transfer a project to a user - """ + """Transfer a project to a user""" projectTransferToUser(id: String!): Boolean! - """ - Updates a project. - """ + """Updates a project.""" projectUpdate(id: String!, input: ProjectUpdateInput!): Project! - """ - Deletes a ProviderAuth. - """ + """Deletes a ProviderAuth.""" providerAuthRemove(id: String!): Boolean! - """ - Generates a new set of recovery codes for the authenticated user. - """ + """Generates a new set of recovery codes for the authenticated user.""" recoveryCodeGenerate: RecoveryCodes! - """ - Validates a recovery code. - """ + """Validates a recovery code.""" recoveryCodeValidate(input: RecoveryCodeValidateInput!): Boolean! - """ - Updates the ReferralInfo for the authenticated user. - """ + """Delete a key in a Redis container""" + redisDeleteKey(environmentId: String!, key: String!, pluginId: String, serviceId: String): Boolean! + + """Generate dummy data for a Redis container""" + redisDummyData(environmentId: String!, pluginId: String, serviceId: String): Boolean! + + """Delete values to a hash in a Redis container""" + redisHashDelete(environmentId: String!, key: String!, pluginId: String, serviceId: String, values: [String!]!): Boolean! + + """Add values to a hash in a Redis container""" + redisHashSet(environmentId: String!, key: String!, pluginId: String, serviceId: String, values: JSON!): Boolean! + + """Pop a value from a list in a Redis container""" + redisPopList(environmentId: String!, key: String!, pluginId: String, serviceId: String, side: String!): Boolean! + + """Push a value to a list in a Redis container""" + redisPushList(environmentId: String!, key: String!, pluginId: String, serviceId: String, side: String!, values: [String!]!): Boolean! + + """Add a value from a set in a Redis container""" + redisSetAdd(environmentId: String!, key: String!, pluginId: String, serviceId: String, values: [String!]!): Boolean! + + """Set a keys expire time in seconds in a Redis container""" + redisSetExpire(environmentId: String!, key: String!, pluginId: String, serviceId: String, ttl: BigInt!): Boolean! + + """Set list index to a value Redis container""" + redisSetListIndex(environmentId: String!, index: Int!, key: String!, pluginId: String, serviceId: String, value: String!): Boolean! + + """Remove a value from a set in a Redis container""" + redisSetRemove(environmentId: String!, key: String!, pluginId: String, serviceId: String, values: [String!]!): Boolean! + + """Set a string value in a Redis container""" + redisStringSet(environmentId: String!, key: String!, pluginId: String, serviceId: String, value: String!): Boolean! + + """Updates the ReferralInfo for the authenticated user.""" referralInfoUpdate(input: ReferralInfoUpdateInput!): ReferralInfo! - """ - Connect a service to a repo - """ + """Remove a cached GitHub access token.""" + removeCachedGitHubAccessToken(userId: String!): Boolean! + + """Connect a service to a source""" serviceConnect(id: String!, input: ServiceConnectInput!): Service! - """ - Creates a new service. - """ + """Creates a new service.""" serviceCreate(input: ServiceCreateInput!): Service! - """ - Deletes a service. - """ - serviceDelete(id: String!): Boolean! + """Deletes a service.""" + serviceDelete( + """ + [Experimental] Environment ID. If the environment is a forked environment, the service will only be deleted in the specified environment, otherwise it will deleted in all environments that are not forks of other environments + """ + environmentId: String + id: String! + ): Boolean! - """ - Disconnect a service from a repo - """ + """Disconnect a service from a repo""" serviceDisconnect(id: String!): Service! - """ - Creates a new service domain. - """ + """Creates a new service domain.""" serviceDomainCreate(input: ServiceDomainCreateInput!): ServiceDomain! - """ - Deletes a service domain. - """ + """Deletes a service domain.""" serviceDomainDelete(id: String!): Boolean! - """ - Updates a service domain. - """ + """Updates a service domain.""" serviceDomainUpdate(input: ServiceDomainUpdateInput!): Boolean! - """ - Redeploy a service instance - """ + """Redeploy a service instance""" serviceInstanceRedeploy(environmentId: String!, serviceId: String!): Boolean! - """ - Update a service instance - """ + """Get a list of suggested variables for a services repo""" + serviceInstanceSuggestedVariables(environmentId: String!, serviceId: String!): JSON! + + """Update a service instance""" serviceInstanceUpdate( + """ + [Experimental] Environment ID. If the environment is a fork, the service will only be updated in it. Otherwise it will updated in all environments that are not forks of other environments + """ + environmentId: String input: ServiceInstanceUpdateInput! serviceId: String! ): Boolean! - """ - Remove the upstream URL from all service instances for this service - """ + """Remove the upstream URL from all service instances for this service""" serviceRemoveUpstreamUrl(id: String!): Service! - """ - Updates a service. - """ + """Updates a service.""" serviceUpdate(id: String!, input: ServiceUpdateInput!): Service! - """ - Deletes a session. - """ + """Deletes a session.""" sessionDelete(id: String!): Boolean! - """ - Configure a shared variable. - """ + """Configure a shared variable.""" sharedVariableConfigure(input: SharedVariableConfigureInput!): Variable! - """ - Creates a support request. - """ - supportRequest(input: SupportRequestInput!): Boolean! + """Insert a column in a table in a SQL database container""" + sqlColumnInsert(column: SQLColumnInput!, databaseType: String!, environmentId: String!, pluginId: String, serviceId: String, tableName: String!): Boolean! - """ - Create a team - """ + """Generate dummy data for a SQL database container""" + sqlDummyData(databaseType: String!, environmentId: String!, pluginId: String, serviceId: String): Boolean! + + """Run the raw SQL query provided by the user""" + sqlRawQueryRun(databaseType: String!, environmentId: String!, pluginId: String, query: String!, serviceId: String): SQLRawQueryResponse! + + """Insert a row into a SQL database container""" + sqlRowInsert(columns: [SQLRowInput!]!, databaseType: String!, environmentId: String!, pluginId: String, serviceId: String, tableName: String!): Boolean! + + """Update row in a table in a SQL database container""" + sqlRowUpdate(data: JSON!, databaseType: String!, environmentId: String!, pKey: String!, pKeyValue: String!, pluginId: String, serviceId: String, tableName: String!): Boolean! + + """Delete rows from a table in a SQL database container""" + sqlRowsDelete(columnName: String!, databaseType: String!, environmentId: String!, pluginId: String, rows: [String!]!, serviceId: String, tableName: String!): Boolean! + + """Create a table in a SQL database container""" + sqlTableCreate(columns: [SQLColumnInput!]!, databaseType: String!, environmentId: String!, name: String!, pluginId: String, serviceId: String): Boolean! + + """Delete a table in a SQL database container""" + sqlTableDelete(databaseType: String!, environmentId: String!, name: String!, pluginId: String, serviceId: String): Boolean! + + """Creates a new TCP proxy for a service instance.""" + tcpProxyCreate(input: TCPProxyCreateInput!): TCPProxy! + + """Deletes a TCP proxy by id""" + tcpProxyDelete(id: String!): Boolean! + + """Ban a team.""" + teamBan(id: String!, input: TeamBanInput!): Boolean! + + """Bulk transfer projects from user to team""" + teamBulkProjectTransfer(input: TeamBulkProjectTransferInput!): Boolean! + + """Create a team""" teamCreate(input: TeamCreateInput!): Team! - """ - Delete a team and all data associated with it - """ + """Create a team and subscribe to the Pro plan""" + teamCreateAndSubscribe(input: TeamCreateAndSubscribeInput!): TeamCreateAndSubscribeResponse! + + """Delete a team and all data associated with it""" teamDelete(id: String!): Boolean! - """ - Get an invite code for a team and role - """ + """Get an invite code for a team and role""" teamInviteCodeCreate(id: String!, input: TeamInviteCodeCreateInput!): String! - """ - Use an invite code to join a team - """ + """Use an invite code to join a team""" teamInviteCodeUse(code: String!): Team! - """ - Leave a team - """ + """Leave a team""" teamLeave(id: String!): Boolean! - """ - Changes a user team permissions. - """ + """Changes a user team permissions.""" teamPermissionChange(input: TeamPermissionChangeInput!): Boolean! - """ - Update a team by id - """ + """Stop all deployments and plugins for a team.""" + teamResourcesStop(id: String!, input: TeamResourcesStopInput): Boolean! + + """Set Direct Support eligiblity for a team""" + teamSetIsEligibleForDirectSupport(isEligibleForDirectSupport: Boolean!, teamId: String!): Boolean! + + """Unban a team.""" + teamUnban(id: String!): Boolean! + + """Update a team by id""" teamUpdate(id: String!, input: TeamUpdateInput!): Team! - """ - Invite a user by email to a team - """ + """Invite a user by email to a team""" teamUserInvite(id: String!, input: TeamUserInviteInput!): Boolean! - """ - Remove a user from a team - """ + """Remove a user from a team""" teamUserRemove(id: String!, input: TeamUserRemoveInput!): Boolean! - """ - Logs panics from CLI to Datadog - """ + """Logs panics from CLI to Datadog""" telemetrySend(input: TelemetrySendInput!): Boolean! - """ - Creates a template. - """ + """Duplicates an existing template""" + templateClone(code: String!): Template! + + """Creates a template.""" templateCreate(input: TemplateCreateInput!): Template! - """ - Deletes a template. - """ + """Deletes a template.""" templateDelete(id: String!): Boolean! - """ - Deploys a template. - """ + """Deploys a template.""" templateDeploy(input: TemplateDeployInput!): TemplateDeployPayload! - """ - Generate a template for a project - """ + """Generate a template for a project""" templateGenerate(input: TemplateGenerateInput!): Template! - """ - Publishes a template. - """ + """Hides a template.""" + templateHide(id: String!): Boolean! + + """Backfill template kickback payouts.""" + templateKickbackBackfill(invoiceId: String!): Boolean! + + """Publishes a template.""" templatePublish(id: String!, input: TemplatePublishInput!): Template! - """ - Unpublishes a template. - """ + """Unpublishes a template.""" templateUnpublish(id: String!): Boolean! - """ - Updates a template. - """ + """Updates a template.""" templateUpdate(id: String!, input: TemplateUpdateInput!): Template! - """ - Setup 2FA authorization for authenticated user. - """ + """Setup 2FA authorization for authenticated user.""" twoFactorInfoCreate(input: TwoFactorInfoCreateInput!): RecoveryCodes! - """ - Deletes the TwoFactorInfo for the authenticated user. - """ + """Deletes the TwoFactorInfo for the authenticated user.""" twoFactorInfoDelete: Boolean! - """ - Generates the 2FA app secret for the authenticated user. - """ + """Reset the 2FA code for a user""" + twoFactorInfoReset(userId: String!): Boolean! + + """Generates the 2FA app secret for the authenticated user.""" twoFactorInfoSecret: TwoFactorInfoSecret! - """ - Validates the token for a 2FA action or for a login request. - """ + """Validates the token for a 2FA action or for a login request.""" twoFactorInfoValidate(input: TwoFactorInfoValidateInput!): Boolean! - """ - Unsubscribe from the Beta program. - """ + """Allowlist a UsageAnomaly.""" + usageAnomalyAllow(input: UsageAnomalyAllowInput!): Boolean! + + """Ban a UsageAnomaly, along with all associated users.""" + usageAnomalyBan(input: UsageAnomalyBanInput!): Boolean! + + """Remove the usage limit for a customer""" + usageLimitRemove(input: UsageLimitRemoveInput!): Boolean! + + """Set the usage limit for a customer""" + usageLimitSet(input: UsageLimitSetInput!): Boolean! + + """Ban a user""" + userBan(input: UserBanInput!): Boolean! + + """Unsubscribe from the Beta program.""" userBetaLeave: Boolean! - """ - Delete the currently authenticated user - """ + """Delete the currently authenticated user""" userDelete: Boolean! - """ - Disconnect your Railway account from Discord. - """ + """Disconnect your Railway account from Discord.""" userDiscordDisconnect: Boolean! - """ - Remove a flag on the user. - """ + """Remove a flag on the user.""" userFlagsRemove(input: UserFlagsRemoveInput!): Boolean! - """ - Set flags on the authenticated user. - """ + """Set flags on the authenticated user.""" userFlagsSet(input: UserFlagsSetInput!): Boolean! - """ - Update date of TermsAgreedOn - """ + """Update the riskLevel for a user""" + userRiskLevelUpdate(input: UserRiskLevelUpdateInput!): Boolean! + + """Update date of TermsAgreedOn""" userTermsUpdate: User - """ - Update currently logged in user - """ - userUpdate(input: UserUpdateInput!): User + """Unban a user""" + userUnban(userId: String!): Boolean! - """ - Waitlist the user - """ - userWaitlist(email: String!): User! + """Update currently logged in user""" + userUpdate(input: UserUpdateInput!): User - """ - Upserts a collection of variables. - """ + """Upserts a collection of variables.""" variableCollectionUpsert(input: VariableCollectionUpsertInput!): Boolean! - """ - Deletes a variable. - """ + """Deletes a variable.""" variableDelete(input: VariableDeleteInput!): Boolean! - """ - Upserts a variable. - """ + """Upserts a variable.""" variableUpsert(input: VariableUpsertInput!): Boolean! + """Create a persistent volume in a project""" + volumeCreate(input: VolumeCreateInput!): Volume! + + """Delete a persistent volume in a project""" + volumeDelete(volumeId: String!): Boolean! + """ - Create a webhook on a project + Change the region of the volume instance. If the new region is different from the current region, a migration of the volume to the new region will be triggered, which will cause downtime for services that have this volume attached. """ - webhookCreate(input: WebhookCreateInput!): ProjectWebhook! + volumeInstanceChangeRegion( + input: VolumeInstanceChangeRegionInput! + + """The id of the volume for which to change the region""" + volumeInstanceId: String! + ): Boolean! """ - Delete a webhook from a project + Resize a volume instance. If no environmentId is provided, all volume instances for the volume will be resized. """ - webhookDelete(id: String!): Boolean! + volumeInstanceResize( + """ + The environment of the volume instance to update. If null, all instances for the volume will be updated + """ + environmentId: String + input: VolumeInstanceResizeInput! + + """The id of the volume to resize""" + volumeId: String! + ): Boolean! """ - Update a webhook on a project + Update a volume instance. If no environmentId is provided, all volume instances for the volume will be updated. """ + volumeInstanceUpdate( + """ + The environment of the volume instance to update. If null, all instances for the volume will be updated + """ + environmentId: String + input: VolumeInstanceUpdateInput! + + """The id of the volume to update""" + volumeId: String! + ): Boolean! + + """Update a persistent volume in a project""" + volumeUpdate(input: VolumeUpdateInput!, volumeId: String!): Volume! + + """Create a webhook on a project""" + webhookCreate(input: WebhookCreateInput!): ProjectWebhook! + + """Delete a webhook from a project""" + webhookDelete(id: String!): Boolean! + + """Update a webhook on a project""" webhookUpdate(id: String!, input: WebhookUpdateInput!): ProjectWebhook! } @@ -1290,12 +1502,27 @@ type PaymentMethodCard { last4: String! } +enum PlatformServiceKey { + ALL_PROVISIONS + ANON_PROVISIONS + FREE_PROVISIONS + NON_PRO_PROVISIONS + SIGNUPS +} + +enum PlatformServiceStatus { + DISABLE + ENABLE +} + type PlatformStatus { incident: Incident isStable: Boolean! + maintenance: Maintenance } type Plugin implements Node { + containers(after: String, before: String, first: Int, last: Int): PluginContainersConnection! createdAt: DateTime! deletedAt: DateTime friendlyName: String! @@ -1304,15 +1531,22 @@ type Plugin implements Node { name: PluginType! project: Project! status: PluginStatus! - variables( - after: String - before: String - first: Int - last: Int - ): PluginVariablesConnection! + variables(after: String, before: String, first: Int, last: Int): PluginVariablesConnection! +} + +type PluginContainersConnection { + edges: [PluginContainersConnectionEdge!]! + pageInfo: PageInfo! +} + +type PluginContainersConnectionEdge { + cursor: String! + node: Container! } input PluginCreateInput { + environmentId: String + friendlyName: String name: String! projectId: String! } @@ -1367,28 +1601,51 @@ input PreferencesUpdateData { usageEmail: Boolean } +type PrivateNetwork { + createdAt: DateTime + deletedAt: DateTime + dnsName: String! + environmentId: String! + name: String! + networkId: BigInt! + projectId: String! + publicId: String! + tags: [String!]! +} + +input PrivateNetworkCreateOrGetInput { + environmentId: String! + name: String! + projectId: String! + tags: [String!]! +} + +type PrivateNetworkEndpoint { + createdAt: DateTime + deletedAt: DateTime + dnsName: String! + privateIps: [String!]! + publicId: String! + serviceInstanceId: String! + tags: [String!]! +} + +input PrivateNetworkEndpointCreateOrGetInput { + environmentId: String! + privateNetworkId: String! + serviceId: String! + serviceName: String! + tags: [String!]! +} + type Project implements Node { + baseEnvironment: Environment createdAt: DateTime! deletedAt: DateTime - deploymentTriggers( - after: String - before: String - first: Int - last: Int - ): ProjectDeploymentTriggersConnection! - deployments( - after: String - before: String - first: Int - last: Int - ): ProjectDeploymentsConnection! + deploymentTriggers(after: String, before: String, first: Int, last: Int): ProjectDeploymentTriggersConnection! + deployments(after: String, before: String, first: Int, last: Int): ProjectDeploymentsConnection! description: String - environments( - after: String - before: String - first: Int - last: Int - ): ProjectEnvironmentsConnection! + environments(after: String, before: String, first: Int, last: Int): ProjectEnvironmentsConnection! expiredAt: DateTime id: ID! isPublic: Boolean! @@ -1396,38 +1653,22 @@ type Project implements Node { isUpdatable: Boolean! members: [ProjectMember!]! name: String! - plugins( - after: String - before: String - first: Int - last: Int - ): ProjectPluginsConnection! + plugins(after: String, before: String, first: Int, last: Int): ProjectPluginsConnection! prDeploys: Boolean! - projectPermissions( - after: String - before: String - first: Int - last: Int - ): ProjectProjectPermissionsConnection! - services( - after: String - before: String - first: Int - last: Int - ): ProjectServicesConnection! + prForks: Boolean! + projectPermissions(after: String, before: String, first: Int, last: Int): ProjectProjectPermissionsConnection! + services(after: String, before: String, first: Int, last: Int): ProjectServicesConnection! + subscriptionType: String! team: Team teamId: String updatedAt: DateTime! upstreamUrl: String - webhooks( - after: String - before: String - first: Int - last: Int - ): ProjectWebhooksConnection! + volumes(after: String, before: String, first: Int, last: Int): ProjectVolumesConnection! + webhooks(after: String, before: String, first: Int, last: Int): ProjectWebhooksConnection! } input ProjectCreateInput { + defaultEnvironmentName: String description: String isPublic: Boolean name: String @@ -1578,10 +1819,24 @@ input ProjectTransferToTeamInput { } input ProjectUpdateInput { + baseEnvironmentId: String description: String isPublic: Boolean name: String prDeploys: Boolean + + """[Experimental] Will be deprecated eventually""" + prForks: Boolean +} + +type ProjectVolumesConnection { + edges: [ProjectVolumesConnectionEdge!]! + pageInfo: PageInfo! +} + +type ProjectVolumesConnectionEdge { + cursor: String! + node: Volume! } type ProjectWebhook implements Node { @@ -1616,131 +1871,127 @@ type PublicStats { } type Query { - """ - Gets all API tokens for the authenticated user. - """ - apiTokens( - after: String - before: String - first: Int - last: Int - ): QueryApiTokensConnection! + """Gets all deployed containers for a environment+service for an admin.""" + adminAllContainerInfoForServiceInEnvironment(environmentId: String!, serviceId: String!): [ContainerInfo!]! - """ - Fetch logs for a build - """ + """Gets all projects for an admin.""" + adminAllProjects(after: String, before: String, deleted: Boolean, expired: Boolean, filter: String, first: Int, last: Int): QueryAdminAllProjectsConnection! + + """Gets all services for an admin.""" + adminAllServices(after: String, before: String, deleted: Boolean, filter: String, first: Int, last: Int): QueryAdminAllServicesConnection! + + """Get all deployments for admin purposes""" + adminDeployments(after: String, before: String, first: Int, input: AdminDeploymentListInput!, last: Int): QueryAdminDeploymentsConnection! + + """Get admin stats. Primarily used for the admin dashboard.""" + adminStats: AdminStats! + + """Get all volume instances for a given volume""" + adminVolumeInstancesForVolume(volumeId: String!): [VolumeInstance!]! + + """Gets all API tokens for the authenticated user.""" + apiTokens(after: String, before: String, first: Int, last: Int): QueryApiTokensConnection! + + """Gets the ban reason history for a user.""" + banReasonHistory(after: String, before: String, first: Int, last: Int, userId: String!): QueryBanReasonHistoryConnection! + + """Fetch logs for a build""" buildLogs( deploymentId: String! endDate: DateTime - """ - Filter logs by a string. Providing an empty value will match all logs. - """ + """Filter logs by a string. Providing an empty value will match all logs.""" filter: String - """ - Limit the number of logs returned. Defaults to 100. - """ - limit: Int! = 100 + """Limit the number of logs returned (defaults 100, max 5000)""" + limit: Int startDate: DateTime ): [Log!]! - """ - Gets the image URL for a Notion image block - """ + """Gets the image URL for a Notion image block""" changelogBlockImage(id: String!): String! - """ - Checks if a custom domain is available. - """ + """Gets the history of changesets for an environment.""" + changesets(after: String, before: String, environmentId: String!, first: Int, last: Int, projectId: String!): QueryChangesetsConnection! + + """Fetch details for a custom domain""" + customDomain(id: String!, projectId: String!): CustomDomain! + + """Checks if a custom domain is available.""" customDomainAvailable(domain: String!): DomainAvailable! - """ - Find a single deployment - """ + """Find a single deployment""" deployment(id: String!): Deployment! - """ - Fetch logs for a deployment - """ + """Find a deployment by public url""" + deploymentByDomain(domain: String!): DeploymentByDomain! + + """Fetch logs for a deployment""" deploymentLogs( deploymentId: String! endDate: DateTime - """ - Filter logs by a string. Providing an empty value will match all logs. - """ + """Filter logs by a string. Providing an empty value will match all logs.""" filter: String - """ - Limit the number of logs returned. Defaults to 100. - """ - limit: Int! = 100 + """Limit the number of logs returned (defaults 100, max 5000)""" + limit: Int startDate: DateTime ): [Log!]! - """ - All deployment triggers. - """ - deploymentTriggers( - after: String - before: String - environmentId: String! - first: Int - last: Int - projectId: String! - serviceId: String! - ): QueryDeploymentTriggersConnection! + """Get a short-lived URL to the deployment snapshot code""" + deploymentSnapshotCodeUri(deploymentId: String!): String! - """ - Get all deployments - """ - deployments( - after: String - before: String - first: Int - input: DeploymentListInput! - last: Int - ): QueryDeploymentsConnection! + """All deployment triggers.""" + deploymentTriggers(after: String, before: String, environmentId: String!, first: Int, last: Int, projectId: String!, serviceId: String!): QueryDeploymentTriggersConnection! - """ - Domain with status - """ - domainStatus(id: String!, projectId: String!): DomainWithStatus! + """Get all deployments""" + deployments(after: String, before: String, first: Int, input: DeploymentListInput!, last: Int): QueryDeploymentsConnection! + + """Returns basic information about the Railway Discord server""" + discordServerInfo: DiscordServerInfo! + + """Domain with status""" + domainStatus(id: String!, projectId: String!): DomainWithStatus! @deprecated(reason: "Use the `status` field within the `domain` query instead") + + """All domains for a service instance""" + domains(environmentId: String!, projectId: String!, serviceId: String!): AllDomains! + + """Find a single environment""" + environment(id: String!): Environment! """ - All domains + Fetch logs for a project environment. Build logs are excluded unless a snapshot ID is explicitly provided in the filter """ - domains( + environmentLogs( + """Latest date to look for logs after the anchor""" + afterDate: String + + """Limit the number of logs returned after the anchor""" + afterLimit: Int + + """Target date time to look for logs""" + anchorDate: String + + """Oldest date to look for logs before the anchor""" + beforeDate: String + + """Limit the number of logs returned before the anchor""" + beforeLimit: Int environmentId: String! - projectId: String! - serviceId: String! - ): AllDomains! - """ - Find a single environment - """ - environment(id: String!): Environment! + """Filter logs using a query syntax""" + filter: String + ): [Log!]! - """ - Gets all environments for a project. - """ - environments( - after: String - before: String - first: Int - isEphemeral: Boolean - last: Int - projectId: String! - ): QueryEnvironmentsConnection! + """Gets all environments for a project.""" + environments(after: String, before: String, first: Int, isEphemeral: Boolean, last: Int, projectId: String!): QueryEnvironmentsConnection! """ Get the estimated total cost of the project at the end of the current billing cycle """ estimatedUsage( - """ - Whether to include deleted projects in estimations. - """ + """Whether to include deleted projects in estimations.""" includeDeleted: Boolean measurements: [MetricMeasurement!]! projectId: String @@ -1748,34 +1999,13 @@ type Query { userId: String ): [EstimatedUsage!]! - """ - Gets the events for a project. - """ - events( - after: String - before: String - environmentId: String - first: Int - last: Int - projectId: String! - ): QueryEventsConnection! + """Gets the events for a project.""" + events(after: String, before: String, environmentId: String, first: Int, last: Int, projectId: String!): QueryEventsConnection! - """ - Get the execution time of projects - """ - executionTime( - """ - Whether to get execution for deleted projects. - """ - includeDeleted: Boolean - projectId: String - teamId: String - userId: String - ): [ExecutionTime!]! + """Get GitHub events for a user""" + githubEvents(userId: String!): [GitHubEvent!]! - """ - Check if a repo name is available - """ + """Check if a repo name is available""" githubIsRepoNameAvailable(fullRepoName: String!): Boolean! """ @@ -1783,60 +2013,37 @@ type Query { """ githubRepoBranches(owner: String!, repo: String!): [GitHubBranch!]! - """ - Get a list of repos for a user that Railway has access to - """ + """Get a list of repos for a user that Railway has access to""" githubRepos: [GitHubRepo!]! - """ - Get a list of scopes the user has installed the installation to - """ + """Get a list of scopes the user has installed the installation to""" githubWritableScopes: [String!]! - """ - Get the Herokus apps for the current user - """ + """Returns a list of usage anomalies grouped by service.""" + groupedUsageAnomalies(input: GroupedUsageAnomaliesInput!): [GroupedUsageAnomaly!]! + + """Get the Herokus apps for the current user""" herokuApps: [HerokuApp!]! - """ - Get an integration auth by provider providerId - """ + """Get an integration auth by provider providerId""" integrationAuth(provider: String!, providerId: String!): IntegrationAuth! - """ - Get all integration auths for a user - """ - integrationAuths( - after: String - before: String - first: Int - last: Int - ): QueryIntegrationAuthsConnection! + """Get all integration auths for a user""" + integrationAuths(after: String, before: String, first: Int, last: Int): QueryIntegrationAuthsConnection! - """ - Get all integrations for a project - """ - integrations( - after: String - before: String - first: Int - last: Int - projectId: String! - ): QueryIntegrationsConnection! + """Get all integrations for a project""" + integrations(after: String, before: String, first: Int, last: Int, projectId: String!): QueryIntegrationsConnection! - """ - Get an invite code by the code - """ + """Get an invite code by the code""" inviteCode(code: String!): InviteCode! - """ - Gets the authenticated user. - """ + """Returns the current lockdown status of the platform.""" + lockdownStatus: LockdownStatus! + + """Gets the authenticated user.""" me: User! - """ - Get metrics for a project, environment, and service - """ + """Get metrics for a project, environment, and service""" metrics( """ The averaging window when computing CPU usage. By default, it is the same as the `sampleRateSeconds`. @@ -1854,9 +2061,7 @@ type Query { """ groupBy: [MetricTag!] - """ - Whether or not to include deleted projects in the results - """ + """Whether or not to include deleted projects in the results""" includeDeleted: Boolean measurements: [MetricMeasurement!]! pluginId: String @@ -1868,167 +2073,147 @@ type Query { sampleRateSeconds: Int serviceId: String - """ - The start of the period to get metrics for. - """ + """The start of the period to get metrics for.""" startDate: DateTime! teamId: String userId: String + volumeId: String ): [MetricsResult!]! - """ - """ + """Get a collection in a MongoDB container""" + mongoCollectionData(database: String!, environmentId: String!, name: String!, pluginId: String, serviceId: String): MongoCollection! + + """Get a list of collection names in a MongoDB container""" + mongoCollectionNames(database: String!, environmentId: String!, pluginId: String, serviceId: String): [String!]! + + """Get a list of database names in a MongoDB container""" + mongoDatabaseNames(environmentId: String!, pluginId: String, serviceId: String): [String!]! + + """""" node(id: ID!): Node - """ - """ + """""" nodes(ids: [ID!]!): [Node]! - """ - Get a user JWT token for a Discord id - """ + """Get a user's Plain Customer ID given their Discord ID.""" + plainCustomerIdForDiscordId(discordId: String!): String! + + """Get a user JWT token for a Discord id""" plainJWTForDiscordId(discordId: String!): String! - """ - Get the current status of the platform - """ + """Get the current status of the platform""" platformStatus: PlatformStatus! - """ - Get a plugin by ID. - """ + """Get a plugin by ID.""" plugin(id: String!): Plugin! - """ - Fetch logs for a plugin - """ + """Fetch logs for a plugin""" pluginLogs( endDate: DateTime environmentId: String! - """ - Filter logs by a string. Providing an empty value will match all logs. - """ + """Filter logs by a string. Providing an empty value will match all logs.""" filter: String - """ - Limit the number of logs returned. Defaults to 100. - """ - limit: Int! = 100 + """Limit the number of logs returned (defaults 100, max 5000)""" + limit: Int pluginId: String! startDate: DateTime ): [Log!]! - """ - Get the email preferences for a user - """ + """Get the email preferences for a user""" preferences(token: String): Preferences! - """ - Get a project by ID - """ + """Get a private network endpoint for a service instance.""" + privateNetworkEndpoint(environmentId: String!, privateNetworkId: String!, serviceId: String!): PrivateNetworkEndpoint + + """Check if an endpoint name is available.""" + privateNetworkEndpointNameAvailable(environmentId: String!, prefix: String!, privateNetworkId: String!): Boolean! + + """List private networks for an environment.""" + privateNetworks(environmentId: String!): [PrivateNetwork!]! + + """Get a project by ID""" project(id: String!): Project! - """ - Get an invite code for a project for a specifc role - """ + """Get an invite code for a project for a specifc role""" projectInviteCode(projectId: String!, role: ProjectRole!): InviteCode! - """ - Gets users who belong to a project along with their role - """ + """Gets users who belong to a project along with their role""" projectMembers(projectId: String!): [ProjectMember!]! - """ - Get resource access rules for project-specific actions - """ + """Get resource access rules for project-specific actions""" projectResourceAccess(projectId: String!): ProjectResourceAccess! - """ - Get a single project token by the value in the header - """ + """Get a single project token by the value in the header""" projectToken: ProjectToken! - """ - Get all project tokens for a project - """ - projectTokens( - after: String - before: String - first: Int - last: Int - projectId: String! - ): QueryProjectTokensConnection! + """Get all project tokens for a project""" + projectTokens(after: String, before: String, first: Int, last: Int, projectId: String!): QueryProjectTokensConnection! - """ - Gets all projects for a user or a team. - """ - projects( - after: String - before: String - first: Int - includeDeleted: Boolean - last: Int - teamId: String - userId: String - ): QueryProjectsConnection! + """Gets all projects for a user or a team.""" + projects(after: String, before: String, first: Int, includeDeleted: Boolean, last: Int, teamId: String, userId: String): QueryProjectsConnection! - """ - Get public Railway stats. Primarily used for the landing page. - """ + """Get public Railway stats. Primarily used for the landing page.""" publicStats: PublicStats! - """ - Gets the ReferralInfo for the authenticated user. - """ + """Get data for key in a Redis container""" + redisGetKey(environmentId: String!, key: String!, pluginId: String, serviceId: String): JSON! + + """Get a list of keys in a Redis container""" + redisKeys(environmentId: String!, pluginId: String, serviceId: String): [RedisKey!]! + + """Gets the ReferralInfo for the authenticated user.""" referralInfo: ReferralInfo! - """ - Get resource access for the current user or team - """ + """List available regions""" + regions: [Region!]! + + """Get resource access for the current user or team""" resourceAccess(explicitResourceOwner: ExplicitOwnerInput): ResourceAccess! - """ - Get a service by ID - """ + """Get a service by ID""" service(id: String!): Service! - """ - Checks if a service domain is available - """ + """Checks if a service domain is available""" serviceDomainAvailable(domain: String!): DomainAvailable! - """ - Check if the upstream repo for a service has an update available - """ - serviceInstanceIsUpdatable( - environmentId: String! - serviceId: String! - ): Boolean! + """Get a service instance belonging to a service and environment""" + serviceInstance(environmentId: String!, serviceId: String!): ServiceInstance! - """ - Gets all sessions for authenticated user. - """ - sessions( - after: String - before: String - first: Int - last: Int - ): QuerySessionsConnection! + """Check if the upstream repo for a service has an update available""" + serviceInstanceIsUpdatable(environmentId: String!, serviceId: String!): Boolean! - """ - Find a team by ID - """ + """Gets all sessions for authenticated user.""" + sessions(after: String, before: String, first: Int, last: Int): QuerySessionsConnection! + + """Get rows for a SQL table""" + sqlTable(databaseType: String!, environmentId: String!, limit: Int, name: String!, offset: Int, pluginId: String, serviceId: String): SQLTable! + + """Get a list of table names in SQLQL container""" + sqlTableNames(databaseType: String!, environmentId: String!, pluginId: String, serviceId: String): [String!]! + + """All TCP proxies for a service instance""" + tcpProxies(environmentId: String!, serviceId: String!): [TCPProxy!]! + + """Find a team by ID""" team(id: String!): Team! - """ - Find a team by invite code - """ + """Find a team by invite code""" teamByCode(code: String!): Team! """ - Get a template by code or GitHub owner and repo. + Fetch Discord info associated with Direct Support-eligible team members, given a Discord UID """ + teamDirectSupportDiscordInfoForDiscordId(discordId: String!): TeamDirectSupportDiscordInfo + + """Get all templates for a team.""" + teamTemplates(after: String, before: String, first: Int, last: Int, teamId: String!): QueryTeamTemplatesConnection! + + """Get all teams""" + teams(after: String, before: String, filter: String, first: Int, last: Int, state: String): QueryTeamsConnection! + + """Get a template by code or GitHub owner and repo.""" template(code: String, owner: String, repo: String): Template! """ @@ -2036,34 +2221,47 @@ type Query { """ templateFromHerokuTemplate(repoUrl: String!): JSON! - """ - Gets the README for a template. - """ + """Gets the README for a template.""" templateReadme(code: String!): TemplateReadme! - """ - Get the source template for a project. - """ + """Get the source template for a project.""" templateSourceForProject(projectId: String!): Template - """ - Get all published templates. - """ + """Get all published templates.""" templates( after: String before: String first: Int last: Int - """ - If set to true, only recommended templates will be returned. - """ + """If set to true, only recommended templates will be returned.""" recommended: Boolean ): QueryTemplatesConnection! - """ - Gets the TwoFactorInfo for the authenticated user. - """ + """Get the top projects by a metric""" + topMetrics( + """ + The averaging window when computing CPU usage. By default, it is the same as the `sampleRateSeconds`. + """ + averagingWindowSeconds: Int + + """ + The end of the period to get metrics for. If not provided, the current datetime is used. + """ + endDate: DateTime + limit: Int! + measurement: MetricMeasurement! + + """ + The frequency of data points in the response. If the `sampleRateSeconds` is 60, then the response will contain one data point per minute. + """ + sampleRateSeconds: Int + + """The start of the period to get metrics for.""" + startDate: DateTime! + ): TopMetricsResult! + + """Gets the TwoFactorInfo for the authenticated user.""" twoFactorInfo: TwoFactorInfo! """ @@ -2077,9 +2275,7 @@ type Query { """ groupBy: [MetricTag!] - """ - Whether to include deleted projects in the usage. - """ + """Whether to include deleted projects in the usage.""" includeDeleted: Boolean measurements: [MetricMeasurement!]! projectId: String @@ -2088,20 +2284,23 @@ type Query { userId: String ): [AggregatedUsage!]! - """ - Get the user id corresponding to a Discord id - """ + """Get a user by id""" + user(userId: String!): User! + + """Get the user id corresponding to a Discord id""" userIdForDiscordId(discordId: String!): String! - """ - Get all templates for the current user. - """ - userTemplates( - after: String - before: String - first: Int - last: Int - ): QueryUserTemplatesConnection! + """Get the reasoning behind the risk level of a user""" + userRiskLevel(userId: String!): RiskLevelDetails! + + """Get all templates for the current user.""" + userTemplates(after: String, before: String, first: Int, last: Int): QueryUserTemplatesConnection! + + """Get all users""" + users(after: String, before: String, first: Int, input: UsersFilterInput, last: Int): QueryUsersConnection! + + """Gets all users with same IP as specified user.""" + usersWithClashingIP(userId: String!): [UserWithClashingIP!]! """ All variables by pluginId or serviceId. If neither are provided, all shared variables are returned. @@ -2109,50 +2308,58 @@ type Query { variables( environmentId: String! - """ - Provide a pluginId to get all variables for a specific plugin. - """ + """Provide a pluginId to get all variables for a specific plugin.""" pluginId: String projectId: String! - """ - Provide a serviceId to get all variables for a specific service. - """ + """Provide a serviceId to get all variables for a specific service.""" serviceId: String unrendered: Boolean ): ServiceVariables! - """ - All rendered variables that are required for a service deployment. - """ - variablesForServiceDeployment( - environmentId: String! - projectId: String! - serviceId: String! - ): ServiceVariables! + """All rendered variables that are required for a service deployment.""" + variablesForServiceDeployment(environmentId: String!, projectId: String!, serviceId: String!): ServiceVariables! - """ - Get information about the user's Vercel accounts - """ + """Get information about the user's Vercel accounts""" vercelInfo: VercelInfo! - """ - Get all webhooks for a project - """ - webhooks( - after: String - before: String - first: Int - last: Int - projectId: String! - ): QueryWebhooksConnection! + """Get all webhooks for a project""" + webhooks(after: String, before: String, first: Int, last: Int, projectId: String!): QueryWebhooksConnection! - """ - Gets the status of a workflow - """ + """Gets the status of a workflow""" workflowStatus(projectId: String, workflowId: String!): WorkflowResult! } +type QueryAdminAllProjectsConnection { + edges: [QueryAdminAllProjectsConnectionEdge!]! + pageInfo: PageInfo! +} + +type QueryAdminAllProjectsConnectionEdge { + cursor: String! + node: Project! +} + +type QueryAdminAllServicesConnection { + edges: [QueryAdminAllServicesConnectionEdge!]! + pageInfo: PageInfo! +} + +type QueryAdminAllServicesConnectionEdge { + cursor: String! + node: Service! +} + +type QueryAdminDeploymentsConnection { + edges: [QueryAdminDeploymentsConnectionEdge!]! + pageInfo: PageInfo! +} + +type QueryAdminDeploymentsConnectionEdge { + cursor: String! + node: Deployment! +} + type QueryApiTokensConnection { edges: [QueryApiTokensConnectionEdge!]! pageInfo: PageInfo! @@ -2163,6 +2370,26 @@ type QueryApiTokensConnectionEdge { node: ApiToken! } +type QueryBanReasonHistoryConnection { + edges: [QueryBanReasonHistoryConnectionEdge!]! + pageInfo: PageInfo! +} + +type QueryBanReasonHistoryConnectionEdge { + cursor: String! + node: BanReasonHistory! +} + +type QueryChangesetsConnection { + edges: [QueryChangesetsConnectionEdge!]! + pageInfo: PageInfo! +} + +type QueryChangesetsConnectionEdge { + cursor: String! + node: Changeset! +} + type QueryDeploymentTriggersConnection { edges: [QueryDeploymentTriggersConnectionEdge!]! pageInfo: PageInfo! @@ -2253,6 +2480,26 @@ type QuerySessionsConnectionEdge { node: Session! } +type QueryTeamTemplatesConnection { + edges: [QueryTeamTemplatesConnectionEdge!]! + pageInfo: PageInfo! +} + +type QueryTeamTemplatesConnectionEdge { + cursor: String! + node: Template! +} + +type QueryTeamsConnection { + edges: [QueryTeamsConnectionEdge!]! + pageInfo: PageInfo! +} + +type QueryTeamsConnectionEdge { + cursor: String! + node: Team! +} + type QueryTemplatesConnection { edges: [QueryTemplatesConnectionEdge!]! pageInfo: PageInfo! @@ -2273,6 +2520,16 @@ type QueryUserTemplatesConnectionEdge { node: Template! } +type QueryUsersConnection { + edges: [QueryUsersConnectionEdge!]! + pageInfo: PageInfo! +} + +type QueryUsersConnectionEdge { + cursor: String! + node: User! +} + type QueryWebhooksConnection { edges: [QueryWebhooksConnectionEdge!]! pageInfo: PageInfo! @@ -2292,6 +2549,12 @@ type RecoveryCodes { recoveryCodes: [String!]! } +type RedisKey { + name: String! + ttl: BigInt + type: String! +} + type ReferralInfo implements Node { code: String! id: ID! @@ -2320,6 +2583,16 @@ type ReferralUser { status: ReferralStatus! } +input RefundFormInput { + message: String! + stripeInvoiceId: String! + teamId: String +} + +type Region { + name: String! +} + enum RegistrationStatus { ONBOARDED REGISTERED @@ -2349,49 +2622,70 @@ enum RestartPolicyType { ON_FAILURE } +type RiskLevelDetails { + compositeScore: CompositeScore! + fairUse: Boolean! + terms: Boolean! +} + +input SQLColumnInput { + constraint: String + default: String + name: String! + type: String! +} + +"""Response returned after running a raw query""" +type SQLRawQueryResponse { + raw: JSON! +} + +input SQLRowInput { + name: String! + value: String! +} + +type SQLTable { + columnNames: [String!]! + columnTypes: [Int!]! + name: String! + primaryKey: String! + rows: [JSON!]! + totalRows: Int! +} + type Service implements Node { createdAt: DateTime! deletedAt: DateTime - deployments( - after: String - before: String - first: Int - last: Int - ): ServiceDeploymentsConnection! + deployments(after: String, before: String, first: Int, last: Int): ServiceDeploymentsConnection! icon: String id: ID! name: String! project: Project! projectId: String! - repoTriggers( - after: String - before: String - first: Int - last: Int - ): ServiceRepoTriggersConnection! - serviceInstances( - after: String - before: String - first: Int - last: Int - ): ServiceServiceInstancesConnection! + repoTriggers(after: String, before: String, first: Int, last: Int): ServiceRepoTriggersConnection! + serviceInstances(after: String, before: String, first: Int, last: Int): ServiceServiceInstancesConnection! updatedAt: DateTime! } input ServiceConnectInput { - """ - The branch to connect to. e.g. 'main' - """ - branch: String! + """The branch to connect to. e.g. 'main'""" + branch: String - """ - The full name of the repo to connect to. e.g. 'railwayapp/starters' - """ - repo: String! + """Name of the Dockerhub or GHCR image to connect this service to.""" + image: String + + """The full name of the repo to connect to. e.g. 'railwayapp/starters'""" + repo: String } input ServiceCreateInput { branch: String + + """ + [Experimental] Environment ID. If the specified environment is a fork, the service will only be created in it. Otherwise it will created in all environments that are not forks of other environments + """ + environmentId: String name: String projectId: String! source: ServiceSourceInput @@ -2434,6 +2728,7 @@ type ServiceInstance implements Node { buildCommand: String builder: Builder! createdAt: DateTime! + cronSchedule: String deletedAt: DateTime domains: AllDomains! environmentId: String! @@ -2441,12 +2736,16 @@ type ServiceInstance implements Node { healthcheckTimeout: Int id: ID! isUpdatable: Boolean! + nextCronRunAt: DateTime nixpacksPlan: JSON + numReplicas: Int railwayConfigFile: String + region: String restartPolicyMaxRetries: Int! restartPolicyType: RestartPolicyType! rootDirectory: String serviceId: String! + sleepApplication: Boolean source: ServiceSource startCommand: String updatedAt: DateTime! @@ -2457,13 +2756,17 @@ type ServiceInstance implements Node { input ServiceInstanceUpdateInput { buildCommand: String builder: Builder + cronSchedule: String healthcheckPath: String healthcheckTimeout: Int nixpacksPlan: JSON + numReplicas: Int railwayConfigFile: String + region: String restartPolicyMaxRetries: Int restartPolicyType: RestartPolicyType rootDirectory: String + sleepApplication: Boolean source: ServiceSourceInput startCommand: String watchPatterns: [String!] @@ -2490,12 +2793,14 @@ type ServiceServiceInstancesConnectionEdge { } type ServiceSource { + image: String repo: String template: TemplateServiceSource } input ServiceSourceInput { - repo: String! + image: String + repo: String } input ServiceUpdateInput { @@ -2539,62 +2844,72 @@ type SimilarTemplate { description: String image: String name: String! + teamId: String + userId: String } type Subscription { - """ - Stream logs for a build - """ + """Stream logs for a build""" buildLogs( deploymentId: String! - """ - Filter logs by a string. Providing an empty value will match all logs. - """ + """Filter logs by a string. Providing an empty value will match all logs.""" filter: String - """ - Limit the number of logs returned. Defaults to 100. - """ - limit: Int! = 100 + """Limit the number of logs returned (defaults 100, max 5000)""" + limit: Int ): [Log!]! - """ - Stream logs for a deployment - """ + """Stream logs for a deployment""" deploymentLogs( deploymentId: String! - """ - Filter logs by a string. Providing an empty value will match all logs. - """ + """Filter logs by a string. Providing an empty value will match all logs.""" filter: String - """ - Limit the number of logs returned. Defaults to 100. - """ - limit: Int! = 100 + """Limit the number of logs returned (defaults 100, max 5000)""" + limit: Int ): [Log!]! - """ - Stream logs for a plugin - """ + """Stream logs for a project environment""" + environmentLogs( + """Latest date to look for logs after the anchor""" + afterDate: String + + """Limit the number of logs returned after the anchor""" + afterLimit: Int + + """Target date time to look for logs""" + anchorDate: String + + """Oldest date to look for logs before the anchor""" + beforeDate: String + + """Limit the number of logs returned before the anchor""" + beforeLimit: Int + environmentId: String! + + """Filter logs using a query syntax""" + filter: String + ): [Log!]! + + """Stream logs for a plugin""" pluginLogs( environmentId: String! - """ - Filter logs by a string. Providing an empty value will match all logs. - """ + """Filter logs by a string. Providing an empty value will match all logs.""" filter: String - """ - Limit the number of logs returned. Defaults to 100. - """ - limit: Int! = 100 + """Limit the number of logs returned (defaults 100, max 5000)""" + limit: Int pluginId: String! ): [Log!]! } +type SubscriptionDiscount { + couponId: String! +} + type SubscriptionItem { itemId: String! priceId: String! @@ -2610,10 +2925,31 @@ enum SubscriptionState { UNPAID } -input SupportRequestInput { - isPurchasing: Boolean - isTechnical: Boolean - text: String! +type TCPProxy { + applicationPort: Int! + createdAt: DateTime + deletedAt: DateTime + domain: String! + environmentId: String! + id: ID! + proxyPort: Int! + serviceId: String! + updatedAt: DateTime +} + +input TCPProxyCreateInput { + applicationPort: Int! + environmentId: String! + serviceId: String! +} + +input TalkToAnEngineerFormInput { + deploymentId: String = null + environmentId: String = null + message: String! + projectId: String = null + serviceId: String = null + teamId: String! } type Team implements Node { @@ -2623,23 +2959,46 @@ type Team implements Node { customer: Customer! discordRole: String id: ID! + isEligibleForDirectSupport: Boolean! members: [TeamMember!]! name: String! - projects( - after: String - before: String - first: Int - last: Int - ): TeamProjectsConnection! + projects(after: String, before: String, first: Int, last: Int): TeamProjectsConnection! teamPermissions: [TeamPermission!]! updatedAt: DateTime! } +input TeamBanInput { + banReason: String! +} + +input TeamBulkProjectTransferInput { + projectIds: [String!]! + teamId: String! +} + +input TeamCreateAndSubscribeInput { + avatar: String + name: String! + paymentMethodId: String! +} + +type TeamCreateAndSubscribeResponse { + customerId: String! + paymentIntent: JSON + teamId: String! +} + input TeamCreateInput { avatar: String name: String! } +type TeamDirectSupportDiscordInfo { + memberDiscordIds: [String!]! + teamId: String! + teamName: String! +} + input TeamInviteCodeCreateInput { role: String! } @@ -2677,6 +3036,10 @@ type TeamProjectsConnectionEdge { node: Project! } +input TeamResourcesStopInput { + reason: String! +} + enum TeamRole { ADMIN MEMBER @@ -2688,8 +3051,8 @@ input TeamUpdateInput { } input TeamUserInviteInput { + code: String! email: String! - link: String! } input TeamUserRemoveInput { @@ -2706,6 +3069,7 @@ input TelemetrySendInput { } type Template implements Node { + activeProjects: Int! code: String! config: TemplateConfig! createdAt: DateTime! @@ -2715,14 +3079,10 @@ type Template implements Node { isApproved: Boolean! metadata: TemplateMetadata! projects: Int! - services( - after: String - before: String - first: Int - last: Int - ): TemplateServicesConnection! + services(after: String, before: String, first: Int, last: Int): TemplateServicesConnection! similarTemplates: [SimilarTemplate!]! status: TemplateStatus! + teamId: String totalPayout: Int! userId: String } @@ -2734,6 +3094,7 @@ input TemplateCreateInput { demoProjectId: String metadata: TemplateMetadata! services: [TemplateServiceCreateInput!]! + teamId: String } type TemplateCreator { @@ -2751,7 +3112,7 @@ input TemplateDeployInput { type TemplateDeployPayload { projectId: String! - workflowId: String! + workflowId: String } input TemplateDeployService { @@ -2760,13 +3121,16 @@ input TemplateDeployService { healthcheckPath: String id: String isPrivate: Boolean - name: String! - owner: String! + name: String + owner: String rootDirectory: String + serviceIcon: String serviceName: String! startCommand: String + tcpProxyApplicationPort: Int template: String! variables: ServiceVariables + volumes: [TemplateVolume!] } input TemplateGenerateInput { @@ -2780,6 +3144,7 @@ input TemplatePublishInput { description: String! image: String readme: String! + teamId: String } type TemplateReadme { @@ -2832,12 +3197,30 @@ input TemplateUpdateInput { config: TemplateConfig! demoProjectId: String - """ - An admin-only flag to force-update a template. - """ + """An admin-only flag to force-update a template.""" forceUpdate: Boolean = false metadata: TemplateMetadata! services: [TemplateServiceUpdateInput!]! + teamId: String +} + +scalar TemplateVolume + +input TogglePlatformServiceInput { + platformServiceKey: PlatformServiceKey! + reason: String + status: PlatformServiceStatus! +} + +"""The result of a top metrics query.""" +type TopMetricsResult { + metrics: [MetricsResult!]! + projects: [Project!]! +} + +type TotalUsage { + current: Float + estimated: Float } type TwoFactorInfo { @@ -2859,11 +3242,59 @@ input TwoFactorInfoValidateInput { twoFactorLinkingKey: String } -""" -The `Upload` scalar type represents a file upload. -""" +"""The `Upload` scalar type represents a file upload.""" scalar Upload +type UsageAnomaly implements Node { + actedOn: DateTime + action: UsageAnomalyAction + actorId: String + flaggedAt: DateTime! + flaggedFor: UsageAnomalyFlagReason! + id: ID! +} + +"""Possible actions for a UsageAnomaly.""" +enum UsageAnomalyAction { + ALLOWED + AUTOBANNED + BANNED +} + +input UsageAnomalyAllowInput { + usageAnomalyIds: [String!]! +} + +input UsageAnomalyBanInput { + teamId: String + usageAnomalyIds: [String!]! + userIds: [String!]! +} + +"""Possible flag reasons for a UsageAnomaly.""" +enum UsageAnomalyFlagReason { + HIGH_CPU_USAGE + HIGH_DISK_USAGE + HIGH_NETWORK_USAGE +} + +type UsageLimit implements Node { + customerId: String! + hardLimit: Int + id: ID! + softLimit: Int! +} + +input UsageLimitRemoveInput { + customerId: String! +} + +input UsageLimitSetInput { + customerId: String! + hardLimitDollars: Int + softLimitDollars: Int! +} + type User implements Node { agreedFairUse: Boolean! avatar: String @@ -2872,46 +3303,37 @@ type User implements Node { createdAt: DateTime! customer: Customer! email: String! - executionTime: Float + featureFlags: [ActiveFeatureFlag!]! flags: [UserFlag!]! has2FA: Boolean! id: ID! isAdmin: Boolean! isDevPlan: Boolean! + isEligibleForFreeHobbyPlan: Boolean! + isOnHobbyPlan: Boolean! isVerified: Boolean! lastLogin: DateTime! name: String - projects( - after: String - before: String - first: Int - last: Int - ): UserProjectsConnection! - providerAuths( - after: String - before: String - first: Int - last: Int - ): UserProviderAuthsConnection! + projects(after: String, before: String, first: Int, last: Int): UserProjectsConnection! + providerAuths(after: String, before: String, first: Int, last: Int): UserProviderAuthsConnection! referredUsers: [ReferralUser!]! registrationStatus: RegistrationStatus! riskLevel: Float - teams( - after: String - before: String - first: Int - last: Int - ): UserTeamsConnection! + teams(after: String, before: String, first: Int, last: Int): UserTeamsConnection! termsAgreedOn: DateTime } +input UserBanInput { + reason: String! + userId: String! +} + type UserCost { current: Float! estimated: Float! } enum UserFlag { - API_PREVIEW BETA } @@ -2945,6 +3367,11 @@ type UserProviderAuthsConnectionEdge { node: ProviderAuth! } +input UserRiskLevelUpdateInput { + riskLevel: Float + userId: String! +} + type UserTeamsConnection { edges: [UserTeamsConnectionEdge!]! pageInfo: PageInfo! @@ -2960,6 +3387,21 @@ input UserUpdateInput { name: String } +type UserWithClashingIP { + email: String! + id: String! + isBanned: Boolean! +} + +input UsersFilterInput { + admin: Boolean + banned: Boolean + filter: String + referredUsers: Boolean + riskLevel: Float + usageSubscription: Boolean +} + type Variable implements Node { createdAt: DateTime! environment: Environment! @@ -3020,6 +3462,101 @@ type VercelProject { name: String! } +type Volume implements Node { + createdAt: DateTime! + id: ID! + name: String! + project: Project! + projectId: String! + volumeInstances(after: String, before: String, first: Int, last: Int): VolumeVolumeInstancesConnection! +} + +input VolumeCreateInput { + """The path in the container to mount the volume to""" + mountPath: String! + + """The project to create the volume in""" + projectId: String! + + """ + The service to attach the volume to. If not provided, the volume will be disconnected. + """ + serviceId: String +} + +type VolumeInstance implements Node { + createdAt: DateTime! + currentSizeMB: Float! + environment: Environment! + environmentId: String! + externalId: String + id: ID! + mountPath: String! + region: String + service: Service! + serviceId: String + sizeMB: Int! + stacker: String + state: VolumeState + volume: Volume! + volumeId: String! +} + +input VolumeInstanceChangeRegionInput { + """ + The region of the volume instance. If provided and different from the current region, a migration of the volume to the new region will be triggered, which will cause downtime for services that have this volume attached. + """ + region: String! +} + +input VolumeInstanceResizeInput { + """ + The size of the volume instance in MB. You can only resize a volume upwards + """ + targetSizeMB: Int! +} + +input VolumeInstanceUpdateInput { + """ + The mount path of the volume instance. If not provided, the mount path will not be updated. + """ + mountPath: String + + """ + The service to attach the volume to. If not provided, the volume will be disconnected. + """ + serviceId: String + + """ + The state of the volume instance. If not provided, the state will not be updated. + """ + state: VolumeState +} + +enum VolumeState { + DELETED + DELETING + ERROR + MIGRATING + READY + UPDATING +} + +input VolumeUpdateInput { + """The name of the volume""" + name: String +} + +type VolumeVolumeInstancesConnection { + edges: [VolumeVolumeInstancesConnectionEdge!]! + pageInfo: PageInfo! +} + +type VolumeVolumeInstancesConnectionEdge { + cursor: String! + node: VolumeInstance! +} + input WebhookCreateInput { projectId: String! url: String! @@ -3037,4 +3574,4 @@ enum WorkflowStatus { Complete Error Running -} +} \ No newline at end of file