diff --git a/PROVIDERS.md b/PROVIDERS.md index 2de466e..bd09a76 100644 --- a/PROVIDERS.md +++ b/PROVIDERS.md @@ -46,11 +46,13 @@ Stripe Projects catalog reference. Offline catalog detail: | `agentmail` | `agentmail/api` | | `agentphone` | `agentphone/number` | | `amplitude` | `amplitude/analytics` | +| `athena` | `athena/agents` | | `auth0` | `auth0/client` | | `base44` | `base44_projects/app` | | `blaxel-sandbox` | `blaxel/sandbox` | | `browserbase` | `browserbase/project` | | `chatbase` | `chatbase/agent` | +| `churnkey` | `churnkey/retention` | | `clerk` | `clerk/auth` | | `clickhouse` | `clickhouse/clickhouse` | | `clickhouse-postgres` | `clickhouse/postgres` | @@ -73,6 +75,7 @@ Stripe Projects catalog reference. Offline catalog detail: | `flyio-mpg` | `flyio/mpg` | | `flyio-sprite` | `flyio/sprite` | | `gitlab` | `gitlab/project` | +| `herenow` | `herenow/hosting` | | `inngest` | `inngest/app` | | `kernel` | `kernel/project` | | `laravel-cloud` | `laravel_cloud/application` | @@ -83,18 +86,21 @@ Stripe Projects catalog reference. Offline catalog detail: | `neon` | `neon/postgres` | | `openrouter` | `openrouter/api` | | `parallel` | `parallel/api` | +| `perplexity` | `perplexity/api` | | `planetscale-mysql` | `planetscale/mysql` | | `planetscale-postgresql` | `planetscale/postgresql` | | `postalform` | `postalform/mail` | | `posthog` | `posthog/analytics` | | `prisma` | `prisma/database` | | `pydantic` | `pydantic/logfire` | +| `quo-app` | `quo/app` | | `railway-bucket` | `railway/bucket` | | `railway-hosting` | `railway/hosting` | | `railway-mongo` | `railway/mongo` | | `railway-postgres` | `railway/postgres` | | `railway-redis` | `railway/redis` | | `render-postgres` | `render/postgres` | +| `resend` | `resend/email` | | `revenuecat` | `revenuecat/app` | | `runloop` | `runloop/sandbox` | | `schematic` | `schematic/schematic-environment` | diff --git a/crates/stackless-integrations/provisional-allowlist.txt b/crates/stackless-integrations/provisional-allowlist.txt index e76dcee..922d58e 100644 --- a/crates/stackless-integrations/provisional-allowlist.txt +++ b/crates/stackless-integrations/provisional-allowlist.txt @@ -7,6 +7,10 @@ # Externally blocked integrations keep source on disk but omit `pub mod` # + registry row and live in EXCL — see docs/ADDING-A-PROVIDER.md # § External pin blockers. Those files are not scanned here. +athena/agents +churnkey/retention herenow/hosting perplexity/api +quo/app +resend/email shopify/store diff --git a/crates/stackless-integrations/src/providers/agentmail/api.rs b/crates/stackless-integrations/src/providers/agentmail/api.rs index 5e71dbf..8bcc1dd 100644 --- a/crates/stackless-integrations/src/providers/agentmail/api.rs +++ b/crates/stackless-integrations/src/providers/agentmail/api.rs @@ -74,7 +74,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_agentmail","provider_name":"AgentMail","service_id":"api","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider":"prvdr_agentmail","provider_name":"AgentMail","service_id":"api","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/agentphone/number.rs b/crates/stackless-integrations/src/providers/agentphone/number.rs index 92f623d..663412e 100644 --- a/crates/stackless-integrations/src/providers/agentphone/number.rs +++ b/crates/stackless-integrations/src/providers/agentphone/number.rs @@ -109,7 +109,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_number","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_agentphone","provider_name":"AgentPhone","service_id":"number","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"agent_name":{"description":"Name for the AI agent","type":"string"},"area_code":{"description":"Preferred 3-digit area code (optional)","type":"string"},"country":{"description":"Country for the phone number","enum":["US","CA"],"type":"string"}},"required":["agent_name"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_number","object":"v2.provisioning.provider_service_detail","provider":"prvdr_agentphone","provider_name":"AgentPhone","service_id":"number","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"agent_name":{"description":"Name for the AI agent","type":"string"},"area_code":{"description":"Preferred 3-digit area code (optional)","type":"string"},"country":{"description":"Country for the phone number","enum":["US","CA"],"type":"string"}},"required":["agent_name"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/algolia/application.rs b/crates/stackless-integrations/src/providers/algolia/application.rs index daec46d..2a2fc66 100644 --- a/crates/stackless-integrations/src/providers/algolia/application.rs +++ b/crates/stackless-integrations/src/providers/algolia/application.rs @@ -113,7 +113,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_application","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_algolia","provider_name":"Algolia","service_id":"application","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid","paid_pricing":[{"type":"free","configuration":{"accept_terms":"test-accept_terms","plan":"free"}}]},"configuration_schema":{"properties":{"accept_terms":{"type":"string"},"name":{"description":"Name of your Algolia application","type":"string"},"region":{"description":"Where your Algolia application will be created. This cannot be changed after provisioning.","enum":["EU West","US Central","US East","US West","United Kingdom"],"type":"string"}},"required":["name","region","accept_terms"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_application","object":"v2.provisioning.provider_service_detail","provider":"prvdr_algolia","provider_name":"Algolia","service_id":"application","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid","paid_pricing":[{"type":"free","configuration":{"accept_terms":"test-accept_terms","plan":"free"}}]},"configuration_schema":{"properties":{"accept_terms":{"type":"string"},"name":{"description":"Name of your Algolia application","type":"string"},"region":{"description":"Where your Algolia application will be created. This cannot be changed after provisioning.","enum":["EU West","US Central","US East","US West","United Kingdom"],"type":"string"}},"required":["name","region","accept_terms"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/amplitude/analytics.rs b/crates/stackless-integrations/src/providers/amplitude/analytics.rs index 402eff7..843c28c 100644 --- a/crates/stackless-integrations/src/providers/amplitude/analytics.rs +++ b/crates/stackless-integrations/src/providers/amplitude/analytics.rs @@ -77,7 +77,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_analytics","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_amplitude","provider_name":"Amplitude","service_id":"analytics","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_analytics","object":"v2.provisioning.provider_service_detail","provider":"prvdr_amplitude","provider_name":"Amplitude","service_id":"analytics","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/athena/agents.rs b/crates/stackless-integrations/src/providers/athena/agents.rs new file mode 100644 index 0000000..cad1758 --- /dev/null +++ b/crates/stackless-integrations/src/providers/athena/agents.rs @@ -0,0 +1,227 @@ +use std::collections::BTreeMap; + +use serde::Serialize; +use stackless_stripe_projects::catalog::verify::CatalogService; +use stackless_stripe_projects::provision::ProvisionContext; + +use super::FamilyResource; +use crate::error::IntegrationError; +use crate::hostable::{ConfigScope, Hostable, IntegrationHosting}; +use crate::registry; + +pub const RESOURCE_KIND: &str = "integration-athena"; + +#[derive(Debug, Serialize)] +pub struct AthenaAgentsConfig { + pub name: String, + pub instructions: String, + pub connect_mcp: String, + pub enable_image_generation: String, + pub enable_music_generation: String, + pub enable_live: String, + pub enable_coding: String, + pub enable_deep_research: String, + pub enable_google_maps: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub mcp_url: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub google_maps_api_key: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub starter_1: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub starter_2: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub starter_3: Option, +} + +impl CatalogService for AthenaAgentsConfig { + const REFERENCE: &'static str = "athena/agents"; +} + +#[derive(Debug)] +pub struct AthenaAgents; + +impl Hostable for AthenaAgents { + const PROVIDER: &'static str = "athena"; + const HOSTING: IntegrationHosting = IntegrationHosting::Managed; + const CONFIG_SCOPE: ConfigScope = ConfigScope::GlobalOnly; + const RESOURCE_KIND: &'static str = RESOURCE_KIND; + const OUTPUTS: &'static [&'static str] = &["agent_id", "api_key", "api_url"]; +} + +impl FamilyResource for AthenaAgents { + type Config = AthenaAgentsConfig; + const PROVIDER_PREFIX: &'static str = "ATHENA"; + // Provisional until pinned by `mise run discover athena/agents`. + const OUTPUT_FIELDS: &'static [(&'static str, &'static str, bool)] = &[ + ("AGENT_ID", "agent_id", true), + ("API_KEY", "api_key", true), + ("API_URL", "api_url", true), + ]; + + fn build_config(ctx: &ProvisionContext<'_>) -> Result { + let config = super::integration_config(ctx)?; + Ok(AthenaAgentsConfig { + name: super::interp_required(ctx, &config, "name")?, + instructions: super::interp_required(ctx, &config, "instructions")?, + connect_mcp: super::interp_required(ctx, &config, "connect_mcp")?, + enable_image_generation: super::interp_required( + ctx, + &config, + "enable_image_generation", + )?, + enable_music_generation: super::interp_required( + ctx, + &config, + "enable_music_generation", + )?, + enable_live: super::interp_required(ctx, &config, "enable_live")?, + enable_coding: super::interp_required(ctx, &config, "enable_coding")?, + enable_deep_research: super::interp_required(ctx, &config, "enable_deep_research")?, + enable_google_maps: super::interp_required(ctx, &config, "enable_google_maps")?, + mcp_url: super::interp_optional(ctx, &config, "mcp_url")?, + google_maps_api_key: super::interp_optional(ctx, &config, "google_maps_api_key")?, + starter_1: super::interp_optional(ctx, &config, "starter_1")?, + starter_2: super::interp_optional(ctx, &config, "starter_2")?, + starter_3: super::interp_optional(ctx, &config, "starter_3")?, + }) + } +} + +const REQUIRED_CONFIG_KEYS: &[&str] = &[ + "name", + "instructions", + "connect_mcp", + "enable_image_generation", + "enable_music_generation", + "enable_live", + "enable_coding", + "enable_deep_research", + "enable_google_maps", +]; + +pub fn validate_config( + name: &str, + config: &BTreeMap, +) -> Result<(), IntegrationError> { + for key in REQUIRED_CONFIG_KEYS { + registry::config_string(config, key).map_err(|err| IntegrationError::ConfigInvalid { + location: format!("integrations.{name}.{key}"), + detail: err.to_string(), + })?; + } + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::ProviderOps; + use crate::resource::ResourcePayload; + use stackless_core::def::StackDef; + use stackless_stripe_projects::stripe::StripeProjects; + use stackless_stripe_projects::test_support; + + fn sample_config() -> AthenaAgentsConfig { + AthenaAgentsConfig { + name: "test-name".into(), + instructions: "test-instructions".into(), + connect_mcp: "no".into(), + enable_image_generation: "no".into(), + enable_music_generation: "no".into(), + enable_live: "no".into(), + enable_coding: "no".into(), + enable_deep_research: "no".into(), + enable_google_maps: "no".into(), + mcp_url: None, + google_maps_api_key: None, + starter_1: None, + starter_2: None, + starter_3: None, + } + } + + #[test] + fn config_matches_catalog() { + const FIXTURE: &str = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../stackless-stripe-projects/tests/fixtures/catalog.json" + )); + let catalog = stackless_stripe_projects::Catalog::from_json_envelope(FIXTURE).unwrap(); + let failures = stackless_stripe_projects::verify_service(&catalog, &sample_config()); + assert!( + failures.is_empty(), + "athena/agents catalog gaps:\n{}", + failures.join("\n") + ); + } + + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"allowed_updates":[],"availability":"available","categories":["ai"],"configuration_schema":{"properties":{"connect_mcp":{"default":"no","description":"Connect one public HTTPS MCP server?","enum":["no","yes"],"type":"string"},"enable_coding":{"default":"no","description":"Enable coding and deep thinking?","enum":["no","yes"],"type":"string"},"enable_deep_research":{"default":"no","description":"Enable deep research?","enum":["no","yes"],"type":"string"},"enable_google_maps":{"default":"no","description":"Enable Google Maps?","enum":["no","yes"],"type":"string"},"enable_image_generation":{"default":"no","description":"Enable image generation?","enum":["no","yes"],"type":"string"},"enable_live":{"default":"no","description":"Enable live voice sessions?","enum":["no","yes"],"type":"string"},"enable_music_generation":{"default":"no","description":"Enable music generation?","enum":["no","yes"],"type":"string"},"google_maps_api_key":{"description":"Google Maps API key. Required only when Google Maps is enabled.","type":"string"},"instructions":{"description":"Instructions for the Athena agent (maximum 2,000 characters).","type":"string"},"mcp_url":{"description":"Public HTTPS MCP server URL. Leave blank when no MCP server is connected.","type":"string"},"name":{"description":"Name for the Athena agent.","type":"string"},"starter_1":{"description":"Optional first conversation starter shown on the public agent.","type":"string"},"starter_2":{"description":"Optional second conversation starter shown on the public agent.","type":"string"},"starter_3":{"description":"Optional third conversation starter shown on the public agent.","type":"string"}},"required":["name","instructions","connect_mcp","enable_image_generation","enable_music_generation","enable_live","enable_coding","enable_deep_research","enable_google_maps"],"type":"object"},"constraints":[],"created":null,"description":"Configurable Athena AI agent with an optional public HTTPS MCP server.","development":false,"group":null,"id":"prvsvc_61VNv58mq1zOThOYP5VZA","kind":"deployable","livemode":true,"llm_context":null,"object":"v2.provisioning.provider_service_detail","pricing":{"component":null,"paid":null,"paid_pricing":[],"type":"free"},"provider":"prvdr_61VNueP9cELmCU01Z5DFA","provider_configuration_schema":{},"provider_name":"Athena","scope":"project","service_id":"agents","updateable_to":["agents"]}]}}"##; + + fn test_def() -> StackDef { + StackDef::parse( + r#" +[stack] +name = "atto" +[stack.projects.stripe] +project = "project_1" +[integrations.res] +provider = "athena" +name = "demo-name" +instructions = "demo-instructions" +connect_mcp = "no" +enable_image_generation = "no" +enable_music_generation = "no" +enable_live = "no" +enable_coding = "no" +enable_deep_research = "no" +enable_google_maps = "no" +[services.api] +source = { repo = "r", ref = "main" } +env = { OUT = "${integrations.res.api_key}" } +health = { path = "/health" } +[services.api.local] +run = "true" +"#, + ) + .unwrap() + } + + #[tokio::test] + async fn provision_records_outputs() { + let runner = test_support::provision_script( + CATALOG_ENVELOPE, + serde_json::json!({ + "ATHENA_AGENT_ID": "val_agent_id", + "ATHENA_API_KEY": "val_api_key", + "ATHENA_API_URL": "val_api_url" + }), + 0, + ); + let dir = tempfile::tempdir().unwrap(); + std::fs::write( + dir.path().join("stackless.toml"), + "[stack]\nname=\"atto\"\n", + ) + .unwrap(); + let stripe = StripeProjects::new(&runner, dir.path()); + + let resource = AthenaAgents + .provision( + &stripe.as_dyn(), + &test_def(), + dir.path(), + "demo", + "res", + "local", + false, + ) + .await + .unwrap(); + assert_eq!(resource.resource_kind, "integration-athena"); + let payload: ResourcePayload = serde_json::from_str(&resource.payload).unwrap(); + assert_eq!(payload.outputs["agent_id"], "val_agent_id"); + assert_eq!(payload.outputs["api_key"], "val_api_key"); + assert_eq!(payload.outputs["api_url"], "val_api_url"); + } +} diff --git a/crates/stackless-integrations/src/providers/athena/mod.rs b/crates/stackless-integrations/src/providers/athena/mod.rs new file mode 100644 index 0000000..b37829c --- /dev/null +++ b/crates/stackless-integrations/src/providers/athena/mod.rs @@ -0,0 +1,5 @@ +pub mod agents; + +pub(crate) use crate::resource::{ + CatalogResource as FamilyResource, integration_config, interp_optional, interp_required, +}; diff --git a/crates/stackless-integrations/src/providers/auth0/client.rs b/crates/stackless-integrations/src/providers/auth0/client.rs index dd2c983..b9beafc 100644 --- a/crates/stackless-integrations/src/providers/auth0/client.rs +++ b/crates/stackless-integrations/src/providers/auth0/client.rs @@ -91,7 +91,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_client","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_auth0","provider_name":"Auth0","service_id":"client","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"name":{"minLength":1,"type":"string"}},"required":["name"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_client","object":"v2.provisioning.provider_service_detail","provider":"prvdr_auth0","provider_name":"Auth0","service_id":"client","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"name":{"minLength":1,"type":"string"}},"required":["name"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/base44_projects/app.rs b/crates/stackless-integrations/src/providers/base44_projects/app.rs index 6c99f4d..d03f107 100644 --- a/crates/stackless-integrations/src/providers/base44_projects/app.rs +++ b/crates/stackless-integrations/src/providers/base44_projects/app.rs @@ -93,7 +93,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_app","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_base44_projects","provider_name":"Base44_Projects","service_id":"app","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"additionalProperties":false,"properties":{"app_name":{"description":"Human-readable name for the Base44 app. Shown in the Base44 dashboard.","maxLength":50,"minLength":1,"title":"App name","type":"string"}},"required":[],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_app","object":"v2.provisioning.provider_service_detail","provider":"prvdr_base44_projects","provider_name":"Base44_Projects","service_id":"app","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"additionalProperties":false,"properties":{"app_name":{"description":"Human-readable name for the Base44 app. Shown in the Base44 dashboard.","maxLength":50,"minLength":1,"title":"App name","type":"string"}},"required":[],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/blaxel/agent_drive.rs b/crates/stackless-integrations/src/providers/blaxel/agent_drive.rs index e51e608..98fe73b 100644 --- a/crates/stackless-integrations/src/providers/blaxel/agent_drive.rs +++ b/crates/stackless-integrations/src/providers/blaxel/agent_drive.rs @@ -99,7 +99,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_agent_drive","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_blaxel","provider_name":"Blaxel","service_id":"agent-drive","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"additionalProperties":false,"properties":{"display_name":{"description":"Human-readable display name shown in the Blaxel dashboard.","type":"string"},"region":{"description":"Region where the drive is created.","enum":["us-was-1"],"type":"string"},"size":{"description":"Drive size in GB.","enum":[1,5,10,50,100],"type":"integer"}},"required":[],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_agent_drive","object":"v2.provisioning.provider_service_detail","provider":"prvdr_blaxel","provider_name":"Blaxel","service_id":"agent-drive","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"additionalProperties":false,"properties":{"display_name":{"description":"Human-readable display name shown in the Blaxel dashboard.","type":"string"},"region":{"description":"Region where the drive is created.","enum":["us-was-1"],"type":"string"},"size":{"description":"Drive size in GB.","enum":[1,5,10,50,100],"type":"integer"}},"required":[],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/blaxel/sandbox.rs b/crates/stackless-integrations/src/providers/blaxel/sandbox.rs index f560f5f..1c2574f 100644 --- a/crates/stackless-integrations/src/providers/blaxel/sandbox.rs +++ b/crates/stackless-integrations/src/providers/blaxel/sandbox.rs @@ -113,7 +113,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_sandbox","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_blaxel","provider_name":"Blaxel","service_id":"sandbox","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"additionalProperties":false,"properties":{"display_name":{"description":"Human-readable display name shown in the Blaxel dashboard.","type":"string"},"image":{"description":"Base image for the sandbox.","enum":["blaxel/base-image:latest","blaxel/ts-app:latest","blaxel/node:latest","blaxel/py-app:latest","blaxel/nextjs:latest","blaxel/vite:latest","blaxel/expo:latest"],"type":"string"},"memory":{"description":"Memory in MB. CPU is derived automatically.","enum":[1024,2048,4096,8192,16384],"type":"integer"},"region":{"description":"Region where the sandbox runs.","enum":["us-pdx-1","us-was-1","eu-lon-1","eu-fra-1"],"type":"string"},"ttl":{"description":"Max-age TTL from creation. Sandbox is deleted after this duration.","enum":["24h","7d","30d"],"type":"string"}},"required":[],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_sandbox","object":"v2.provisioning.provider_service_detail","provider":"prvdr_blaxel","provider_name":"Blaxel","service_id":"sandbox","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"additionalProperties":false,"properties":{"display_name":{"description":"Human-readable display name shown in the Blaxel dashboard.","type":"string"},"image":{"description":"Base image for the sandbox.","enum":["blaxel/base-image:latest","blaxel/ts-app:latest","blaxel/node:latest","blaxel/py-app:latest","blaxel/nextjs:latest","blaxel/vite:latest","blaxel/expo:latest"],"type":"string"},"memory":{"description":"Memory in MB. CPU is derived automatically.","enum":[1024,2048,4096,8192,16384],"type":"integer"},"region":{"description":"Region where the sandbox runs.","enum":["us-pdx-1","us-was-1","eu-lon-1","eu-fra-1"],"type":"string"},"ttl":{"description":"Max-age TTL from creation. Sandbox is deleted after this duration.","enum":["24h","7d","30d"],"type":"string"}},"required":[],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/browserbase/project.rs b/crates/stackless-integrations/src/providers/browserbase/project.rs index 18f85b3..8078744 100644 --- a/crates/stackless-integrations/src/providers/browserbase/project.rs +++ b/crates/stackless-integrations/src/providers/browserbase/project.rs @@ -79,7 +79,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_project","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_browserbase","provider_name":"Browserbase","service_id":"project","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_project","object":"v2.provisioning.provider_service_detail","provider":"prvdr_browserbase","provider_name":"Browserbase","service_id":"project","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/chatbase/agent.rs b/crates/stackless-integrations/src/providers/chatbase/agent.rs index 9cc0ae7..0a491d2 100644 --- a/crates/stackless-integrations/src/providers/chatbase/agent.rs +++ b/crates/stackless-integrations/src/providers/chatbase/agent.rs @@ -92,7 +92,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_agent","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_chatbase","provider_name":"Chatbase","service_id":"agent","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"name":{"type":"string"}},"type":"object","required":["name"]}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_agent","object":"v2.provisioning.provider_service_detail","provider":"prvdr_chatbase","provider_name":"Chatbase","service_id":"agent","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"name":{"type":"string"}},"type":"object","required":["name"]}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/chroma/database.rs b/crates/stackless-integrations/src/providers/chroma/database.rs index 35e0d12..17a4970 100644 --- a/crates/stackless-integrations/src/providers/chroma/database.rs +++ b/crates/stackless-integrations/src/providers/chroma/database.rs @@ -89,7 +89,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_database","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_chroma","provider_name":"Chroma","service_id":"database","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"name":{"description":"Name for the database (defaults to 'agent'). Must be at least 3 characters, using only letters, numbers, underscores, and hyphens.","minLength":3,"type":"string"}},"required":["name"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_database","object":"v2.provisioning.provider_service_detail","provider":"prvdr_chroma","provider_name":"Chroma","service_id":"database","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"name":{"description":"Name for the database (defaults to 'agent'). Must be at least 3 characters, using only letters, numbers, underscores, and hyphens.","minLength":3,"type":"string"}},"required":["name"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/churnkey/mod.rs b/crates/stackless-integrations/src/providers/churnkey/mod.rs new file mode 100644 index 0000000..1b87d84 --- /dev/null +++ b/crates/stackless-integrations/src/providers/churnkey/mod.rs @@ -0,0 +1,5 @@ +pub mod retention; + +pub(crate) use crate::resource::{ + CatalogResource as FamilyResource, integration_config, interp_optional, +}; diff --git a/crates/stackless-integrations/src/providers/churnkey/retention.rs b/crates/stackless-integrations/src/providers/churnkey/retention.rs new file mode 100644 index 0000000..0a6685a --- /dev/null +++ b/crates/stackless-integrations/src/providers/churnkey/retention.rs @@ -0,0 +1,151 @@ +use std::collections::BTreeMap; + +use serde::Serialize; +use stackless_stripe_projects::catalog::verify::CatalogService; +use stackless_stripe_projects::provision::ProvisionContext; + +use super::FamilyResource; +use crate::error::IntegrationError; +use crate::hostable::{ConfigScope, Hostable, IntegrationHosting}; + +pub const RESOURCE_KIND: &str = "integration-churnkey"; + +#[derive(Debug, Serialize)] +pub struct ChurnkeyRetentionConfig { + #[serde(skip_serializing_if = "Option::is_none")] + pub company_name: Option, +} + +impl CatalogService for ChurnkeyRetentionConfig { + const REFERENCE: &'static str = "churnkey/retention"; +} + +#[derive(Debug)] +pub struct ChurnkeyRetention; + +impl Hostable for ChurnkeyRetention { + const PROVIDER: &'static str = "churnkey"; + const HOSTING: IntegrationHosting = IntegrationHosting::Managed; + const CONFIG_SCOPE: ConfigScope = ConfigScope::GlobalOnly; + const RESOURCE_KIND: &'static str = RESOURCE_KIND; + const OUTPUTS: &'static [&'static str] = &["app_id", "api_key", "data_api_key", "mode"]; +} + +impl FamilyResource for ChurnkeyRetention { + type Config = ChurnkeyRetentionConfig; + const PROVIDER_PREFIX: &'static str = "CHURNKEY"; + // Provisional until pinned by `mise run discover churnkey/retention`. + const OUTPUT_FIELDS: &'static [(&'static str, &'static str, bool)] = &[ + ("APP_ID", "app_id", true), + ("API_KEY", "api_key", true), + ("DATA_API_KEY", "data_api_key", true), + ("MODE", "mode", true), + ]; + + fn build_config( + ctx: &ProvisionContext<'_>, + ) -> Result { + let config = super::integration_config(ctx)?; + Ok(ChurnkeyRetentionConfig { + company_name: super::interp_optional(ctx, &config, "company_name")?, + }) + } +} + +pub fn validate_config( + name: &str, + config: &BTreeMap, +) -> Result<(), IntegrationError> { + let _ = (name, config); + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::ProviderOps; + use crate::resource::ResourcePayload; + use stackless_core::def::StackDef; + use stackless_stripe_projects::stripe::StripeProjects; + use stackless_stripe_projects::test_support; + + #[test] + fn config_matches_catalog() { + const FIXTURE: &str = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../stackless-stripe-projects/tests/fixtures/catalog.json" + )); + let catalog = stackless_stripe_projects::Catalog::from_json_envelope(FIXTURE).unwrap(); + let failures = stackless_stripe_projects::verify_service( + &catalog, + &ChurnkeyRetentionConfig { company_name: None }, + ); + assert!( + failures.is_empty(), + "churnkey/retention catalog gaps:\n{}", + failures.join("\n") + ); + } + + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_retention","object":"v2.provisioning.provider_service_detail","provider":"prvdr_churnkey","provider_name":"Churnkey","service_id":"retention","categories":["payments"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"properties":{"company_name":{"description":"Your company name as shown to customers in the cancel flow","type":"string"}},"type":"object"}}]}}"##; + + fn test_def() -> StackDef { + StackDef::parse( + r#" +[stack] +name = "atto" +[stack.projects.stripe] +project = "project_1" +[integrations.res] +provider = "churnkey" +[services.api] +source = { repo = "r", ref = "main" } +env = { OUT = "${integrations.res.api_key}" } +health = { path = "/health" } +[services.api.local] +run = "true" +"#, + ) + .unwrap() + } + + #[tokio::test] + async fn provision_records_outputs() { + let runner = test_support::provision_script( + CATALOG_ENVELOPE, + serde_json::json!({ + "CHURNKEY_APP_ID": "val_app_id", + "CHURNKEY_API_KEY": "val_api_key", + "CHURNKEY_DATA_API_KEY": "val_data_api_key", + "CHURNKEY_MODE": "val_mode" + }), + 0, + ); + let dir = tempfile::tempdir().unwrap(); + std::fs::write( + dir.path().join("stackless.toml"), + "[stack]\nname=\"atto\"\n", + ) + .unwrap(); + let stripe = StripeProjects::new(&runner, dir.path()); + + let resource = ChurnkeyRetention + .provision( + &stripe.as_dyn(), + &test_def(), + dir.path(), + "demo", + "res", + "local", + false, + ) + .await + .unwrap(); + assert_eq!(resource.resource_kind, "integration-churnkey"); + let payload: ResourcePayload = serde_json::from_str(&resource.payload).unwrap(); + assert_eq!(payload.outputs["app_id"], "val_app_id"); + assert_eq!(payload.outputs["api_key"], "val_api_key"); + assert_eq!(payload.outputs["data_api_key"], "val_data_api_key"); + assert_eq!(payload.outputs["mode"], "val_mode"); + } +} diff --git a/crates/stackless-integrations/src/providers/clerk.rs b/crates/stackless-integrations/src/providers/clerk.rs index 406418b..db3c7f3 100644 --- a/crates/stackless-integrations/src/providers/clerk.rs +++ b/crates/stackless-integrations/src/providers/clerk.rs @@ -481,7 +481,7 @@ mod tests { const CLERK_CATALOG_ENVELOPE: &str = r#"{"ok":true,"command":"projects catalog","data":{ "last_updated":"2026-06-12T00:00:00Z","services":[{ "id":"prvsvc_clerk","object":"v2.provisioning.provider_service_detail", - "provider_id":"prvdr_clerk","provider_name":"Clerk","service_id":"auth", + "provider":"prvdr_clerk","provider_name":"Clerk","service_id":"auth", "categories":["auth"],"kind":"deployable","scope":"project","availability":"available", "development":false,"livemode":true,"pricing":{"type":"component"}, "configuration_schema":{"type":"object","required":["app_name"],"additionalProperties":false, diff --git a/crates/stackless-integrations/src/providers/clickhouse/cluster.rs b/crates/stackless-integrations/src/providers/clickhouse/cluster.rs index 3d4e8fd..a9f9590 100644 --- a/crates/stackless-integrations/src/providers/clickhouse/cluster.rs +++ b/crates/stackless-integrations/src/providers/clickhouse/cluster.rs @@ -157,7 +157,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_clickhouse","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_clickhouse","provider_name":"ClickHouse","service_id":"clickhouse","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"additionalProperties":false,"properties":{"idleScaling":{"description":"When true, compute scales to zero after idleTimeoutMinutes of inactivity and bills $0/hour during idle periods. Defaults to false when omitted.","type":"boolean"},"idleTimeoutMinutes":{"description":"Minutes of inactivity before idle scale-down triggers. Only meaningful when idleScaling=true. Defaults to 60 when omitted.","maximum":1440,"minimum":5,"type":"integer"},"maxReplicaMemoryGb":{"default":12,"description":"Autoscale upper bound: memory per replica, in GiB. Must be \u2265 minReplicaMemoryGb (enforced server-side). Accepts 8\u2013356 GiB per replica in steps of 4; the maximum drops to 236 GiB on AWS regions due to UI caps.","maximum":356,"minimum":8,"multipleOf":4,"type":"integer"},"minReplicaMemoryGb":{"default":12,"description":"Autoscale lower bound: memory per replica, in GiB. Must be \u2264 maxReplicaMemoryGb (enforced server-side). Accepts 8\u2013356 GiB per replica in steps of 4; the maximum drops to 236 GiB on AWS regions due to UI caps.","maximum":356,"minimum":8,"multipleOf":4,"type":"integer"},"name":{"description":"Human-readable name for the ClickHouse service.","maxLength":64,"minLength":1,"type":"string"},"numReplicas":{"default":2,"description":"Number of replicas (HA). Defaults to 2 when omitted. Each replica meters compute independently, so total compute cost scales linearly with numReplicas.","maximum":100,"minimum":1,"type":"integer"},"region":{"description":"Cloud provider and region to host the service in, as a single cloud-qualified id (e.g. aws-us-east-1, gcp-us-east1, azure-eastus). The cloud provider is encoded in the value, so no separate field is needed. Pricing varies per region.","enum":["aws-us-west-2","aws-us-east-2","aws-us-east-1","aws-eu-west-1","aws-eu-west-2","aws-eu-central-1","aws-ap-southeast-1","aws-ap-southeast-2","aws-ap-northeast-1","aws-ap-south-1","aws-ap-northeast-2","aws-il-central-1","gcp-us-east1","gcp-us-central1","gcp-europe-west2","gcp-europe-west4","gcp-asia-southeast1","gcp-asia-northeast1","azure-germanywestcentral","azure-eastus2","azure-westus3"],"type":"string"}},"required":["name","region","minReplicaMemoryGb","maxReplicaMemoryGb"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_clickhouse","object":"v2.provisioning.provider_service_detail","provider":"prvdr_clickhouse","provider_name":"ClickHouse","service_id":"clickhouse","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"additionalProperties":false,"properties":{"idleScaling":{"description":"When true, compute scales to zero after idleTimeoutMinutes of inactivity and bills $0/hour during idle periods. Defaults to false when omitted.","type":"boolean"},"idleTimeoutMinutes":{"description":"Minutes of inactivity before idle scale-down triggers. Only meaningful when idleScaling=true. Defaults to 60 when omitted.","maximum":1440,"minimum":5,"type":"integer"},"maxReplicaMemoryGb":{"default":12,"description":"Autoscale upper bound: memory per replica, in GiB. Must be \u2265 minReplicaMemoryGb (enforced server-side). Accepts 8\u2013356 GiB per replica in steps of 4; the maximum drops to 236 GiB on AWS regions due to UI caps.","maximum":356,"minimum":8,"multipleOf":4,"type":"integer"},"minReplicaMemoryGb":{"default":12,"description":"Autoscale lower bound: memory per replica, in GiB. Must be \u2264 maxReplicaMemoryGb (enforced server-side). Accepts 8\u2013356 GiB per replica in steps of 4; the maximum drops to 236 GiB on AWS regions due to UI caps.","maximum":356,"minimum":8,"multipleOf":4,"type":"integer"},"name":{"description":"Human-readable name for the ClickHouse service.","maxLength":64,"minLength":1,"type":"string"},"numReplicas":{"default":2,"description":"Number of replicas (HA). Defaults to 2 when omitted. Each replica meters compute independently, so total compute cost scales linearly with numReplicas.","maximum":100,"minimum":1,"type":"integer"},"region":{"description":"Cloud provider and region to host the service in, as a single cloud-qualified id (e.g. aws-us-east-1, gcp-us-east1, azure-eastus). The cloud provider is encoded in the value, so no separate field is needed. Pricing varies per region.","enum":["aws-us-west-2","aws-us-east-2","aws-us-east-1","aws-eu-west-1","aws-eu-west-2","aws-eu-central-1","aws-ap-southeast-1","aws-ap-southeast-2","aws-ap-northeast-1","aws-ap-south-1","aws-ap-northeast-2","aws-il-central-1","gcp-us-east1","gcp-us-central1","gcp-europe-west2","gcp-europe-west4","gcp-asia-southeast1","gcp-asia-northeast1","azure-germanywestcentral","azure-eastus2","azure-westus3"],"type":"string"}},"required":["name","region","minReplicaMemoryGb","maxReplicaMemoryGb"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/clickhouse/postgres.rs b/crates/stackless-integrations/src/providers/clickhouse/postgres.rs index 32d13d1..26f3149 100644 --- a/crates/stackless-integrations/src/providers/clickhouse/postgres.rs +++ b/crates/stackless-integrations/src/providers/clickhouse/postgres.rs @@ -129,7 +129,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_postgres","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_clickhouse","provider_name":"ClickHouse","service_id":"postgres","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"additionalProperties":false,"properties":{"haType":{"description":"High-availability mode. Defaults to \"none\" when omitted.","enum":["none","async","sync"],"type":"string"},"name":{"description":"Human-readable name for the Postgres instance.","maxLength":50,"minLength":1,"type":"string"},"postgresVersion":{"description":"Major Postgres version. Defaults to the latest available when omitted.","enum":["18","17"],"type":"string"},"region":{"description":"Cloud provider and region to host the service in, as a single cloud-qualified id (e.g. aws-us-east-1). The cloud provider is encoded in the value, so no separate field is needed. Pricing varies per region.","enum":["aws-ap-northeast-1","aws-ap-northeast-2","aws-ap-south-1","aws-ap-southeast-1","aws-ap-southeast-2","aws-eu-central-1","aws-eu-west-1","aws-eu-west-2","aws-us-east-1","aws-us-east-2","aws-us-west-2"],"type":"string"},"size":{"description":"VM instance type determining CPU, memory, and storage.","enum":["c6gd.large","c6gd.xlarge","c6gd.2xlarge","c6gd.4xlarge","c6gd.8xlarge","c6gd.16xlarge","i7i.large","i7i.xlarge","i7i.2xlarge","i7i.4xlarge","i7i.8xlarge","i7i.12xlarge","i7i.16xlarge","i7i.24xlarge","i7ie.large","i7ie.xlarge","i7ie.2xlarge","i7ie.3xlarge","i7ie.6xlarge","i7ie.12xlarge","i7ie.18xlarge","i7ie.24xlarge","i8g.large","i8g.xlarge","i8g.2xlarge","i8g.4xlarge","i8g.8xlarge","i8g.16xlarge","i8g.24xlarge","i8ge.large","i8ge.xlarge","i8ge.2xlarge","i8ge.3xlarge","i8ge.6xlarge","i8ge.12xlarge","i8ge.18xlarge","i8ge.24xlarge","m6gd.large","m6gd.xlarge","m6gd.2xlarge","m6gd.4xlarge","m6gd.8xlarge","m6gd.16xlarge","m6id.large","m6id.xlarge","m6id.2xlarge","m6id.4xlarge","m6id.8xlarge","m6id.16xlarge","m8gd.large","m8gd.xlarge","m8gd.2xlarge","m8gd.4xlarge","m8gd.8xlarge","m8gd.16xlarge","r6gd.medium","r6gd.large","r6gd.xlarge","r6gd.2xlarge","r6gd.4xlarge","r6gd.8xlarge","r6gd.12xlarge","r6gd.16xlarge","r6id.large","r6id.xlarge","r6id.2xlarge","r6id.4xlarge","r6id.8xlarge","r6id.12xlarge","r6id.16xlarge","r6id.24xlarge","r6id.32xlarge","r8gd.medium","r8gd.large","r8gd.xlarge","r8gd.2xlarge","r8gd.4xlarge","r8gd.8xlarge","r8gd.12xlarge","r8gd.16xlarge","r8gd.24xlarge","r8gd.48xlarge"],"type":"string"}},"required":["name","region","size"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_postgres","object":"v2.provisioning.provider_service_detail","provider":"prvdr_clickhouse","provider_name":"ClickHouse","service_id":"postgres","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"additionalProperties":false,"properties":{"haType":{"description":"High-availability mode. Defaults to \"none\" when omitted.","enum":["none","async","sync"],"type":"string"},"name":{"description":"Human-readable name for the Postgres instance.","maxLength":50,"minLength":1,"type":"string"},"postgresVersion":{"description":"Major Postgres version. Defaults to the latest available when omitted.","enum":["18","17"],"type":"string"},"region":{"description":"Cloud provider and region to host the service in, as a single cloud-qualified id (e.g. aws-us-east-1). The cloud provider is encoded in the value, so no separate field is needed. Pricing varies per region.","enum":["aws-ap-northeast-1","aws-ap-northeast-2","aws-ap-south-1","aws-ap-southeast-1","aws-ap-southeast-2","aws-eu-central-1","aws-eu-west-1","aws-eu-west-2","aws-us-east-1","aws-us-east-2","aws-us-west-2"],"type":"string"},"size":{"description":"VM instance type determining CPU, memory, and storage.","enum":["c6gd.large","c6gd.xlarge","c6gd.2xlarge","c6gd.4xlarge","c6gd.8xlarge","c6gd.16xlarge","i7i.large","i7i.xlarge","i7i.2xlarge","i7i.4xlarge","i7i.8xlarge","i7i.12xlarge","i7i.16xlarge","i7i.24xlarge","i7ie.large","i7ie.xlarge","i7ie.2xlarge","i7ie.3xlarge","i7ie.6xlarge","i7ie.12xlarge","i7ie.18xlarge","i7ie.24xlarge","i8g.large","i8g.xlarge","i8g.2xlarge","i8g.4xlarge","i8g.8xlarge","i8g.16xlarge","i8g.24xlarge","i8ge.large","i8ge.xlarge","i8ge.2xlarge","i8ge.3xlarge","i8ge.6xlarge","i8ge.12xlarge","i8ge.18xlarge","i8ge.24xlarge","m6gd.large","m6gd.xlarge","m6gd.2xlarge","m6gd.4xlarge","m6gd.8xlarge","m6gd.16xlarge","m6id.large","m6id.xlarge","m6id.2xlarge","m6id.4xlarge","m6id.8xlarge","m6id.16xlarge","m8gd.large","m8gd.xlarge","m8gd.2xlarge","m8gd.4xlarge","m8gd.8xlarge","m8gd.16xlarge","r6gd.medium","r6gd.large","r6gd.xlarge","r6gd.2xlarge","r6gd.4xlarge","r6gd.8xlarge","r6gd.12xlarge","r6gd.16xlarge","r6id.large","r6id.xlarge","r6id.2xlarge","r6id.4xlarge","r6id.8xlarge","r6id.12xlarge","r6id.16xlarge","r6id.24xlarge","r6id.32xlarge","r8gd.medium","r8gd.large","r8gd.xlarge","r8gd.2xlarge","r8gd.4xlarge","r8gd.8xlarge","r8gd.12xlarge","r8gd.16xlarge","r8gd.24xlarge","r8gd.48xlarge"],"type":"string"}},"required":["name","region","size"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/cloudflare/browser_run.rs b/crates/stackless-integrations/src/providers/cloudflare/browser_run.rs index 0a45f85..55f035a 100644 --- a/crates/stackless-integrations/src/providers/cloudflare/browser_run.rs +++ b/crates/stackless-integrations/src/providers/cloudflare/browser_run.rs @@ -85,7 +85,7 @@ mod tests { const CATALOG_ENVELOPE: &str = r#"{"ok":true,"command":"projects catalog","data":{ "last_updated":"2026-06-16T00:00:00Z","services":[{ "id":"prvsvc_br","object":"v2.provisioning.provider_service_detail", - "provider_id":"prvdr_cloudflare","provider_name":"Cloudflare","service_id":"browser-run", + "provider":"prvdr_cloudflare","provider_name":"Cloudflare","service_id":"browser-run", "categories":["compute"],"kind":"deployable","scope":"project","availability":"available", "development":false,"livemode":true,"pricing":{"type":"component"}, "configuration_schema":{"type":"object","additionalProperties":false,"properties":{}} diff --git a/crates/stackless-integrations/src/providers/cloudflare/d1.rs b/crates/stackless-integrations/src/providers/cloudflare/d1.rs index cf6b320..02be5e7 100644 --- a/crates/stackless-integrations/src/providers/cloudflare/d1.rs +++ b/crates/stackless-integrations/src/providers/cloudflare/d1.rs @@ -98,7 +98,7 @@ mod tests { const D1_CATALOG_ENVELOPE: &str = r#"{"ok":true,"command":"projects catalog","data":{ "last_updated":"2026-06-16T00:00:00Z","services":[{ "id":"prvsvc_d1","object":"v2.provisioning.provider_service_detail", - "provider_id":"prvdr_cloudflare","provider_name":"Cloudflare","service_id":"d1", + "provider":"prvdr_cloudflare","provider_name":"Cloudflare","service_id":"d1", "categories":["database"],"kind":"deployable","scope":"project","availability":"available", "development":false,"livemode":true,"pricing":{"type":"component"}, "configuration_schema":{"type":"object","required":["name"],"additionalProperties":false, diff --git a/crates/stackless-integrations/src/providers/cloudflare/hyperdrive.rs b/crates/stackless-integrations/src/providers/cloudflare/hyperdrive.rs index 6ddb962..8e8280c 100644 --- a/crates/stackless-integrations/src/providers/cloudflare/hyperdrive.rs +++ b/crates/stackless-integrations/src/providers/cloudflare/hyperdrive.rs @@ -137,7 +137,7 @@ mod tests { const HYPERDRIVE_CATALOG_ENVELOPE: &str = r#"{"ok":true,"command":"projects catalog","data":{ "last_updated":"2026-06-16T00:00:00Z","services":[{ "id":"prvsvc_hd","object":"v2.provisioning.provider_service_detail", - "provider_id":"prvdr_cloudflare","provider_name":"Cloudflare","service_id":"hyperdrive", + "provider":"prvdr_cloudflare","provider_name":"Cloudflare","service_id":"hyperdrive", "categories":["database"],"kind":"deployable","scope":"project","availability":"available", "development":false,"livemode":true,"pricing":{"type":"component"}, "configuration_schema":{"type":"object", diff --git a/crates/stackless-integrations/src/providers/cloudflare/kv.rs b/crates/stackless-integrations/src/providers/cloudflare/kv.rs index 6a55f2a..6af96e5 100644 --- a/crates/stackless-integrations/src/providers/cloudflare/kv.rs +++ b/crates/stackless-integrations/src/providers/cloudflare/kv.rs @@ -93,7 +93,7 @@ mod tests { const KV_CATALOG_ENVELOPE: &str = r#"{"ok":true,"command":"projects catalog","data":{ "last_updated":"2026-06-16T00:00:00Z","services":[{ "id":"prvsvc_kv","object":"v2.provisioning.provider_service_detail", - "provider_id":"prvdr_cloudflare","provider_name":"Cloudflare","service_id":"kv", + "provider":"prvdr_cloudflare","provider_name":"Cloudflare","service_id":"kv", "categories":["cache"],"kind":"deployable","scope":"project","availability":"available", "development":false,"livemode":true,"pricing":{"type":"component"}, "configuration_schema":{"type":"object","required":["title"],"additionalProperties":false, diff --git a/crates/stackless-integrations/src/providers/cloudflare/queues.rs b/crates/stackless-integrations/src/providers/cloudflare/queues.rs index fd65154..59c7273 100644 --- a/crates/stackless-integrations/src/providers/cloudflare/queues.rs +++ b/crates/stackless-integrations/src/providers/cloudflare/queues.rs @@ -104,7 +104,7 @@ mod tests { const QUEUES_CATALOG_ENVELOPE: &str = r#"{"ok":true,"command":"projects catalog","data":{ "last_updated":"2026-06-16T00:00:00Z","services":[{ "id":"prvsvc_queues","object":"v2.provisioning.provider_service_detail", - "provider_id":"prvdr_cloudflare","provider_name":"Cloudflare","service_id":"queues", + "provider":"prvdr_cloudflare","provider_name":"Cloudflare","service_id":"queues", "categories":["queue"],"kind":"deployable","scope":"project","availability":"available", "development":false,"livemode":true,"pricing":{"type":"component"}, "configuration_schema":{"type":"object","required":["queue_name"],"additionalProperties":false, diff --git a/crates/stackless-integrations/src/providers/cloudflare/r2.rs b/crates/stackless-integrations/src/providers/cloudflare/r2.rs index c7b3a62..f4136bf 100644 --- a/crates/stackless-integrations/src/providers/cloudflare/r2.rs +++ b/crates/stackless-integrations/src/providers/cloudflare/r2.rs @@ -119,7 +119,7 @@ mod tests { const R2_CATALOG_ENVELOPE: &str = r#"{"ok":true,"command":"projects catalog","data":{ "last_updated":"2026-06-16T00:00:00Z","services":[{ "id":"prvsvc_r2","object":"v2.provisioning.provider_service_detail", - "provider_id":"prvdr_cloudflare","provider_name":"Cloudflare","service_id":"r2:bucket", + "provider":"prvdr_cloudflare","provider_name":"Cloudflare","service_id":"r2:bucket", "categories":["storage"],"kind":"deployable","scope":"project","availability":"available", "development":false,"livemode":true, "pricing":{"type":"paid","paid_pricing":[{"type":"freeform","freeform":"usage-based"}]}, diff --git a/crates/stackless-integrations/src/providers/cloudflare/workers.rs b/crates/stackless-integrations/src/providers/cloudflare/workers.rs index b017ff6..090155c 100644 --- a/crates/stackless-integrations/src/providers/cloudflare/workers.rs +++ b/crates/stackless-integrations/src/providers/cloudflare/workers.rs @@ -90,7 +90,7 @@ mod tests { const WORKERS_CATALOG_ENVELOPE: &str = r#"{"ok":true,"command":"projects catalog","data":{ "last_updated":"2026-06-16T00:00:00Z","services":[{ "id":"prvsvc_workers","object":"v2.provisioning.provider_service_detail", - "provider_id":"prvdr_cloudflare","provider_name":"Cloudflare","service_id":"workers", + "provider":"prvdr_cloudflare","provider_name":"Cloudflare","service_id":"workers", "categories":["compute"],"kind":"deployable","scope":"project","availability":"available", "development":false,"livemode":true,"pricing":{"type":"component"}, "configuration_schema":{"type":"object","additionalProperties":false,"properties":{}} diff --git a/crates/stackless-integrations/src/providers/cloudflare/workers_ai.rs b/crates/stackless-integrations/src/providers/cloudflare/workers_ai.rs index 200fbe2..a02415a 100644 --- a/crates/stackless-integrations/src/providers/cloudflare/workers_ai.rs +++ b/crates/stackless-integrations/src/providers/cloudflare/workers_ai.rs @@ -85,7 +85,7 @@ mod tests { const CATALOG_ENVELOPE: &str = r#"{"ok":true,"command":"projects catalog","data":{ "last_updated":"2026-06-16T00:00:00Z","services":[{ "id":"prvsvc_wai","object":"v2.provisioning.provider_service_detail", - "provider_id":"prvdr_cloudflare","provider_name":"Cloudflare","service_id":"workers-ai", + "provider":"prvdr_cloudflare","provider_name":"Cloudflare","service_id":"workers-ai", "categories":["compute"],"kind":"deployable","scope":"project","availability":"available", "development":false,"livemode":true,"pricing":{"type":"component"}, "configuration_schema":{"type":"object","additionalProperties":false,"properties":{}} diff --git a/crates/stackless-integrations/src/providers/composio/project.rs b/crates/stackless-integrations/src/providers/composio/project.rs index 2f4720c..3782578 100644 --- a/crates/stackless-integrations/src/providers/composio/project.rs +++ b/crates/stackless-integrations/src/providers/composio/project.rs @@ -97,7 +97,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_project","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_composio","provider_name":"Composio","service_id":"project","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"properties":{"name":{"type":"string"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_project","object":"v2.provisioning.provider_service_detail","provider":"prvdr_composio","provider_name":"Composio","service_id":"project","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"properties":{"name":{"type":"string"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/customerio/workspace.rs b/crates/stackless-integrations/src/providers/customerio/workspace.rs index 38c6b42..02310a5 100644 --- a/crates/stackless-integrations/src/providers/customerio/workspace.rs +++ b/crates/stackless-integrations/src/providers/customerio/workspace.rs @@ -88,7 +88,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_workspace","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_customerio","provider_name":"customerio","service_id":"workspace","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_workspace","object":"v2.provisioning.provider_service_detail","provider":"prvdr_customerio","provider_name":"customerio","service_id":"workspace","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/datadog/observability.rs b/crates/stackless-integrations/src/providers/datadog/observability.rs index f6c73eb..22530cc 100644 --- a/crates/stackless-integrations/src/providers/datadog/observability.rs +++ b/crates/stackless-integrations/src/providers/datadog/observability.rs @@ -80,7 +80,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_61V3GqrHb9AUATMHV5U6q","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_61V2Z15R0ek7uaOxE57Z2","provider_name":"Datadog","service_id":"observability","categories":["observability"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_61V3GqrHb9AUATMHV5U6q","object":"v2.provisioning.provider_service_detail","provider":"prvdr_61V2Z15R0ek7uaOxE57Z2","provider_name":"Datadog","service_id":"observability","categories":["observability"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/daytona/sandbox.rs b/crates/stackless-integrations/src/providers/daytona/sandbox.rs index e17252f..2d1be52 100644 --- a/crates/stackless-integrations/src/providers/daytona/sandbox.rs +++ b/crates/stackless-integrations/src/providers/daytona/sandbox.rs @@ -153,7 +153,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_sandbox","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_daytona","provider_name":"Daytona","service_id":"sandbox","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"additionalProperties":false,"properties":{"auto_archive_interval":{"minimum":0,"type":"integer"},"auto_delete_interval":{"description":"Negative values disable auto-delete.","type":"integer"},"auto_stop_interval":{"minimum":0,"type":"integer"},"cpu":{"minimum":1,"type":"integer"},"disk":{"description":"Disk in GiB.","minimum":1,"type":"integer"},"env":{"description":"Environment variables as comma-separated KEY=value pairs (e.g., FOO=bar,BAZ=qux).","type":"string"},"ephemeral":{"description":"If true, sandbox is deleted immediately upon stopping.","type":"boolean"},"image":{"description":"Docker image to use (e.g., debian:12.9). Mutually exclusive with snapshot.","type":"string"},"labels":{"description":"Labels as comma-separated KEY=value pairs (e.g., team=backend,env=dev).","type":"string"},"language":{"description":"Programming language for code execution.","enum":["python","typescript","javascript"],"type":"string"},"memory":{"description":"Memory in GiB.","minimum":1,"type":"integer"},"name":{"description":"Optional display name for the Daytona sandbox.","type":"string"},"network_allow_list":{"description":"Comma-separated CIDR allow list.","type":"string"},"network_block_all":{"description":"Block all egress from the sandbox.","type":"boolean"},"public":{"description":"Expose HTTP preview publicly.","type":"boolean"},"snapshot":{"description":"Optional Daytona snapshot ID or name to restore.","type":"string"},"target":{"description":"Daytona target region.","enum":["us","eu"],"type":"string"},"user":{"description":"User value sent to Daytona for the sandbox.","type":"string"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_sandbox","object":"v2.provisioning.provider_service_detail","provider":"prvdr_daytona","provider_name":"Daytona","service_id":"sandbox","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"additionalProperties":false,"properties":{"auto_archive_interval":{"minimum":0,"type":"integer"},"auto_delete_interval":{"description":"Negative values disable auto-delete.","type":"integer"},"auto_stop_interval":{"minimum":0,"type":"integer"},"cpu":{"minimum":1,"type":"integer"},"disk":{"description":"Disk in GiB.","minimum":1,"type":"integer"},"env":{"description":"Environment variables as comma-separated KEY=value pairs (e.g., FOO=bar,BAZ=qux).","type":"string"},"ephemeral":{"description":"If true, sandbox is deleted immediately upon stopping.","type":"boolean"},"image":{"description":"Docker image to use (e.g., debian:12.9). Mutually exclusive with snapshot.","type":"string"},"labels":{"description":"Labels as comma-separated KEY=value pairs (e.g., team=backend,env=dev).","type":"string"},"language":{"description":"Programming language for code execution.","enum":["python","typescript","javascript"],"type":"string"},"memory":{"description":"Memory in GiB.","minimum":1,"type":"integer"},"name":{"description":"Optional display name for the Daytona sandbox.","type":"string"},"network_allow_list":{"description":"Comma-separated CIDR allow list.","type":"string"},"network_block_all":{"description":"Block all egress from the sandbox.","type":"boolean"},"public":{"description":"Expose HTTP preview publicly.","type":"boolean"},"snapshot":{"description":"Optional Daytona snapshot ID or name to restore.","type":"string"},"target":{"description":"Daytona target region.","enum":["us","eu"],"type":"string"},"user":{"description":"User value sent to Daytona for the sandbox.","type":"string"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/depot/api.rs b/crates/stackless-integrations/src/providers/depot/api.rs index 24785f1..3de6a6b 100644 --- a/crates/stackless-integrations/src/providers/depot/api.rs +++ b/crates/stackless-integrations/src/providers/depot/api.rs @@ -77,7 +77,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_depot","provider_name":"Depot","service_id":"api","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"additionalProperties":false,"properties":{},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider":"prvdr_depot","provider_name":"Depot","service_id":"api","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"additionalProperties":false,"properties":{},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/e2b/sandbox.rs b/crates/stackless-integrations/src/providers/e2b/sandbox.rs index 1e3375b..a7ac059 100644 --- a/crates/stackless-integrations/src/providers/e2b/sandbox.rs +++ b/crates/stackless-integrations/src/providers/e2b/sandbox.rs @@ -77,7 +77,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_sandbox","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_e2b","provider_name":"E2B","service_id":"sandbox","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_sandbox","object":"v2.provisioning.provider_service_detail","provider":"prvdr_e2b","provider_name":"E2B","service_id":"sandbox","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/elevenlabs/tts.rs b/crates/stackless-integrations/src/providers/elevenlabs/tts.rs index 68a2f54..8e7402d 100644 --- a/crates/stackless-integrations/src/providers/elevenlabs/tts.rs +++ b/crates/stackless-integrations/src/providers/elevenlabs/tts.rs @@ -74,7 +74,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_tts","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_elevenlabs","provider_name":"ElevenLabs","service_id":"tts","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_tts","object":"v2.provisioning.provider_service_detail","provider":"prvdr_elevenlabs","provider_name":"ElevenLabs","service_id":"tts","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/exa/api.rs b/crates/stackless-integrations/src/providers/exa/api.rs index 89e3ec1..4a376e3 100644 --- a/crates/stackless-integrations/src/providers/exa/api.rs +++ b/crates/stackless-integrations/src/providers/exa/api.rs @@ -74,7 +74,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_exa","provider_name":"Exa","service_id":"api","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider":"prvdr_exa","provider_name":"Exa","service_id":"api","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/firecrawl/api.rs b/crates/stackless-integrations/src/providers/firecrawl/api.rs index da43187..477cb6e 100644 --- a/crates/stackless-integrations/src/providers/firecrawl/api.rs +++ b/crates/stackless-integrations/src/providers/firecrawl/api.rs @@ -77,7 +77,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_firecrawl","provider_name":"Firecrawl","service_id":"api","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"additionalProperties":false,"properties":{},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider":"prvdr_firecrawl","provider_name":"Firecrawl","service_id":"api","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"additionalProperties":false,"properties":{},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/flyio/mpg.rs b/crates/stackless-integrations/src/providers/flyio/mpg.rs index b9994d1..d19b259 100644 --- a/crates/stackless-integrations/src/providers/flyio/mpg.rs +++ b/crates/stackless-integrations/src/providers/flyio/mpg.rs @@ -105,7 +105,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_mpg","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_flyio","provider_name":"Flyio","service_id":"mpg","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"name":{"description":"Cluster name","maxLength":63,"minLength":5,"pattern":"^[a-z0-9][a-z0-9-]*[a-z0-9]$","type":"string"},"plan":{"enum":["basic","starter","launch","scale","Performance"],"type":"string"},"region":{"enum":["ams","dfw","fra","gru","iad","lax","lhr","nrt","ord","sin","sjc","syd","yyz"],"type":"string"}},"required":["name","region","plan"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_mpg","object":"v2.provisioning.provider_service_detail","provider":"prvdr_flyio","provider_name":"Flyio","service_id":"mpg","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"name":{"description":"Cluster name","maxLength":63,"minLength":5,"pattern":"^[a-z0-9][a-z0-9-]*[a-z0-9]$","type":"string"},"plan":{"enum":["basic","starter","launch","scale","Performance"],"type":"string"},"region":{"enum":["ams","dfw","fra","gru","iad","lax","lhr","nrt","ord","sin","sjc","syd","yyz"],"type":"string"}},"required":["name","region","plan"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/flyio/sprite.rs b/crates/stackless-integrations/src/providers/flyio/sprite.rs index 4831149..caea828 100644 --- a/crates/stackless-integrations/src/providers/flyio/sprite.rs +++ b/crates/stackless-integrations/src/providers/flyio/sprite.rs @@ -91,7 +91,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_sprite","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_flyio","provider_name":"Flyio","service_id":"sprite","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"name":{"description":"Sprite name","maxLength":63,"minLength":5,"pattern":"^[a-z0-9][a-z0-9-]*[a-z0-9]$","type":"string"}},"required":["name"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_sprite","object":"v2.provisioning.provider_service_detail","provider":"prvdr_flyio","provider_name":"Flyio","service_id":"sprite","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"name":{"description":"Sprite name","maxLength":63,"minLength":5,"pattern":"^[a-z0-9][a-z0-9-]*[a-z0-9]$","type":"string"}},"required":["name"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/gitlab/project.rs b/crates/stackless-integrations/src/providers/gitlab/project.rs index f6ad816..fb4f4e2 100644 --- a/crates/stackless-integrations/src/providers/gitlab/project.rs +++ b/crates/stackless-integrations/src/providers/gitlab/project.rs @@ -105,7 +105,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_project","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_gitlab","provider_name":"GitLab","service_id":"project","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"properties":{"name":{"description":"Name of the project","type":"string"},"visibility":{"description":"Visibility level of the project","enum":["private","public"],"type":"string"}},"required":["name","visibility"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_project","object":"v2.provisioning.provider_service_detail","provider":"prvdr_gitlab","provider_name":"GitLab","service_id":"project","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"properties":{"name":{"description":"Name of the project","type":"string"},"visibility":{"description":"Visibility level of the project","enum":["private","public"],"type":"string"}},"required":["name","visibility"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/herenow/hosting.rs b/crates/stackless-integrations/src/providers/herenow/hosting.rs index 07671d8..bb04ecc 100644 --- a/crates/stackless-integrations/src/providers/herenow/hosting.rs +++ b/crates/stackless-integrations/src/providers/herenow/hosting.rs @@ -76,7 +76,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_hosting","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_herenow","provider_name":"herenow","service_id":"hosting","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_hosting","object":"v2.provisioning.provider_service_detail","provider":"prvdr_herenow","provider_name":"herenow","service_id":"hosting","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/heygen/api.rs b/crates/stackless-integrations/src/providers/heygen/api.rs index 0b2a630..3f39038 100644 --- a/crates/stackless-integrations/src/providers/heygen/api.rs +++ b/crates/stackless-integrations/src/providers/heygen/api.rs @@ -93,7 +93,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_heygen","provider_name":"HeyGen","service_id":"api","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"auto_reload_amount":{"default":10,"description":"USD of API credit to add each time the balance runs low. Range $5-$1000, default $10.","maximum":1000,"minimum":5,"type":"integer"},"auto_reload_enabled":{"description":"Turn auto-reload on to top up API credit automatically when the balance runs low. Off by default; when off, amount/threshold are ignored.","type":"boolean"},"auto_reload_threshold":{"default":5,"description":"Auto-reload triggers when the remaining API credit balance falls below this USD amount. Range $5-$1000, default $5.","maximum":1000,"minimum":5,"type":"integer"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider":"prvdr_heygen","provider_name":"HeyGen","service_id":"api","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"auto_reload_amount":{"default":10,"description":"USD of API credit to add each time the balance runs low. Range $5-$1000, default $10.","maximum":1000,"minimum":5,"type":"integer"},"auto_reload_enabled":{"description":"Turn auto-reload on to top up API credit automatically when the balance runs low. Off by default; when off, amount/threshold are ignored.","type":"boolean"},"auto_reload_threshold":{"default":5,"description":"Auto-reload triggers when the remaining API credit balance falls below this USD amount. Range $5-$1000, default $5.","maximum":1000,"minimum":5,"type":"integer"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/inngest/app.rs b/crates/stackless-integrations/src/providers/inngest/app.rs index ea59ad9..52a205d 100644 --- a/crates/stackless-integrations/src/providers/inngest/app.rs +++ b/crates/stackless-integrations/src/providers/inngest/app.rs @@ -100,7 +100,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_app","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_inngest","provider_name":"Inngest","service_id":"app","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"id":{"description":"Inngest app ID. This should match the id passed to your Inngest SDK client, e.g. new Inngest({ id: \"my-app\" }).","minLength":1,"type":"string"}},"required":["id"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_app","object":"v2.provisioning.provider_service_detail","provider":"prvdr_inngest","provider_name":"Inngest","service_id":"app","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"id":{"description":"Inngest app ID. This should match the id passed to your Inngest SDK client, e.g. new Inngest({ id: \"my-app\" }).","minLength":1,"type":"string"}},"required":["id"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/kernel/project.rs b/crates/stackless-integrations/src/providers/kernel/project.rs index 849d1d4..7dd86d2 100644 --- a/crates/stackless-integrations/src/providers/kernel/project.rs +++ b/crates/stackless-integrations/src/providers/kernel/project.rs @@ -93,7 +93,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_project","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_kernel","provider_name":"KERNEL","service_id":"project","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"name":{"description":"A name for this API key","type":"string"}},"required":["name"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_project","object":"v2.provisioning.provider_service_detail","provider":"prvdr_kernel","provider_name":"KERNEL","service_id":"project","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"name":{"description":"A name for this API key","type":"string"}},"required":["name"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/laravel_cloud/application.rs b/crates/stackless-integrations/src/providers/laravel_cloud/application.rs index dd1675b..f572ee0 100644 --- a/crates/stackless-integrations/src/providers/laravel_cloud/application.rs +++ b/crates/stackless-integrations/src/providers/laravel_cloud/application.rs @@ -119,7 +119,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_application","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_laravel_cloud","provider_name":"Laravel_Cloud","service_id":"application","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"create_cache":{"default":"no","description":"Provision a managed Valkey cache and connect it to this application.","enum":["yes","no"],"title":"Create a cache","type":"string"},"create_database":{"default":"no","description":"Provision a managed MySQL database and connect it to this application.","enum":["yes","no"],"title":"Create a database","type":"string"},"name":{"description":"A name for your Laravel application.","title":"Application Name","type":"string"},"region":{"enum":["us-east-1","us-east-2","eu-central-1","eu-west-1","eu-west-2","ap-southeast-1","ap-southeast-2","ap-northeast-1","ca-central-1","me-central-1"],"type":"string"},"repository":{"description":"Full repository name (e.g. laravel/cloud).","title":"Repository","type":"string"}},"required":["name","repository","region"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_application","object":"v2.provisioning.provider_service_detail","provider":"prvdr_laravel_cloud","provider_name":"Laravel_Cloud","service_id":"application","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"create_cache":{"default":"no","description":"Provision a managed Valkey cache and connect it to this application.","enum":["yes","no"],"title":"Create a cache","type":"string"},"create_database":{"default":"no","description":"Provision a managed MySQL database and connect it to this application.","enum":["yes","no"],"title":"Create a database","type":"string"},"name":{"description":"A name for your Laravel application.","title":"Application Name","type":"string"},"region":{"enum":["us-east-1","us-east-2","eu-central-1","eu-west-1","eu-west-2","ap-southeast-1","ap-southeast-2","ap-northeast-1","ca-central-1","me-central-1"],"type":"string"},"repository":{"description":"Full repository name (e.g. laravel/cloud).","title":"Repository","type":"string"}},"required":["name","repository","region"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/laravel_cloud/mysql.rs b/crates/stackless-integrations/src/providers/laravel_cloud/mysql.rs index 27d5e57..3da0470 100644 --- a/crates/stackless-integrations/src/providers/laravel_cloud/mysql.rs +++ b/crates/stackless-integrations/src/providers/laravel_cloud/mysql.rs @@ -104,7 +104,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_mysql","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_laravel_cloud","provider_name":"Laravel_Cloud","service_id":"mysql","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"instance_size":{"enum":["mysql-flex-512mb","mysql-flex-1gb","mysql-flex-2gb","mysql-pro-4gb","mysql-pro-8gb","mysql-pro-16gb","mysql-pro-32gb"],"type":"string"},"region":{"enum":["us-east-1","us-east-2","eu-central-1","eu-west-1","eu-west-2","ap-southeast-1","ap-southeast-2","ap-northeast-1","ca-central-1","me-central-1"],"type":"string"}},"required":["instance_size","region"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_mysql","object":"v2.provisioning.provider_service_detail","provider":"prvdr_laravel_cloud","provider_name":"Laravel_Cloud","service_id":"mysql","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"instance_size":{"enum":["mysql-flex-512mb","mysql-flex-1gb","mysql-flex-2gb","mysql-pro-4gb","mysql-pro-8gb","mysql-pro-16gb","mysql-pro-32gb"],"type":"string"},"region":{"enum":["us-east-1","us-east-2","eu-central-1","eu-west-1","eu-west-2","ap-southeast-1","ap-southeast-2","ap-northeast-1","ca-central-1","me-central-1"],"type":"string"}},"required":["instance_size","region"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/laravel_cloud/valkey.rs b/crates/stackless-integrations/src/providers/laravel_cloud/valkey.rs index f5956ad..8dca1a4 100644 --- a/crates/stackless-integrations/src/providers/laravel_cloud/valkey.rs +++ b/crates/stackless-integrations/src/providers/laravel_cloud/valkey.rs @@ -102,7 +102,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_valkey","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_laravel_cloud","provider_name":"Laravel_Cloud","service_id":"valkey","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"instance_size":{"enum":["valkey-flex-250mb","valkey-flex-1gb","valkey-flex-2.5gb","valkey-pro.5gb","valkey-pro.12gb","valkey-pro.25gb","valkey-pro.50gb"],"type":"string"},"region":{"enum":["us-east-1","us-east-2","eu-central-1","eu-west-1","eu-west-2","ap-southeast-1","ap-southeast-2","ap-northeast-1","ca-central-1","me-central-1"],"type":"string"}},"required":["instance_size","region"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_valkey","object":"v2.provisioning.provider_service_detail","provider":"prvdr_laravel_cloud","provider_name":"Laravel_Cloud","service_id":"valkey","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"instance_size":{"enum":["valkey-flex-250mb","valkey-flex-1gb","valkey-flex-2.5gb","valkey-pro.5gb","valkey-pro.12gb","valkey-pro.25gb","valkey-pro.50gb"],"type":"string"},"region":{"enum":["us-east-1","us-east-2","eu-central-1","eu-west-1","eu-west-2","ap-southeast-1","ap-southeast-2","ap-northeast-1","ca-central-1","me-central-1"],"type":"string"}},"required":["instance_size","region"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/metronome/sandbox.rs b/crates/stackless-integrations/src/providers/metronome/sandbox.rs index e1c5d58..cbe4ce4 100644 --- a/crates/stackless-integrations/src/providers/metronome/sandbox.rs +++ b/crates/stackless-integrations/src/providers/metronome/sandbox.rs @@ -77,7 +77,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_sandbox","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_metronome","provider_name":"Metronome","service_id":"sandbox","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_sandbox","object":"v2.provisioning.provider_service_detail","provider":"prvdr_metronome","provider_name":"Metronome","service_id":"sandbox","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/mixpanel/analytics.rs b/crates/stackless-integrations/src/providers/mixpanel/analytics.rs index 4747c0a..f766b1e 100644 --- a/crates/stackless-integrations/src/providers/mixpanel/analytics.rs +++ b/crates/stackless-integrations/src/providers/mixpanel/analytics.rs @@ -90,7 +90,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_analytics","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_mixpanel","provider_name":"Mixpanel","service_id":"analytics","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_analytics","object":"v2.provisioning.provider_service_detail","provider":"prvdr_mixpanel","provider_name":"Mixpanel","service_id":"analytics","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/mod.rs b/crates/stackless-integrations/src/providers/mod.rs index 1d3b936..1977e23 100644 --- a/crates/stackless-integrations/src/providers/mod.rs +++ b/crates/stackless-integrations/src/providers/mod.rs @@ -1,11 +1,13 @@ pub mod agentmail; pub mod agentphone; pub mod amplitude; +pub mod athena; pub mod auth0; pub mod base44_projects; pub mod blaxel; pub mod browserbase; pub mod chatbase; +pub mod churnkey; pub mod clerk; pub mod clickhouse; pub mod cloudflare; @@ -34,8 +36,10 @@ pub mod postalform; pub mod posthog; pub mod prisma; pub mod pydantic; +pub mod quo; pub mod railway; pub mod render_db; +pub mod resend; pub mod revenuecat; pub mod runloop; pub mod schematic; @@ -57,12 +61,13 @@ mod tests { use stackless_provider_sdk::Hostable; use crate::providers::{ - agentmail, agentphone, amplitude, auth0, base44_projects, blaxel, browserbase, chatbase, - clickhouse, cloudflare, composio, customerio, datadog, depot, e2b, elevenlabs, exa, - firecrawl, flyio, gitlab, herenow, inngest, kernel, laravel_cloud, metronome, mixpanel, - neon, openrouter, parallel, perplexity, planetscale, postalform, posthog, prisma, pydantic, - railway, render_db, revenuecat, runloop, schematic, sentry, shopify, steel, supabase, - supermemory, tabstack, turso, upstash, wix, wordpress_com, workos, + agentmail, agentphone, amplitude, athena, auth0, base44_projects, blaxel, browserbase, + chatbase, churnkey, clickhouse, cloudflare, composio, customerio, datadog, depot, e2b, + elevenlabs, exa, firecrawl, flyio, gitlab, herenow, inngest, kernel, laravel_cloud, + metronome, mixpanel, neon, openrouter, parallel, perplexity, planetscale, postalform, + posthog, prisma, pydantic, quo, railway, render_db, resend, revenuecat, runloop, schematic, + sentry, shopify, steel, supabase, supermemory, tabstack, turso, upstash, wix, + wordpress_com, workos, }; fn assert_outputs_match() { @@ -89,11 +94,13 @@ mod tests { assert_outputs_match::(); assert_outputs_match::(); assert_outputs_match::(); + assert_outputs_match::(); assert_outputs_match::(); assert_outputs_match::(); assert_outputs_match::(); assert_outputs_match::(); assert_outputs_match::(); + assert_outputs_match::(); assert_outputs_match::(); assert_outputs_match::(); assert_outputs_match::(); @@ -125,12 +132,14 @@ mod tests { assert_outputs_match::(); assert_outputs_match::(); assert_outputs_match::(); + assert_outputs_match::(); assert_outputs_match::(); assert_outputs_match::(); assert_outputs_match::(); assert_outputs_match::(); assert_outputs_match::(); assert_outputs_match::(); + assert_outputs_match::(); assert_outputs_match::(); assert_outputs_match::(); assert_outputs_match::(); diff --git a/crates/stackless-integrations/src/providers/neon/postgres.rs b/crates/stackless-integrations/src/providers/neon/postgres.rs index 5a21a79..9031f23 100644 --- a/crates/stackless-integrations/src/providers/neon/postgres.rs +++ b/crates/stackless-integrations/src/providers/neon/postgres.rs @@ -87,7 +87,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_postgres","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_neon","provider_name":"Neon","service_id":"postgres","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_postgres","object":"v2.provisioning.provider_service_detail","provider":"prvdr_neon","provider_name":"Neon","service_id":"postgres","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/openrouter/api.rs b/crates/stackless-integrations/src/providers/openrouter/api.rs index ccddabc..acfbae1 100644 --- a/crates/stackless-integrations/src/providers/openrouter/api.rs +++ b/crates/stackless-integrations/src/providers/openrouter/api.rs @@ -74,7 +74,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_openrouter","provider_name":"OpenRouter","service_id":"api","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider":"prvdr_openrouter","provider_name":"OpenRouter","service_id":"api","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/parallel/api.rs b/crates/stackless-integrations/src/providers/parallel/api.rs index 30990ea..47b8e26 100644 --- a/crates/stackless-integrations/src/providers/parallel/api.rs +++ b/crates/stackless-integrations/src/providers/parallel/api.rs @@ -99,7 +99,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_parallel","provider_name":"Parallel","service_id":"api","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid","paid_pricing":[{"type":"freeform","is_default":true,"configuration":{"product":"search"}}]},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider":"prvdr_parallel","provider_name":"Parallel","service_id":"api","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid","paid_pricing":[{"type":"freeform","is_default":true,"configuration":{"product":"search"}}]},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/perplexity/api.rs b/crates/stackless-integrations/src/providers/perplexity/api.rs index 25b3045..87d5d81 100644 --- a/crates/stackless-integrations/src/providers/perplexity/api.rs +++ b/crates/stackless-integrations/src/providers/perplexity/api.rs @@ -97,7 +97,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_perplexity","provider_name":"Perplexity","service_id":"api","categories":["search","ai"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"auto_recharge":{"description":"Automatically buy more API credits when the balance runs low; applies to the whole account. When true, recharge_amount_usd must also be sent.","type":"boolean"},"buy_credits_usd":{"description":"One-time credit purchase in USD charged to the shared payment token. Valid on updates only, and never persisted as configuration state: each update carrying it is one purchase.","minimum":10,"type":"integer"},"initial_credit_usd":{"description":"One-time credit purchase in USD charged to the shared payment token when the resource is provisioned. Valid at provisioning only; to buy more credits later, send buy_credits_usd on an update.","minimum":10,"type":"integer"},"recharge_amount_usd":{"description":"Credit amount in USD purchased by each automatic recharge; only valid alongside auto_recharge.","minimum":10,"type":"integer"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider":"prvdr_perplexity","provider_name":"Perplexity","service_id":"api","categories":["search","ai"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"auto_recharge":{"description":"Automatically buy more API credits when the balance runs low; applies to the whole account. When true, recharge_amount_usd must also be sent.","type":"boolean"},"buy_credits_usd":{"description":"One-time credit purchase in USD charged to the shared payment token. Valid on updates only, and never persisted as configuration state: each update carrying it is one purchase.","minimum":10,"type":"integer"},"initial_credit_usd":{"description":"One-time credit purchase in USD charged to the shared payment token when the resource is provisioned. Valid at provisioning only; to buy more credits later, send buy_credits_usd on an update.","minimum":10,"type":"integer"},"recharge_amount_usd":{"description":"Credit amount in USD purchased by each automatic recharge; only valid alongside auto_recharge.","minimum":10,"type":"integer"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/planetscale/mysql.rs b/crates/stackless-integrations/src/providers/planetscale/mysql.rs index 058e8a9..542c77b 100644 --- a/crates/stackless-integrations/src/providers/planetscale/mysql.rs +++ b/crates/stackless-integrations/src/providers/planetscale/mysql.rs @@ -109,7 +109,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_mysql","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_planetscale","provider_name":"PlanetScale","service_id":"mysql","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"cluster":{"description":"Cluster size","enum":["PS-10","PS-20","PS-40","PS-80","PS-160","PS-320"],"type":"string"},"name":{"description":"Database name.","maxLength":63,"minLength":2,"pattern":"^[a-z0-9][a-z0-9_-]*[a-z0-9]$","type":"string"},"region":{"description":"Deployment region (prefixed with cloud provider, e.g., aws-us-east, gcp-us-central1)","enum":["aws-ap-northeast","aws-ap-south","aws-ap-southeast","aws-ap-southeast-2","aws-ca-central-1","aws-eu-central","aws-eu-west","aws-eu-west-2","aws-sa-east-1","aws-us-east","aws-us-east-2","aws-us-west","gcp-asia-northeast3","gcp-europe-west1","gcp-europe-west4","gcp-northamerica-northeast1","gcp-us-central1","gcp-us-east1","gcp-us-east4"],"type":"string"}},"required":["name","cluster","region"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_mysql","object":"v2.provisioning.provider_service_detail","provider":"prvdr_planetscale","provider_name":"PlanetScale","service_id":"mysql","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"cluster":{"description":"Cluster size","enum":["PS-10","PS-20","PS-40","PS-80","PS-160","PS-320"],"type":"string"},"name":{"description":"Database name.","maxLength":63,"minLength":2,"pattern":"^[a-z0-9][a-z0-9_-]*[a-z0-9]$","type":"string"},"region":{"description":"Deployment region (prefixed with cloud provider, e.g., aws-us-east, gcp-us-central1)","enum":["aws-ap-northeast","aws-ap-south","aws-ap-southeast","aws-ap-southeast-2","aws-ca-central-1","aws-eu-central","aws-eu-west","aws-eu-west-2","aws-sa-east-1","aws-us-east","aws-us-east-2","aws-us-west","gcp-asia-northeast3","gcp-europe-west1","gcp-europe-west4","gcp-northamerica-northeast1","gcp-us-central1","gcp-us-east1","gcp-us-east4"],"type":"string"}},"required":["name","cluster","region"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/planetscale/postgresql.rs b/crates/stackless-integrations/src/providers/planetscale/postgresql.rs index 732f553..3222687 100644 --- a/crates/stackless-integrations/src/providers/planetscale/postgresql.rs +++ b/crates/stackless-integrations/src/providers/planetscale/postgresql.rs @@ -113,7 +113,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_postgresql","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_planetscale","provider_name":"PlanetScale","service_id":"postgresql","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"cluster":{"description":"Cluster size","enum":["PS-5","PS-10","PS-20","PS-40","PS-80","PS-160","PS-320"],"type":"string"},"name":{"description":"Database name.","maxLength":63,"minLength":2,"pattern":"^[a-z0-9][a-z0-9_-]*[a-z0-9]$","type":"string"},"region":{"description":"Deployment region (prefixed with cloud provider, e.g., aws-us-east, gcp-us-central1)","enum":["aws-ap-northeast","aws-ap-south","aws-ap-southeast","aws-ap-southeast-2","aws-ca-central-1","aws-eu-central","aws-eu-west","aws-eu-west-2","aws-sa-east-1","aws-us-east","aws-us-east-2","aws-us-west","gcp-asia-northeast3","gcp-europe-west1","gcp-europe-west4","gcp-northamerica-northeast1","gcp-us-central1","gcp-us-east1","gcp-us-east4"],"type":"string"},"replicas":{"default":0,"description":"Number of replicas (0 for single node, 2+ for high availability)","maximum":9,"minimum":0,"type":"integer"}},"required":["name","cluster","region"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_postgresql","object":"v2.provisioning.provider_service_detail","provider":"prvdr_planetscale","provider_name":"PlanetScale","service_id":"postgresql","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"cluster":{"description":"Cluster size","enum":["PS-5","PS-10","PS-20","PS-40","PS-80","PS-160","PS-320"],"type":"string"},"name":{"description":"Database name.","maxLength":63,"minLength":2,"pattern":"^[a-z0-9][a-z0-9_-]*[a-z0-9]$","type":"string"},"region":{"description":"Deployment region (prefixed with cloud provider, e.g., aws-us-east, gcp-us-central1)","enum":["aws-ap-northeast","aws-ap-south","aws-ap-southeast","aws-ap-southeast-2","aws-ca-central-1","aws-eu-central","aws-eu-west","aws-eu-west-2","aws-sa-east-1","aws-us-east","aws-us-east-2","aws-us-west","gcp-asia-northeast3","gcp-europe-west1","gcp-europe-west4","gcp-northamerica-northeast1","gcp-us-central1","gcp-us-east1","gcp-us-east4"],"type":"string"},"replicas":{"default":0,"description":"Number of replicas (0 for single node, 2+ for high availability)","maximum":9,"minimum":0,"type":"integer"}},"required":["name","cluster","region"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/postalform/mail.rs b/crates/stackless-integrations/src/providers/postalform/mail.rs index e5cc88c..b006fbd 100644 --- a/crates/stackless-integrations/src/providers/postalform/mail.rs +++ b/crates/stackless-integrations/src/providers/postalform/mail.rs @@ -109,7 +109,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_mail","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_postalform","provider_name":"PostalForm","service_id":"mail","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"additionalProperties":true,"properties":{"webhook_url":{"description":"Optional HTTPS endpoint that receives signed PostalForm status webhooks. If supplied, PostalForm creates or reuses a webhook endpoint and returns its signing secret in the access configuration.","pattern":"^https://","type":"string"},"workspace_name":{"description":"Optional display name for the PostalForm Projects workspace.","type":"string"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_mail","object":"v2.provisioning.provider_service_detail","provider":"prvdr_postalform","provider_name":"PostalForm","service_id":"mail","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"additionalProperties":true,"properties":{"webhook_url":{"description":"Optional HTTPS endpoint that receives signed PostalForm status webhooks. If supplied, PostalForm creates or reuses a webhook endpoint and returns its signing secret in the access configuration.","pattern":"^https://","type":"string"},"workspace_name":{"description":"Optional display name for the PostalForm Projects workspace.","type":"string"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/posthog/analytics.rs b/crates/stackless-integrations/src/providers/posthog/analytics.rs index 75cbbbc..4531f31 100644 --- a/crates/stackless-integrations/src/providers/posthog/analytics.rs +++ b/crates/stackless-integrations/src/providers/posthog/analytics.rs @@ -80,7 +80,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_analytics","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_posthog","provider_name":"PostHog","service_id":"analytics","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_analytics","object":"v2.provisioning.provider_service_detail","provider":"prvdr_posthog","provider_name":"PostHog","service_id":"analytics","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/prisma/database.rs b/crates/stackless-integrations/src/providers/prisma/database.rs index c617edb..6ac0f83 100644 --- a/crates/stackless-integrations/src/providers/prisma/database.rs +++ b/crates/stackless-integrations/src/providers/prisma/database.rs @@ -97,7 +97,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_database","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_prisma","provider_name":"Prisma","service_id":"database","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"additionalProperties":false,"properties":{"region":{"default":"us-east-1","description":"Prisma Postgres region identifier (Defaults to \"us-east-1\").","enum":["us-east-1","us-west-1","eu-west-3","eu-central-1","ap-northeast-1","ap-southeast-1"],"type":"string"}},"required":["region"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_database","object":"v2.provisioning.provider_service_detail","provider":"prvdr_prisma","provider_name":"Prisma","service_id":"database","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"additionalProperties":false,"properties":{"region":{"default":"us-east-1","description":"Prisma Postgres region identifier (Defaults to \"us-east-1\").","enum":["us-east-1","us-west-1","eu-west-3","eu-central-1","ap-northeast-1","ap-southeast-1"],"type":"string"}},"required":["region"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/privy/app.rs b/crates/stackless-integrations/src/providers/privy/app.rs index dfcc2d9..2dce1b2 100644 --- a/crates/stackless-integrations/src/providers/privy/app.rs +++ b/crates/stackless-integrations/src/providers/privy/app.rs @@ -91,7 +91,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_app","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_privy","provider_name":"Privy","service_id":"app","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"app_name":{"description":"Display name for the app","type":"string"}},"required":["app_name"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_app","object":"v2.provisioning.provider_service_detail","provider":"prvdr_privy","provider_name":"Privy","service_id":"app","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"app_name":{"description":"Display name for the app","type":"string"}},"required":["app_name"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/pydantic/logfire.rs b/crates/stackless-integrations/src/providers/pydantic/logfire.rs index 6ae7e2b..188d515 100644 --- a/crates/stackless-integrations/src/providers/pydantic/logfire.rs +++ b/crates/stackless-integrations/src/providers/pydantic/logfire.rs @@ -105,7 +105,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_logfire","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_pydantic","provider_name":"Pydantic","service_id":"logfire","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"organization":{"type":"string"},"project_name":{"type":"string"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_logfire","object":"v2.provisioning.provider_service_detail","provider":"prvdr_pydantic","provider_name":"Pydantic","service_id":"logfire","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"organization":{"type":"string"},"project_name":{"type":"string"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/quo/app.rs b/crates/stackless-integrations/src/providers/quo/app.rs new file mode 100644 index 0000000..8edcab3 --- /dev/null +++ b/crates/stackless-integrations/src/providers/quo/app.rs @@ -0,0 +1,128 @@ +use std::collections::BTreeMap; + +use serde::Serialize; +use stackless_stripe_projects::catalog::verify::CatalogService; +use stackless_stripe_projects::provision::ProvisionContext; + +use super::FamilyResource; +use crate::error::IntegrationError; +use crate::hostable::{ConfigScope, Hostable, IntegrationHosting}; + +pub const RESOURCE_KIND: &str = "integration-quo-app"; + +#[derive(Debug, Serialize)] +pub struct QuoAppConfig {} + +impl CatalogService for QuoAppConfig { + const REFERENCE: &'static str = "quo/app"; +} + +#[derive(Debug)] +pub struct QuoApp; + +impl Hostable for QuoApp { + const PROVIDER: &'static str = "quo-app"; + const HOSTING: IntegrationHosting = IntegrationHosting::Managed; + const CONFIG_SCOPE: ConfigScope = ConfigScope::GlobalOnly; + const RESOURCE_KIND: &'static str = RESOURCE_KIND; + const OUTPUTS: &'static [&'static str] = &["api_key"]; +} + +impl FamilyResource for QuoApp { + type Config = QuoAppConfig; + const PROVIDER_PREFIX: &'static str = "QUO"; + // Provisional until pinned by `mise run discover quo/app`. + const OUTPUT_FIELDS: &'static [(&'static str, &'static str, bool)] = + &[("API_KEY", "api_key", true)]; + + fn build_config(ctx: &ProvisionContext<'_>) -> Result { + super::integration_config(ctx)?; + Ok(QuoAppConfig {}) + } +} + +pub fn validate_config( + _name: &str, + _config: &BTreeMap, +) -> Result<(), IntegrationError> { + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::ProviderOps; + use crate::resource::ResourcePayload; + use stackless_core::def::StackDef; + use stackless_stripe_projects::stripe::StripeProjects; + use stackless_stripe_projects::test_support; + + #[test] + fn config_matches_catalog() { + const FIXTURE: &str = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../stackless-stripe-projects/tests/fixtures/catalog.json" + )); + let catalog = stackless_stripe_projects::Catalog::from_json_envelope(FIXTURE).unwrap(); + let failures = stackless_stripe_projects::verify_service(&catalog, &QuoAppConfig {}); + assert!( + failures.is_empty(), + "quo/app catalog gaps:\n{}", + failures.join("\n") + ); + } + + const CATALOG_ENVELOPE: &str = r#"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"allowed_updates":[],"availability":"available","categories":["communications"],"configuration_schema":{},"constraints":[{"count":{"at_most":1},"type":"count"}],"created":null,"description":"Business phone numbers, calling, and messaging. Paid Starter plan with a 7-day free trial.","development":false,"group":"workspace","id":"prvsvc_61VP2qveAWh4hu16A5KvA","kind":"deployable","livemode":true,"llm_context":null,"object":"v2.provisioning.provider_service_detail","pricing":{"component":{"options":[{"is_default":null,"paid":null,"parent_services":["starter"],"type":"free"}]},"paid":null,"paid_pricing":[],"type":"component"},"provider":"prvdr_61VKP6RyKXtCSxNAo55ns","provider_configuration_schema":{},"provider_name":"Quo","scope":"project","service_id":"app","updateable_to":["app"]},{"allowed_updates":[],"availability":"available","categories":["communications"],"configuration_schema":{},"constraints":[{"count":{"at_most":1},"type":"count"}],"created":null,"description":"Starter plan for a Quo workspace","development":false,"group":"plan","id":"prvsvc_61VP2qu8TNanWtQrR5QzY","kind":"plan","livemode":true,"llm_context":null,"object":"v2.provisioning.provider_service_detail","pricing":{"component":null,"paid":{"description":null,"freeform":"$19 per seat / month, 7-day free trial","type":"freeform"},"paid_pricing":[{"configuration":null,"description":null,"freeform":"$19 per seat / month, 7-day free trial","is_default":true,"type":"freeform"}],"type":"paid"},"provider":"prvdr_61VKP6RyKXtCSxNAo55ns","provider_configuration_schema":{},"provider_name":"Quo","scope":"account","service_id":"starter","updateable_to":["starter"]}]}}"#; + + fn test_def() -> StackDef { + StackDef::parse( + r#" +[stack] +name = "atto" +[stack.projects.stripe] +project = "project_1" +[integrations.phone] +provider = "quo-app" +[services.api] +source = { repo = "r", ref = "main" } +env = { OUT = "${integrations.phone.api_key}" } +health = { path = "/health" } +[services.api.local] +run = "true" +"#, + ) + .unwrap() + } + + #[tokio::test] + async fn provision_records_outputs() { + let runner = test_support::provision_script( + CATALOG_ENVELOPE, + serde_json::json!({"QUO_API_KEY": "val_api_key"}), + 1, + ); + let dir = tempfile::tempdir().unwrap(); + std::fs::write( + dir.path().join("stackless.toml"), + "[stack]\nname=\"atto\"\n", + ) + .unwrap(); + let stripe = StripeProjects::new(&runner, dir.path()); + + let resource = QuoApp + .provision( + &stripe.as_dyn(), + &test_def(), + dir.path(), + "demo", + "phone", + "local", + false, + ) + .await + .unwrap(); + assert_eq!(resource.resource_kind, "integration-quo-app"); + let payload: ResourcePayload = serde_json::from_str(&resource.payload).unwrap(); + assert_eq!(payload.outputs["api_key"], "val_api_key"); + } +} diff --git a/crates/stackless-integrations/src/providers/quo/mod.rs b/crates/stackless-integrations/src/providers/quo/mod.rs new file mode 100644 index 0000000..4d5d9d6 --- /dev/null +++ b/crates/stackless-integrations/src/providers/quo/mod.rs @@ -0,0 +1,3 @@ +pub mod app; + +pub(crate) use crate::resource::{CatalogResource as FamilyResource, integration_config}; diff --git a/crates/stackless-integrations/src/providers/railway/bucket.rs b/crates/stackless-integrations/src/providers/railway/bucket.rs index 5e02cca..6288556 100644 --- a/crates/stackless-integrations/src/providers/railway/bucket.rs +++ b/crates/stackless-integrations/src/providers/railway/bucket.rs @@ -101,7 +101,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_bucket","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_railway","provider_name":"Railway","service_id":"bucket","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"name":{"description":"Bucket name (auto-generated if omitted).","type":"string"},"region":{"description":"Storage region (e.g. sjc, iad, ams, sin).","type":"string"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_bucket","object":"v2.provisioning.provider_service_detail","provider":"prvdr_railway","provider_name":"Railway","service_id":"bucket","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"name":{"description":"Bucket name (auto-generated if omitted).","type":"string"},"region":{"description":"Storage region (e.g. sjc, iad, ams, sin).","type":"string"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/railway/hosting.rs b/crates/stackless-integrations/src/providers/railway/hosting.rs index 11a1538..bf6085f 100644 --- a/crates/stackless-integrations/src/providers/railway/hosting.rs +++ b/crates/stackless-integrations/src/providers/railway/hosting.rs @@ -85,7 +85,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_hosting","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_railway","provider_name":"Railway","service_id":"hosting","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_hosting","object":"v2.provisioning.provider_service_detail","provider":"prvdr_railway","provider_name":"Railway","service_id":"hosting","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/railway/mongo.rs b/crates/stackless-integrations/src/providers/railway/mongo.rs index 6db054c..889608c 100644 --- a/crates/stackless-integrations/src/providers/railway/mongo.rs +++ b/crates/stackless-integrations/src/providers/railway/mongo.rs @@ -82,7 +82,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_mongo","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_railway","provider_name":"Railway","service_id":"mongo","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"region":{"description":"Deployment region (e.g. us-west1, us-east4)","type":"string"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_mongo","object":"v2.provisioning.provider_service_detail","provider":"prvdr_railway","provider_name":"Railway","service_id":"mongo","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"region":{"description":"Deployment region (e.g. us-west1, us-east4)","type":"string"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/railway/postgres.rs b/crates/stackless-integrations/src/providers/railway/postgres.rs index 0c7917b..894291f 100644 --- a/crates/stackless-integrations/src/providers/railway/postgres.rs +++ b/crates/stackless-integrations/src/providers/railway/postgres.rs @@ -82,7 +82,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_postgres","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_railway","provider_name":"Railway","service_id":"postgres","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"region":{"description":"Deployment region (e.g. us-west1, us-east4)","type":"string"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_postgres","object":"v2.provisioning.provider_service_detail","provider":"prvdr_railway","provider_name":"Railway","service_id":"postgres","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"region":{"description":"Deployment region (e.g. us-west1, us-east4)","type":"string"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/railway/redis.rs b/crates/stackless-integrations/src/providers/railway/redis.rs index 5acdcaf..e5d5cae 100644 --- a/crates/stackless-integrations/src/providers/railway/redis.rs +++ b/crates/stackless-integrations/src/providers/railway/redis.rs @@ -82,7 +82,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_redis","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_railway","provider_name":"Railway","service_id":"redis","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"region":{"description":"Deployment region (e.g. us-west1, us-east4)","type":"string"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_redis","object":"v2.provisioning.provider_service_detail","provider":"prvdr_railway","provider_name":"Railway","service_id":"redis","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"region":{"description":"Deployment region (e.g. us-west1, us-east4)","type":"string"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/render_db/postgres.rs b/crates/stackless-integrations/src/providers/render_db/postgres.rs index 6a0a3f0..de5fdb4 100644 --- a/crates/stackless-integrations/src/providers/render_db/postgres.rs +++ b/crates/stackless-integrations/src/providers/render_db/postgres.rs @@ -103,7 +103,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_postgres","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_render_db","provider_name":"Render","service_id":"postgres","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"disk_size":{"description":"Storage capacity for the database instance, in GB. Defaults to 15 GB. Must be in multiples of 5 GB.","type":"integer"},"name":{"description":"Name of the PostgreSQL database instance","type":"string"},"owner_id":{"description":"Workspace ID to deploy into. If omitted, uses the default workspace.","type":"string"},"region":{"description":"Region to deploy the database in (e.g. oregon, frankfurt, ohio, singapore, virginia). Defaults to 'oregon'.","type":"string"},"version":{"description":"PostgreSQL major version (e.g. 16, 17, 18). Defaults to the latest supported version.","type":"string"}},"required":["name"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_postgres","object":"v2.provisioning.provider_service_detail","provider":"prvdr_render_db","provider_name":"Render","service_id":"postgres","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"disk_size":{"description":"Storage capacity for the database instance, in GB. Defaults to 15 GB. Must be in multiples of 5 GB.","type":"integer"},"name":{"description":"Name of the PostgreSQL database instance","type":"string"},"owner_id":{"description":"Workspace ID to deploy into. If omitted, uses the default workspace.","type":"string"},"region":{"description":"Region to deploy the database in (e.g. oregon, frankfurt, ohio, singapore, virginia). Defaults to 'oregon'.","type":"string"},"version":{"description":"PostgreSQL major version (e.g. 16, 17, 18). Defaults to the latest supported version.","type":"string"}},"required":["name"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/resend/email.rs b/crates/stackless-integrations/src/providers/resend/email.rs new file mode 100644 index 0000000..35aaaea --- /dev/null +++ b/crates/stackless-integrations/src/providers/resend/email.rs @@ -0,0 +1,129 @@ +use std::collections::BTreeMap; + +use serde::Serialize; +use stackless_stripe_projects::catalog::verify::CatalogService; +use stackless_stripe_projects::provision::ProvisionContext; + +use super::FamilyResource; +use crate::error::IntegrationError; +use crate::hostable::{ConfigScope, Hostable, IntegrationHosting}; + +pub const RESOURCE_KIND: &str = "integration-resend"; + +#[derive(Debug, Serialize)] +pub struct ResendEmailConfig {} + +impl CatalogService for ResendEmailConfig { + const REFERENCE: &'static str = "resend/email"; +} + +#[derive(Debug)] +pub struct ResendEmail; + +impl Hostable for ResendEmail { + const PROVIDER: &'static str = "resend"; + const HOSTING: IntegrationHosting = IntegrationHosting::Managed; + const CONFIG_SCOPE: ConfigScope = ConfigScope::GlobalOnly; + const RESOURCE_KIND: &'static str = RESOURCE_KIND; + const OUTPUTS: &'static [&'static str] = &["api_key"]; +} + +impl FamilyResource for ResendEmail { + type Config = ResendEmailConfig; + const PROVIDER_PREFIX: &'static str = "RESEND"; + // Provisional until pinned by `mise run discover resend/email`. + const OUTPUT_FIELDS: &'static [(&'static str, &'static str, bool)] = + &[("API_KEY", "api_key", true)]; + + fn build_config(ctx: &ProvisionContext<'_>) -> Result { + let _ = super::integration_config(ctx)?; + Ok(ResendEmailConfig {}) + } +} + +pub fn validate_config( + name: &str, + config: &BTreeMap, +) -> Result<(), IntegrationError> { + let _ = (name, config); + Ok(()) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::ProviderOps; + use crate::resource::ResourcePayload; + use stackless_core::def::StackDef; + use stackless_stripe_projects::stripe::StripeProjects; + use stackless_stripe_projects::test_support; + + #[test] + fn config_matches_catalog() { + const FIXTURE: &str = include_str!(concat!( + env!("CARGO_MANIFEST_DIR"), + "/../stackless-stripe-projects/tests/fixtures/catalog.json" + )); + let catalog = stackless_stripe_projects::Catalog::from_json_envelope(FIXTURE).unwrap(); + let failures = stackless_stripe_projects::verify_service(&catalog, &ResendEmailConfig {}); + assert!( + failures.is_empty(), + "resend/email catalog gaps:\n{}", + failures.join("\n") + ); + } + + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"allowed_updates":[],"availability":"available","categories":["email"],"configuration_schema":{},"constraints":[{"count":{"at_most":1},"type":"count"}],"created":null,"description":"Email for developers. One API key per project, one shared sending quota.","development":false,"group":"resend","id":"prvsvc_61VFx44H4RKHoEjct5QIi","kind":"deployable","livemode":true,"llm_context":"https://raw.githubusercontent.com/resend/resend-skills/main/skills/resend/SKILL.md","object":"v2.provisioning.provider_service_detail","pricing":{"component":{"options":[{"is_default":null,"paid":null,"parent_services":["pro","free"],"type":"free"}]},"paid":null,"paid_pricing":[],"type":"component"},"provider":"prvdr_61VFXTzsszWb1r1S25KMa","provider_configuration_schema":{},"provider_name":"Resend","scope":"project","service_id":"email","updateable_to":["email"]}]}}"##; + + fn test_def() -> StackDef { + StackDef::parse( + r#" +[stack] +name = "atto" +[stack.projects.stripe] +project = "project_1" +[integrations.res] +provider = "resend" +[services.api] +source = { repo = "r", ref = "main" } +env = { OUT = "${integrations.res.api_key}" } +health = { path = "/health" } +[services.api.local] +run = "true" +"#, + ) + .unwrap() + } + + #[tokio::test] + async fn provision_records_outputs() { + let runner = test_support::provision_script( + CATALOG_ENVELOPE, + serde_json::json!({"RESEND_API_KEY": "val_api_key"}), + 0, + ); + let dir = tempfile::tempdir().unwrap(); + std::fs::write( + dir.path().join("stackless.toml"), + "[stack]\nname=\"atto\"\n", + ) + .unwrap(); + let stripe = StripeProjects::new(&runner, dir.path()); + + let resource = ResendEmail + .provision( + &stripe.as_dyn(), + &test_def(), + dir.path(), + "demo", + "res", + "local", + false, + ) + .await + .unwrap(); + assert_eq!(resource.resource_kind, "integration-resend"); + let payload: ResourcePayload = serde_json::from_str(&resource.payload).unwrap(); + assert_eq!(payload.outputs["api_key"], "val_api_key"); + } +} diff --git a/crates/stackless-integrations/src/providers/resend/mod.rs b/crates/stackless-integrations/src/providers/resend/mod.rs new file mode 100644 index 0000000..d8c1b7e --- /dev/null +++ b/crates/stackless-integrations/src/providers/resend/mod.rs @@ -0,0 +1,3 @@ +pub mod email; + +pub(crate) use crate::resource::{CatalogResource as FamilyResource, integration_config}; diff --git a/crates/stackless-integrations/src/providers/revenuecat/app.rs b/crates/stackless-integrations/src/providers/revenuecat/app.rs index 86ac812..7ea7899 100644 --- a/crates/stackless-integrations/src/providers/revenuecat/app.rs +++ b/crates/stackless-integrations/src/providers/revenuecat/app.rs @@ -77,7 +77,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_app","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_revenuecat","provider_name":"RevenueCat","service_id":"app","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_app","object":"v2.provisioning.provider_service_detail","provider":"prvdr_revenuecat","provider_name":"RevenueCat","service_id":"app","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"},"configuration_schema":{}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/runloop/sandbox.rs b/crates/stackless-integrations/src/providers/runloop/sandbox.rs index 8746765..facf3a2 100644 --- a/crates/stackless-integrations/src/providers/runloop/sandbox.rs +++ b/crates/stackless-integrations/src/providers/runloop/sandbox.rs @@ -78,7 +78,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_sandbox","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_runloop","provider_name":"Runloop","service_id":"sandbox","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_sandbox","object":"v2.provisioning.provider_service_detail","provider":"prvdr_runloop","provider_name":"Runloop","service_id":"sandbox","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/schematic/schematic_environment.rs b/crates/stackless-integrations/src/providers/schematic/schematic_environment.rs index 921d77c..31d0cd1 100644 --- a/crates/stackless-integrations/src/providers/schematic/schematic_environment.rs +++ b/crates/stackless-integrations/src/providers/schematic/schematic_environment.rs @@ -99,7 +99,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_schematic_environment","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_schematic","provider_name":"Schematic","service_id":"schematic-environment","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"environment_type":{"type":"string","enum":["development","production"]},"name":{"type":"string"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_schematic_environment","object":"v2.provisioning.provider_service_detail","provider":"prvdr_schematic","provider_name":"Schematic","service_id":"schematic-environment","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"environment_type":{"type":"string","enum":["development","production"]},"name":{"type":"string"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/sentry/project.rs b/crates/stackless-integrations/src/providers/sentry/project.rs index a4acda6..62df4f2 100644 --- a/crates/stackless-integrations/src/providers/sentry/project.rs +++ b/crates/stackless-integrations/src/providers/sentry/project.rs @@ -93,7 +93,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_project","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_sentry","provider_name":"Sentry","service_id":"project","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"platform":{"description":"Platform/language (e.g. python, javascript, node, react)","type":"string"},"project_name":{"description":"Name for the Sentry project","type":"string"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_project","object":"v2.provisioning.provider_service_detail","provider":"prvdr_sentry","provider_name":"Sentry","service_id":"project","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"platform":{"description":"Platform/language (e.g. python, javascript, node, react)","type":"string"},"project_name":{"description":"Name for the Sentry project","type":"string"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/sentry/seer.rs b/crates/stackless-integrations/src/providers/sentry/seer.rs index d7c06e5..468e3af 100644 --- a/crates/stackless-integrations/src/providers/sentry/seer.rs +++ b/crates/stackless-integrations/src/providers/sentry/seer.rs @@ -77,7 +77,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_seer","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_sentry","provider_name":"Sentry","service_id":"seer","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_seer","object":"v2.provisioning.provider_service_detail","provider":"prvdr_sentry","provider_name":"Sentry","service_id":"seer","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"type":"object","required":[],"additionalProperties":false,"properties":{}}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/shopify/store.rs b/crates/stackless-integrations/src/providers/shopify/store.rs index 21859d7..edcb7ab 100644 --- a/crates/stackless-integrations/src/providers/shopify/store.rs +++ b/crates/stackless-integrations/src/providers/shopify/store.rs @@ -92,7 +92,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_store","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_shopify","provider_name":"Shopify","service_id":"store","categories":["ecommerce"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"additionalProperties":false,"properties":{"plan":{"enum":["trial","basic","grow","advanced"],"type":"string"},"store_name":{"maxLength":50,"minLength":1,"type":"string"}},"optional":["store_name","plan"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_store","object":"v2.provisioning.provider_service_detail","provider":"prvdr_shopify","provider_name":"Shopify","service_id":"store","categories":["ecommerce"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"additionalProperties":false,"properties":{"plan":{"enum":["trial","basic","grow","advanced"],"type":"string"},"store_name":{"maxLength":50,"minLength":1,"type":"string"}},"optional":["store_name","plan"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/steel/browser.rs b/crates/stackless-integrations/src/providers/steel/browser.rs index 233fdab..fe2c929 100644 --- a/crates/stackless-integrations/src/providers/steel/browser.rs +++ b/crates/stackless-integrations/src/providers/steel/browser.rs @@ -84,7 +84,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_browser","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_steel","provider_name":"Steel","service_id":"browser","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"name":{"type":"string"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_browser","object":"v2.provisioning.provider_service_detail","provider":"prvdr_steel","provider_name":"Steel","service_id":"browser","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"name":{"type":"string"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/supabase/project.rs b/crates/stackless-integrations/src/providers/supabase/project.rs index 45dc764..7b40377 100644 --- a/crates/stackless-integrations/src/providers/supabase/project.rs +++ b/crates/stackless-integrations/src/providers/supabase/project.rs @@ -101,7 +101,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_project","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_supabase","provider_name":"Supabase","service_id":"project","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"name":{"maxLength":60,"minLength":1,"type":"string"},"region":{"default":"americas","enum":["americas","emea","apac"],"type":"string"}},"required":[],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_project","object":"v2.provisioning.provider_service_detail","provider":"prvdr_supabase","provider_name":"Supabase","service_id":"project","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"name":{"maxLength":60,"minLength":1,"type":"string"},"region":{"default":"americas","enum":["americas","emea","apac"],"type":"string"}},"required":[],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/supermemory/memory.rs b/crates/stackless-integrations/src/providers/supermemory/memory.rs index 760fc79..854065d 100644 --- a/crates/stackless-integrations/src/providers/supermemory/memory.rs +++ b/crates/stackless-integrations/src/providers/supermemory/memory.rs @@ -92,7 +92,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_memory","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_supermemory","provider_name":"Supermemory","service_id":"memory","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"plan":{"description":"Subscription tier","enum":["free","pro","max","scale"],"type":"string"}},"required":["plan"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_memory","object":"v2.provisioning.provider_service_detail","provider":"prvdr_supermemory","provider_name":"Supermemory","service_id":"memory","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"plan":{"description":"Subscription tier","enum":["free","pro","max","scale"],"type":"string"}},"required":["plan"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/tabstack/api.rs b/crates/stackless-integrations/src/providers/tabstack/api.rs index cbda8a4..e808d10 100644 --- a/crates/stackless-integrations/src/providers/tabstack/api.rs +++ b/crates/stackless-integrations/src/providers/tabstack/api.rs @@ -80,7 +80,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_tabstack","provider_name":"Tabstack","service_id":"api","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"plan":{"type":"string","enum":["trial","individual","team","pro"],"description":"The plan tier to provision."}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_api","object":"v2.provisioning.provider_service_detail","provider":"prvdr_tabstack","provider_name":"Tabstack","service_id":"api","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"plan":{"type":"string","enum":["trial","individual","team","pro"],"description":"The plan tier to provision."}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/turso/database.rs b/crates/stackless-integrations/src/providers/turso/database.rs index a35a8ab..fb2caf7 100644 --- a/crates/stackless-integrations/src/providers/turso/database.rs +++ b/crates/stackless-integrations/src/providers/turso/database.rs @@ -97,7 +97,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_database","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_turso","provider_name":"Turso","service_id":"database","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"location":{"description":"Primary location (e.g. aws-us-east-1, aws-eu-west-1)","enum":["aws-us-east-1","aws-us-east-2","aws-us-west-2","aws-eu-west-1","aws-ap-south-1","aws-ap-northeast-1"],"type":"string"},"name":{"description":"Database name","type":"string"}},"required":["name","location"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_database","object":"v2.provisioning.provider_service_detail","provider":"prvdr_turso","provider_name":"Turso","service_id":"database","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{"properties":{"location":{"description":"Primary location (e.g. aws-us-east-1, aws-eu-west-1)","enum":["aws-us-east-1","aws-us-east-2","aws-us-west-2","aws-eu-west-1","aws-ap-south-1","aws-ap-northeast-1"],"type":"string"},"name":{"description":"Database name","type":"string"}},"required":["name","location"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/twilio/email.rs b/crates/stackless-integrations/src/providers/twilio/email.rs index 45cb4f8..2c056e3 100644 --- a/crates/stackless-integrations/src/providers/twilio/email.rs +++ b/crates/stackless-integrations/src/providers/twilio/email.rs @@ -75,7 +75,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_61UQvwE7qadLu0Kgo5BZg","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_61UQsPLOiNuyFxFP45ADo","provider_name":"Twilio","service_id":"email","categories":["email"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_61UQvwE7qadLu0Kgo5BZg","object":"v2.provisioning.provider_service_detail","provider":"prvdr_61UQsPLOiNuyFxFP45ADo","provider_name":"Twilio","service_id":"email","categories":["email"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"component"},"configuration_schema":{}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/upstash/qstash.rs b/crates/stackless-integrations/src/providers/upstash/qstash.rs index 8f483df..8b08711 100644 --- a/crates/stackless-integrations/src/providers/upstash/qstash.rs +++ b/crates/stackless-integrations/src/providers/upstash/qstash.rs @@ -88,7 +88,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_qstash","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_upstash","provider_name":"Upstash","service_id":"qstash","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"price":{"default":"payg","description":"Pricing tier. 'free' provisions on the free plan (subject to free-tier limits and one-per-account). 'payg' provisions pay-as-you-go. Defaults to 'payg'.","enum":["free","payg"],"type":"string"},"region":{"description":"Region for the QStash user","enum":["eu-central-1","us-east-1"],"type":"string"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_qstash","object":"v2.provisioning.provider_service_detail","provider":"prvdr_upstash","provider_name":"Upstash","service_id":"qstash","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"price":{"default":"payg","description":"Pricing tier. 'free' provisions on the free plan (subject to free-tier limits and one-per-account). 'payg' provisions pay-as-you-go. Defaults to 'payg'.","enum":["free","payg"],"type":"string"},"region":{"description":"Region for the QStash user","enum":["eu-central-1","us-east-1"],"type":"string"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/upstash/redis.rs b/crates/stackless-integrations/src/providers/upstash/redis.rs index eed89f0..126dd5c 100644 --- a/crates/stackless-integrations/src/providers/upstash/redis.rs +++ b/crates/stackless-integrations/src/providers/upstash/redis.rs @@ -117,7 +117,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_redis","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_upstash","provider_name":"Upstash","service_id":"redis","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"eviction":{"description":"Enable eviction when data size limit is reached (on or off)","enum":["on","off"],"type":"string"},"name":{"description":"Database name","maxLength":40,"minLength":1,"type":"string"},"price":{"default":"payg","description":"Pricing tier. 'free' provisions on the free plan (subject to free-tier limits and one-per-account). 'payg' provisions pay-as-you-go. Defaults to 'payg'.","enum":["free","payg"],"type":"string"},"prod_pack":{"description":"Enable Production Pack ($200/mo) for enhanced SLA, higher limits, and multi-zone replication. Requires price=payg.","enum":["on","off"],"type":"string"},"read_regions":{"description":"Comma-separated list of read replica regions for global databases (e.g. \"eu-west-1,ap-southeast-1\"). Leave empty for single-region. Allowed values: us-east-1, us-west-1, us-west-2, us-east-2, eu-west-1, eu-west-2, eu-central-1, ap-southeast-1, ap-southeast-2, ap-northeast-1, ap-south-1, af-south-1, sa-east-1, ca-central-1, us-central1, europe-west1, asia-northeast1, us-east4","type":"string"},"region":{"description":"AWS/GCP region for the database","enum":["us-east-1","us-west-1","us-west-2","us-east-2","eu-west-1","eu-west-2","eu-central-1","ap-southeast-1","ap-southeast-2","ap-northeast-1","ap-south-1","af-south-1","sa-east-1","ca-central-1","us-central1","europe-west1","asia-northeast1","us-east4"],"type":"string"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_redis","object":"v2.provisioning.provider_service_detail","provider":"prvdr_upstash","provider_name":"Upstash","service_id":"redis","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"eviction":{"description":"Enable eviction when data size limit is reached (on or off)","enum":["on","off"],"type":"string"},"name":{"description":"Database name","maxLength":40,"minLength":1,"type":"string"},"price":{"default":"payg","description":"Pricing tier. 'free' provisions on the free plan (subject to free-tier limits and one-per-account). 'payg' provisions pay-as-you-go. Defaults to 'payg'.","enum":["free","payg"],"type":"string"},"prod_pack":{"description":"Enable Production Pack ($200/mo) for enhanced SLA, higher limits, and multi-zone replication. Requires price=payg.","enum":["on","off"],"type":"string"},"read_regions":{"description":"Comma-separated list of read replica regions for global databases (e.g. \"eu-west-1,ap-southeast-1\"). Leave empty for single-region. Allowed values: us-east-1, us-west-1, us-west-2, us-east-2, eu-west-1, eu-west-2, eu-central-1, ap-southeast-1, ap-southeast-2, ap-northeast-1, ap-south-1, af-south-1, sa-east-1, ca-central-1, us-central1, europe-west1, asia-northeast1, us-east4","type":"string"},"region":{"description":"AWS/GCP region for the database","enum":["us-east-1","us-west-1","us-west-2","us-east-2","eu-west-1","eu-west-2","eu-central-1","ap-southeast-1","ap-southeast-2","ap-northeast-1","ap-south-1","af-south-1","sa-east-1","ca-central-1","us-central1","europe-west1","asia-northeast1","us-east4"],"type":"string"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/upstash/search.rs b/crates/stackless-integrations/src/providers/upstash/search.rs index 12e19bf..9687796 100644 --- a/crates/stackless-integrations/src/providers/upstash/search.rs +++ b/crates/stackless-integrations/src/providers/upstash/search.rs @@ -92,7 +92,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_search","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_upstash","provider_name":"Upstash","service_id":"search","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"name":{"description":"Search index name","minLength":1,"type":"string"},"price":{"default":"payg","description":"Pricing tier. 'free' provisions on the free plan (subject to free-tier limits and one-per-account). 'payg' provisions pay-as-you-go. Defaults to 'payg'.","enum":["free","payg"],"type":"string"},"region":{"description":"Region for the search index","enum":["eu-west-1","us-central1"],"type":"string"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_search","object":"v2.provisioning.provider_service_detail","provider":"prvdr_upstash","provider_name":"Upstash","service_id":"search","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"name":{"description":"Search index name","minLength":1,"type":"string"},"price":{"default":"payg","description":"Pricing tier. 'free' provisions on the free plan (subject to free-tier limits and one-per-account). 'payg' provisions pay-as-you-go. Defaults to 'payg'.","enum":["free","payg"],"type":"string"},"region":{"description":"Region for the search index","enum":["eu-west-1","us-central1"],"type":"string"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/upstash/vector.rs b/crates/stackless-integrations/src/providers/upstash/vector.rs index 0d86ecf..ad0365c 100644 --- a/crates/stackless-integrations/src/providers/upstash/vector.rs +++ b/crates/stackless-integrations/src/providers/upstash/vector.rs @@ -104,7 +104,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_vector","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_upstash","provider_name":"Upstash","service_id":"vector","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"dimension":{"description":"Vector dimension count. Ignored when embedding_model is set (dimension is derived from the model)","maximum":3072,"minimum":1,"type":"integer"},"embedding_model":{"description":"Embedding model. Use empty string to bring your own vectors (dimension required).","enum":["BGE_SMALL_EN_V1_5","BGE_BASE_EN_V1_5","BGE_LARGE_EN_V1_5","BGE_M3"],"type":"string"},"name":{"description":"Index name","minLength":1,"type":"string"},"price":{"default":"payg","description":"Pricing tier. 'free' provisions on the free plan (subject to free-tier limits and one-per-account). 'payg' provisions pay-as-you-go. Defaults to 'payg'.","enum":["free","payg"],"type":"string"},"region":{"description":"Region for the vector index","enum":["us-east-1","eu-west-1","us-central1"],"type":"string"},"similarity_function":{"description":"Distance metric for similarity search","enum":["COSINE","EUCLIDEAN","DOT_PRODUCT"],"type":"string"}},"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_vector","object":"v2.provisioning.provider_service_detail","provider":"prvdr_upstash","provider_name":"Upstash","service_id":"vector","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"dimension":{"description":"Vector dimension count. Ignored when embedding_model is set (dimension is derived from the model)","maximum":3072,"minimum":1,"type":"integer"},"embedding_model":{"description":"Embedding model. Use empty string to bring your own vectors (dimension required).","enum":["BGE_SMALL_EN_V1_5","BGE_BASE_EN_V1_5","BGE_LARGE_EN_V1_5","BGE_M3"],"type":"string"},"name":{"description":"Index name","minLength":1,"type":"string"},"price":{"default":"payg","description":"Pricing tier. 'free' provisions on the free plan (subject to free-tier limits and one-per-account). 'payg' provisions pay-as-you-go. Defaults to 'payg'.","enum":["free","payg"],"type":"string"},"region":{"description":"Region for the vector index","enum":["us-east-1","eu-west-1","us-central1"],"type":"string"},"similarity_function":{"description":"Distance metric for similarity search","enum":["COSINE","EUCLIDEAN","DOT_PRODUCT"],"type":"string"}},"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/wix/headless.rs b/crates/stackless-integrations/src/providers/wix/headless.rs index 8e22dc9..3369e86 100644 --- a/crates/stackless-integrations/src/providers/wix/headless.rs +++ b/crates/stackless-integrations/src/providers/wix/headless.rs @@ -92,7 +92,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_headless","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_wix","provider_name":"Wix","service_id":"headless","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"additionalProperties":false,"properties":{"plan":{"description":"Pre-filled from the tier selected above; override only if you need to.","enum":["free","premium"],"title":"Plan","type":"string"},"wix_project_name":{"description":"Human-readable name for the Wix site that backs this project. Shown in the Wix dashboard.","maxLength":50,"minLength":1,"title":"Wix project name","type":"string"}},"required":[],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_headless","object":"v2.provisioning.provider_service_detail","provider":"prvdr_wix","provider_name":"Wix","service_id":"headless","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"additionalProperties":false,"properties":{"plan":{"description":"Pre-filled from the tier selected above; override only if you need to.","enum":["free","premium"],"title":"Plan","type":"string"},"wix_project_name":{"description":"Human-readable name for the Wix site that backs this project. Shown in the Wix dashboard.","maxLength":50,"minLength":1,"title":"Wix project name","type":"string"}},"required":[],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/wordpress_com/site.rs b/crates/stackless-integrations/src/providers/wordpress_com/site.rs index 9492b08..1d70e7c 100644 --- a/crates/stackless-integrations/src/providers/wordpress_com/site.rs +++ b/crates/stackless-integrations/src/providers/wordpress_com/site.rs @@ -100,7 +100,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_site","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_wordpress_com","provider_name":"WordPress.com","service_id":"site","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"plan":{"description":"Which WordPress.com plan to provision. See the pricing options for what each plan includes.","enum":["free","personal","premium","business","commerce"],"type":"string"}},"required":["plan"],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_site","object":"v2.provisioning.provider_service_detail","provider":"prvdr_wordpress_com","provider_name":"WordPress.com","service_id":"site","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"plan":{"description":"Which WordPress.com plan to provision. See the pricing options for what each plan includes.","enum":["free","personal","premium","business","commerce"],"type":"string"}},"required":["plan"],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/providers/workos/auth.rs b/crates/stackless-integrations/src/providers/workos/auth.rs index d386ad6..b487d97 100644 --- a/crates/stackless-integrations/src/providers/workos/auth.rs +++ b/crates/stackless-integrations/src/providers/workos/auth.rs @@ -87,7 +87,7 @@ mod tests { ); } - const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_auth","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_workos","provider_name":"WorkOS","service_id":"auth","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"environment":{"default":"sandbox","description":"Environment type. Sandbox environments are free for development and testing.","enum":["sandbox","production"],"type":"string"}},"required":[],"type":"object"}}]}}"##; + const CATALOG_ENVELOPE: &str = r##"{"ok":true,"command":"projects catalog","data":{"last_updated":"2026-07-11T00:00:00Z","services":[{"id":"prvsvc_auth","object":"v2.provisioning.provider_service_detail","provider":"prvdr_workos","provider_name":"WorkOS","service_id":"auth","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"paid"},"configuration_schema":{"properties":{"environment":{"default":"sandbox","description":"Environment type. Sandbox environments are free for development and testing.","enum":["sandbox","production"],"type":"string"}},"required":[],"type":"object"}}]}}"##; fn test_def() -> StackDef { StackDef::parse( diff --git a/crates/stackless-integrations/src/registry.rs b/crates/stackless-integrations/src/registry.rs index 90f7ce4..ea6a00a 100644 --- a/crates/stackless-integrations/src/registry.rs +++ b/crates/stackless-integrations/src/registry.rs @@ -79,11 +79,13 @@ register_providers! { (agentmail::api, AgentMailApi), (agentphone::number, AgentPhoneNumber), (amplitude::analytics, AmplitudeAnalytics), + (athena::agents, AthenaAgents), (auth0::client, Auth0Client), (base44_projects::app, Base44ProjectsApp), (blaxel::sandbox, BlaxelSandbox), (browserbase::project, BrowserbaseProject), (chatbase::agent, ChatbaseAgent), + (churnkey::retention, ChurnkeyRetention), (clickhouse::cluster, ClickHouseClickhouse), (clickhouse::postgres, ClickHousePostgres), (composio::project, ComposioProject), @@ -115,12 +117,14 @@ register_providers! { (posthog::analytics, PostHogAnalytics), (prisma::database, PrismaDatabase), (pydantic::logfire, PydanticLogfire), + (quo::app, QuoApp), (railway::bucket, RailwayBucket), (railway::hosting, RailwayHosting), (railway::mongo, RailwayMongo), (railway::postgres, RailwayPostgres), (railway::redis, RailwayRedis), (render_db::postgres, RenderPostgres), + (resend::email, ResendEmail), (revenuecat::app, RevenuecatApp), (runloop::sandbox, RunloopSandbox), (schematic::schematic_environment, SchematicEnvironment), diff --git a/crates/stackless-stripe-projects/src/catalog.rs b/crates/stackless-stripe-projects/src/catalog.rs index bdb2e01..530aa7e 100644 --- a/crates/stackless-stripe-projects/src/catalog.rs +++ b/crates/stackless-stripe-projects/src/catalog.rs @@ -72,7 +72,7 @@ impl Catalog { pub struct ServiceDetail { pub id: String, pub object: String, - pub provider_id: String, + pub provider: String, pub provider_name: String, pub service_id: String, #[serde(default)] diff --git a/crates/stackless-stripe-projects/src/catalog/tests.rs b/crates/stackless-stripe-projects/src/catalog/tests.rs index 46df8ac..db6d0fa 100644 --- a/crates/stackless-stripe-projects/src/catalog/tests.rs +++ b/crates/stackless-stripe-projects/src/catalog/tests.rs @@ -6,7 +6,7 @@ fn service(reference: &str, schema: Value, pricing: Value) -> ServiceDetail { serde_json::from_value(json!({ "id": "prvsvc_test", "object": "v2.provisioning.provider_service_detail", - "provider_id": "prvdr_test", + "provider": "prvdr_test", "provider_name": provider, "service_id": service_id, "categories": [], diff --git a/crates/stackless-stripe-projects/src/catalog/verify.rs b/crates/stackless-stripe-projects/src/catalog/verify.rs index 78b7840..0003603 100644 --- a/crates/stackless-stripe-projects/src/catalog/verify.rs +++ b/crates/stackless-stripe-projects/src/catalog/verify.rs @@ -170,7 +170,7 @@ mod tests { { "id": "prvsvc_app", "object": "v2.provisioning.provider_service_detail", - "provider_id": "prvdr_example", + "provider": "prvdr_example", "provider_name": "Example", "service_id": "app", "categories": ["communications"], @@ -198,7 +198,7 @@ mod tests { { "id": "prvsvc_starter", "object": "v2.provisioning.provider_service_detail", - "provider_id": "prvdr_example", + "provider": "prvdr_example", "provider_name": "Example", "service_id": "starter", "categories": ["communications"], diff --git a/crates/stackless-stripe-projects/src/journal.rs b/crates/stackless-stripe-projects/src/journal.rs index 9c31d37..9003123 100644 --- a/crates/stackless-stripe-projects/src/journal.rs +++ b/crates/stackless-stripe-projects/src/journal.rs @@ -462,7 +462,7 @@ async fn recover_remote( .ok_or_else(|| ProjectsError::CreationUnknown { resource: name.into(), })?; - if remote.provider != service.provider_id || remote.service_ref != service.service_id { + if remote.provider != service.provider || remote.service_ref != service.service_id { return Err(crate::remote::invalid( "remote resource name has a different catalog identity", )); @@ -640,7 +640,7 @@ mod tests { .unwrap(); let mut service = catalog["data"]["services"][0].clone(); service["provider_name"] = json!("Example"); - service["provider_id"] = json!("provider_1"); + service["provider"] = json!("provider_1"); service["service_id"] = json!("database"); catalog["data"]["services"] = json!([service]); Ok(ok(catalog["data"].clone())) diff --git a/crates/stackless-stripe-projects/src/stripe.rs b/crates/stackless-stripe-projects/src/stripe.rs index 62ca064..0ece664 100644 --- a/crates/stackless-stripe-projects/src/stripe.rs +++ b/crates/stackless-stripe-projects/src/stripe.rs @@ -790,7 +790,7 @@ mod tests { "services": [{ "id": "clerk_auth", "object": "service", - "provider_id": "clerk", + "provider": "clerk", "provider_name": "Clerk", "service_id": "auth", "kind": "saas", @@ -842,7 +842,7 @@ mod tests { #[tokio::test] async fn catalog_envelope_falls_back_to_category_filters() { - let service = r#"{"id":"prvsvc_1","object":"v2.provisioning.provider_service_detail","provider_id":"prvdr_1","provider_name":"Neon","service_id":"postgres","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"}}"#; + let service = r#"{"id":"prvsvc_1","object":"v2.provisioning.provider_service_detail","provider":"prvdr_1","provider_name":"Neon","service_id":"postgres","categories":["database"],"kind":"deployable","scope":"project","availability":"available","development":false,"livemode":true,"pricing":{"type":"free"}}"#; let filtered = format!( r#"{{"ok":true,"command":"projects catalog","version":"0.1","data":{{"last_updated":"t","provider":null,"category_filter":"database","provider_filter":null,"services":[{service}],"source":null}}}}"# ); diff --git a/crates/stackless-stripe-projects/src/surface.rs b/crates/stackless-stripe-projects/src/surface.rs index ddf7f74..365e78f 100644 --- a/crates/stackless-stripe-projects/src/surface.rs +++ b/crates/stackless-stripe-projects/src/surface.rs @@ -8,15 +8,8 @@ use crate::error::ProjectsError; use crate::stripe::{CommandRunner, StripeProjects}; -/// Every `stripe projects` invocation we snapshot, as the argv *after* `projects`. -/// The order is fixed in code, not discovered from the plugin, so the snapshot -/// never self-reorders — a newly shipped command surfaces as a diff in the -/// top-level `--help` block and is then added here in the same change. Groups -/// (`services`/`env`/`billing`) are listed immediately before their children. -/// Verified against plugin 0.39.1. const TRAVERSAL: &[&[&str]] = &[ &[], - // GET STARTED &["init"], &["build"], &["list"], @@ -27,7 +20,6 @@ const TRAVERSAL: &[&[&str]] = &[ &["catalog"], &["search"], &["switch-account"], - // MANAGE SERVICES &["add"], &["update"], &["upgrade"], @@ -37,7 +29,6 @@ const TRAVERSAL: &[&[&str]] = &[ &["link"], &["unlink"], &["open"], - // ENVIRONMENT &["env"], &["env", "list"], &["env", "show"], @@ -52,13 +43,11 @@ const TRAVERSAL: &[&[&str]] = &[ &["variables", "list"], &["variables", "delete"], &["llm-context"], - // BILLING &["billing"], &["billing", "show"], &["billing", "add"], &["billing", "update"], &["spend"], - // FEEDBACK &["feedback"], ]; @@ -186,8 +175,6 @@ mod tests { use async_trait::async_trait; use std::path::Path; - /// Returns canned help text echoing the argv it was called with, so we can - /// assert the assembly logic without scripting one output per command. struct EchoRunner; #[async_trait] @@ -195,7 +182,6 @@ mod tests { async fn run(&self, args: &[String], _cwd: &Path) -> Result { Ok(CommandOutput { status: 0, - // Pad with blank lines + trailing spaces to exercise normalization. stdout: format!("\n\nhelp for: {} \n\n", args.join(" ")), stderr: String::new(), }) @@ -257,11 +243,9 @@ GET STARTED\n init [name] Initialize a new project\n"; let body = command_surface(&driver()).await.unwrap(); let seps: Vec<&str> = body.lines().filter(|l| l.starts_with("===== ")).collect(); assert_eq!(seps, command_separators()); - // Top-level uses the bare label and the echo carries the normalized args. assert!(body.starts_with("===== stripe projects --help =====\n")); assert!(body.contains("help for: --help --color off")); assert!(body.contains("help for: env list --help --color off")); - // Trimmed: no trailing blank line. assert!(!body.ends_with('\n')); } } diff --git a/crates/stackless-stripe-projects/tests/fixtures/catalog.json b/crates/stackless-stripe-projects/tests/fixtures/catalog.json index e4a1b04..bd4957b 100644 --- a/crates/stackless-stripe-projects/tests/fixtures/catalog.json +++ b/crates/stackless-stripe-projects/tests/fixtures/catalog.json @@ -6,6 +6,426 @@ "provider": null, "provider_filter": null, "services": [ + { + "allowed_updates": [], + "availability": "available", + "categories": [ + "ecommerce" + ], + "configuration_schema": {}, + "constraints": [], + "created": null, + "description": "Subscribe to a Squarespace website — hosting, professional templates, unlimited pages, SEO tools, and integrated commerce. Pick a plan and billing term when you provision. See https://www.squarespace.com/pricing", + "development": false, + "group": null, + "id": "prvsvc_61VUQiD3p5cKuX93B53eC", + "kind": "deployable", + "livemode": true, + "llm_context": "https://production.squarespace.thisdotstripeapps.com/stripe/provisioning/llm/website", + "object": "v2.provisioning.provider_service_detail", + "pricing": { + "component": null, + "paid": { + "description": "Templates, unlimited pages, SEO, and a standard online store", + "freeform": "USD 220.80 / year", + "type": "freeform" + }, + "paid_pricing": [ + { + "configuration": { + "plan": "CORE", + "term": "ANNUAL" + }, + "description": "Templates, unlimited pages, SEO, and a standard online store", + "freeform": "USD 220.80 / year", + "is_default": true, + "type": "freeform" + }, + { + "configuration": { + "plan": "CORE", + "term": "MONTHLY" + }, + "description": "Templates, unlimited pages, SEO, and a standard online store", + "freeform": "USD 28.80 / month", + "is_default": false, + "type": "freeform" + }, + { + "configuration": { + "plan": "PLUS", + "term": "ANNUAL" + }, + "description": "Adds commerce — subscriptions, advanced discounts, and video", + "freeform": "USD 374.40 / year", + "is_default": false, + "type": "freeform" + }, + { + "configuration": { + "plan": "PLUS", + "term": "MONTHLY" + }, + "description": "Adds commerce — subscriptions, advanced discounts, and video", + "freeform": "USD 44.80 / month", + "is_default": false, + "type": "freeform" + }, + { + "configuration": { + "plan": "ADVANCED", + "term": "ANNUAL" + }, + "description": "Adds point of sale, top AI credits, and premium integrations", + "freeform": "USD 950.40 / year", + "is_default": false, + "type": "freeform" + }, + { + "configuration": { + "plan": "ADVANCED", + "term": "MONTHLY" + }, + "description": "Adds point of sale, top AI credits, and premium integrations", + "freeform": "USD 111.20 / month", + "is_default": false, + "type": "freeform" + } + ], + "type": "paid" + }, + "provider": "prvdr_61UacoeBnJSHilBZJ5FIm", + "provider_configuration_schema": {}, + "provider_name": "Squarespace", + "scope": "project", + "service_id": "website", + "updateable_to": [ + "website" + ] + }, + { + "allowed_updates": [], + "availability": "available", + "categories": [ + "queue" + ], + "configuration_schema": {}, + "constraints": [], + "created": null, + "description": "Growth — Inngest billing plan.", + "development": false, + "group": null, + "id": "prvsvc_61VS1nQ1jlctikf5l5Mhs", + "kind": "plan", + "livemode": true, + "llm_context": null, + "object": "v2.provisioning.provider_service_detail", + "pricing": { + "component": null, + "paid": { + "description": null, + "freeform": "$499.00 per month", + "type": "freeform" + }, + "paid_pricing": [ + { + "configuration": null, + "description": null, + "freeform": "$499.00 per month", + "is_default": null, + "type": "freeform" + } + ], + "type": "paid" + }, + "provider": "prvdr_61UQ7Ta2evjv111Sl5Tqa", + "provider_configuration_schema": {}, + "provider_name": "Inngest", + "scope": "project", + "service_id": "growth-2026-09-22", + "updateable_to": [ + "growth-2026-09-22" + ] + }, + { + "allowed_updates": [], + "availability": "available", + "categories": [ + "payments" + ], + "configuration_schema": { + "properties": { + "company_name": { + "description": "Your company name as shown to customers in the cancel flow", + "type": "string" + } + }, + "type": "object" + }, + "constraints": [], + "created": null, + "description": "Cancel flows, failed payment recovery, and reactivation for Stripe subscriptions. Free 14-day trial, then billed by Churnkey (see churnkey.co/pricing). Returns Churnkey SDK credentials for one environment.", + "development": false, + "group": null, + "id": "prvsvc_61VPMO4IPcRRbwDld5UUq", + "kind": "deployable", + "livemode": true, + "llm_context": "https://sdk.churnkey.co/llm.md", + "object": "v2.provisioning.provider_service_detail", + "pricing": { + "component": null, + "paid": null, + "paid_pricing": [], + "type": "free" + }, + "provider": "prvdr_61VPMO2NNE73fBT3S5Ljc", + "provider_configuration_schema": {}, + "provider_name": "Churnkey", + "scope": "project", + "service_id": "retention", + "updateable_to": [ + "retention" + ] + }, + { + "allowed_updates": [], + "availability": "available", + "categories": [ + "communications" + ], + "configuration_schema": {}, + "constraints": [ + { + "count": { + "at_most": 1 + }, + "type": "count" + } + ], + "created": null, + "description": "Business phone numbers, calling, and messaging. Paid Starter plan with a 7-day free trial.", + "development": false, + "group": "workspace", + "id": "prvsvc_61VP2qveAWh4hu16A5KvA", + "kind": "deployable", + "livemode": true, + "llm_context": null, + "object": "v2.provisioning.provider_service_detail", + "pricing": { + "component": { + "options": [ + { + "is_default": null, + "paid": null, + "parent_services": [ + "starter" + ], + "type": "free" + } + ] + }, + "paid": null, + "paid_pricing": [], + "type": "component" + }, + "provider": "prvdr_61VKP6RyKXtCSxNAo55ns", + "provider_configuration_schema": {}, + "provider_name": "Quo", + "scope": "project", + "service_id": "app", + "updateable_to": [ + "app" + ] + }, + { + "allowed_updates": [], + "availability": "available", + "categories": [ + "communications" + ], + "configuration_schema": {}, + "constraints": [ + { + "count": { + "at_most": 1 + }, + "type": "count" + } + ], + "created": null, + "description": "Starter plan for a Quo workspace", + "development": false, + "group": "plan", + "id": "prvsvc_61VP2qu8TNanWtQrR5QzY", + "kind": "plan", + "livemode": true, + "llm_context": null, + "object": "v2.provisioning.provider_service_detail", + "pricing": { + "component": null, + "paid": { + "description": null, + "freeform": "$19 per seat / month, 7-day free trial", + "type": "freeform" + }, + "paid_pricing": [ + { + "configuration": null, + "description": null, + "freeform": "$19 per seat / month, 7-day free trial", + "is_default": true, + "type": "freeform" + } + ], + "type": "paid" + }, + "provider": "prvdr_61VKP6RyKXtCSxNAo55ns", + "provider_configuration_schema": {}, + "provider_name": "Quo", + "scope": "account", + "service_id": "starter", + "updateable_to": [ + "starter" + ] + }, + { + "allowed_updates": [], + "availability": "available", + "categories": [ + "ai" + ], + "configuration_schema": { + "properties": { + "connect_mcp": { + "default": "no", + "description": "Connect one public HTTPS MCP server?", + "enum": [ + "no", + "yes" + ], + "type": "string" + }, + "enable_coding": { + "default": "no", + "description": "Enable coding and deep thinking?", + "enum": [ + "no", + "yes" + ], + "type": "string" + }, + "enable_deep_research": { + "default": "no", + "description": "Enable deep research?", + "enum": [ + "no", + "yes" + ], + "type": "string" + }, + "enable_google_maps": { + "default": "no", + "description": "Enable Google Maps?", + "enum": [ + "no", + "yes" + ], + "type": "string" + }, + "enable_image_generation": { + "default": "no", + "description": "Enable image generation?", + "enum": [ + "no", + "yes" + ], + "type": "string" + }, + "enable_live": { + "default": "no", + "description": "Enable live voice sessions?", + "enum": [ + "no", + "yes" + ], + "type": "string" + }, + "enable_music_generation": { + "default": "no", + "description": "Enable music generation?", + "enum": [ + "no", + "yes" + ], + "type": "string" + }, + "google_maps_api_key": { + "description": "Google Maps API key. Required only when Google Maps is enabled.", + "type": "string" + }, + "instructions": { + "description": "Instructions for the Athena agent (maximum 2,000 characters).", + "type": "string" + }, + "mcp_url": { + "description": "Public HTTPS MCP server URL. Leave blank when no MCP server is connected.", + "type": "string" + }, + "name": { + "description": "Name for the Athena agent.", + "type": "string" + }, + "starter_1": { + "description": "Optional first conversation starter shown on the public agent.", + "type": "string" + }, + "starter_2": { + "description": "Optional second conversation starter shown on the public agent.", + "type": "string" + }, + "starter_3": { + "description": "Optional third conversation starter shown on the public agent.", + "type": "string" + } + }, + "required": [ + "name", + "instructions", + "connect_mcp", + "enable_image_generation", + "enable_music_generation", + "enable_live", + "enable_coding", + "enable_deep_research", + "enable_google_maps" + ], + "type": "object" + }, + "constraints": [], + "created": null, + "description": "Configurable Athena AI agent with an optional public HTTPS MCP server.", + "development": false, + "group": null, + "id": "prvsvc_61VNv58mq1zOThOYP5VZA", + "kind": "deployable", + "livemode": true, + "llm_context": null, + "object": "v2.provisioning.provider_service_detail", + "pricing": { + "component": null, + "paid": null, + "paid_pricing": [], + "type": "free" + }, + "provider": "prvdr_61VNueP9cELmCU01Z5DFA", + "provider_configuration_schema": {}, + "provider_name": "Athena", + "scope": "project", + "service_id": "agents", + "updateable_to": [ + "agents" + ] + }, { "allowed_updates": [ { @@ -77,8 +497,8 @@ ], "type": "paid" }, + "provider": "prvdr_61VGMON1XIsZqQ3Fd5Cro", "provider_configuration_schema": {}, - "provider_id": "prvdr_61VGMON1XIsZqQ3Fd5Cro", "provider_name": "Perplexity", "scope": "project", "service_id": "api", @@ -86,32 +506,193 @@ "api" ] }, + { + "allowed_updates": [ + { + "direction": "up", + "service": "pro" + } + ], + "availability": "available", + "categories": [ + "email" + ], + "configuration_schema": {}, + "constraints": [ + { + "count": { + "at_most": 1 + }, + "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" + } + ], + "created": null, + "description": "Resend Free: 3,000 transactional emails per month, 3 domains.", + "development": false, + "group": "resend", + "id": "prvsvc_61VFx44fZQDj8o3cu5FCa", + "kind": "plan", + "livemode": true, + "llm_context": null, + "object": "v2.provisioning.provider_service_detail", + "pricing": { + "component": null, + "paid": null, + "paid_pricing": [], + "type": "free" + }, + "provider": "prvdr_61VFXTzsszWb1r1S25KMa", + "provider_configuration_schema": {}, + "provider_name": "Resend", + "scope": "account", + "service_id": "free", + "updateable_to": [ + "pro", + "free" + ] + }, { "allowed_updates": [ { "direction": "down", - "service": "hobby" + "service": "free" } ], "availability": "available", "categories": [ - "cdn" + "email" ], "configuration_schema": {}, "constraints": [ + { + "count": { + "at_most": 1 + }, + "type": "count" + }, { "mutual_exclusion_allowed_updates": true, "type": "mutual_exclusion_allowed_updates" + } + ], + "created": null, + "description": "Resend Pro: 50,000 transactional emails per month, 10 domains.", + "development": false, + "group": "resend", + "id": "prvsvc_61VFx44O170Djoah259to", + "kind": "plan", + "livemode": true, + "llm_context": null, + "object": "v2.provisioning.provider_service_detail", + "pricing": { + "component": null, + "paid": { + "description": null, + "freeform": "$20 per month", + "type": "freeform" + }, + "paid_pricing": [ + { + "configuration": null, + "description": null, + "freeform": "$20 per month", + "is_default": null, + "type": "freeform" + } + ], + "type": "paid" + }, + "provider": "prvdr_61VFXTzsszWb1r1S25KMa", + "provider_configuration_schema": {}, + "provider_name": "Resend", + "scope": "account", + "service_id": "pro", + "updateable_to": [ + "free", + "pro" + ] + }, + { + "allowed_updates": [], + "availability": "available", + "categories": [ + "email" + ], + "configuration_schema": {}, + "constraints": [ + { + "count": { + "at_most": 1 + }, + "type": "count" + } + ], + "created": null, + "description": "Email for developers. One API key per project, one shared sending quota.", + "development": false, + "group": "resend", + "id": "prvsvc_61VFx44H4RKHoEjct5QIi", + "kind": "deployable", + "livemode": true, + "llm_context": "https://raw.githubusercontent.com/resend/resend-skills/main/skills/resend/SKILL.md", + "object": "v2.provisioning.provider_service_detail", + "pricing": { + "component": { + "options": [ + { + "is_default": null, + "paid": null, + "parent_services": [ + "free", + "pro" + ], + "type": "free" + } + ] }, + "paid": null, + "paid_pricing": [], + "type": "component" + }, + "provider": "prvdr_61VFXTzsszWb1r1S25KMa", + "provider_configuration_schema": {}, + "provider_name": "Resend", + "scope": "project", + "service_id": "email", + "updateable_to": [ + "email" + ] + }, + { + "allowed_updates": [ + { + "direction": "down", + "service": "hobby" + } + ], + "availability": "available", + "categories": [ + "cdn" + ], + "configuration_schema": {}, + "constraints": [ { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, - "description": "here.now Developer plan — $20/month: unlimited sites, 2 TB storage, 20 custom domains, vanity subdomain namespaces, and a higher publish rate limit.", + "description": "here.now Developer plan — $20/month: unlimited sites, 2 TB storage, 20 custom domains, vanity subdomain namespaces, and a higher publish rate limit. Includes $5/month of Editor credits.", "development": false, "group": "plan", "id": "prvsvc_61VFZkEhYvWqln2mM5L4i", @@ -137,8 +718,8 @@ ], "type": "paid" }, + "provider": "prvdr_61VFZkDcte0pRsAFj5BFo", "provider_configuration_schema": {}, - "provider_id": "prvdr_61VFZkDcte0pRsAFj5BFo", "provider_name": "herenow", "scope": "account", "service_id": "developer", @@ -185,8 +766,8 @@ "is_default": null, "paid": null, "parent_services": [ - "hobby", - "developer" + "developer", + "hobby" ], "type": "free" } @@ -196,8 +777,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61VFZkDcte0pRsAFj5BFo", "provider_configuration_schema": {}, - "provider_id": "prvdr_61VFZkDcte0pRsAFj5BFo", "provider_name": "herenow", "scope": "project", "service_id": "hosting", @@ -218,19 +799,19 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, - "description": "here.now Hobby plan — $4/month: up to 1,000 sites, 500 GB storage, 5 custom domains, vanity subdomain namespaces, and a higher publish rate limit.", + "description": "here.now Hobby plan — $4/month: up to 1,000 sites, 500 GB storage, 5 custom domains, vanity subdomain namespaces, and a higher publish rate limit. Includes $2/month of Editor credits.", "development": false, "group": "plan", "id": "prvsvc_61VFZkE0r3eb7UjQR5AK0", @@ -256,8 +837,8 @@ ], "type": "paid" }, + "provider": "prvdr_61VFZkDcte0pRsAFj5BFo", "provider_configuration_schema": {}, - "provider_id": "prvdr_61VFZkDcte0pRsAFj5BFo", "provider_name": "herenow", "scope": "account", "service_id": "hobby", @@ -356,12 +937,12 @@ ], "type": "paid" }, + "provider": "prvdr_61V3J0dhwegIR1fhV5Jx2", "provider_configuration_schema": { "additionalProperties": false, "properties": {}, "type": "object" }, - "provider_id": "prvdr_61V3J0dhwegIR1fhV5Jx2", "provider_name": "Shopify", "scope": "project", "service_id": "store", @@ -377,15 +958,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -415,6 +996,7 @@ ], "type": "paid" }, + "provider": "prvdr_61V2Z15R0ek7uaOxE57Z2", "provider_configuration_schema": { "properties": { "org_name": { @@ -427,7 +1009,6 @@ ], "type": "object" }, - "provider_id": "prvdr_61V2Z15R0ek7uaOxE57Z2", "provider_name": "Datadog", "scope": "account", "service_id": "pay-as-you-go", @@ -488,6 +1069,7 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61V2Z15R0ek7uaOxE57Z2", "provider_configuration_schema": { "properties": { "org_name": { @@ -500,7 +1082,6 @@ ], "type": "object" }, - "provider_id": "prvdr_61V2Z15R0ek7uaOxE57Z2", "provider_name": "Datadog", "scope": "project", "service_id": "observability", @@ -521,15 +1102,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -547,6 +1128,7 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61V2Z15R0ek7uaOxE57Z2", "provider_configuration_schema": { "properties": { "org_name": { @@ -559,7 +1141,6 @@ ], "type": "object" }, - "provider_id": "prvdr_61V2Z15R0ek7uaOxE57Z2", "provider_name": "Datadog", "scope": "account", "service_id": "trial", @@ -629,11 +1210,11 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61V2d6KyQRdM5XHd4505o", "provider_configuration_schema": { "properties": {}, "type": "object" }, - "provider_id": "prvdr_61V2d6KyQRdM5XHd4505o", "provider_name": "Steel", "scope": "project", "service_id": "browser", @@ -654,15 +1235,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -680,11 +1261,11 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61V2d6KyQRdM5XHd4505o", "provider_configuration_schema": { "properties": {}, "type": "object" }, - "provider_id": "prvdr_61V2d6KyQRdM5XHd4505o", "provider_name": "Steel", "scope": "account", "service_id": "plan-launch", @@ -706,15 +1287,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -744,11 +1325,11 @@ ], "type": "paid" }, + "provider": "prvdr_61V2d6KyQRdM5XHd4505o", "provider_configuration_schema": { "properties": {}, "type": "object" }, - "provider_id": "prvdr_61V2d6KyQRdM5XHd4505o", "provider_name": "Steel", "scope": "account", "service_id": "plan-scale", @@ -785,8 +1366,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61V2MN5n5dVBeEEIX5S8m", "provider_configuration_schema": {}, - "provider_id": "prvdr_61V2MN5n5dVBeEEIX5S8m", "provider_name": "Schematic", "scope": "account", "service_id": "schematic-free", @@ -833,8 +1414,8 @@ "is_default": true, "paid": null, "parent_services": [ - "schematic-growth", - "schematic-free" + "schematic-free", + "schematic-growth" ], "type": "free" } @@ -844,8 +1425,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61V2MN5n5dVBeEEIX5S8m", "provider_configuration_schema": {}, - "provider_id": "prvdr_61V2MN5n5dVBeEEIX5S8m", "provider_name": "Schematic", "scope": "project", "service_id": "schematic-environment", @@ -893,8 +1474,8 @@ ], "type": "paid" }, + "provider": "prvdr_61V2MN5n5dVBeEEIX5S8m", "provider_configuration_schema": {}, - "provider_id": "prvdr_61V2MN5n5dVBeEEIX5S8m", "provider_name": "Schematic", "scope": "account", "service_id": "schematic-growth", @@ -938,11 +1519,11 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61V0NO7jETrcGDKod57JY", "provider_configuration_schema": { "properties": {}, "type": "object" }, - "provider_id": "prvdr_61V0NO7jETrcGDKod57JY", "provider_name": "customerio", "scope": "account", "service_id": "builder:sandbox", @@ -1006,11 +1587,11 @@ ], "type": "paid" }, + "provider": "prvdr_61V0NO7jETrcGDKod57JY", "provider_configuration_schema": { "properties": {}, "type": "object" }, - "provider_id": "prvdr_61V0NO7jETrcGDKod57JY", "provider_name": "customerio", "scope": "account", "service_id": "builder", @@ -1029,15 +1610,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -1055,6 +1636,7 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61V0eUvURNJSjPY2J5WfY", "provider_configuration_schema": { "properties": { "account": { @@ -1064,7 +1646,6 @@ }, "type": "object" }, - "provider_id": "prvdr_61V0eUvURNJSjPY2J5WfY", "provider_name": "Pydantic", "scope": "account", "service_id": "personal", @@ -1084,7 +1665,7 @@ "configuration_schema": { "properties": { "organization": { - "description": "Name of an existing organization you administer to create the new project in. Defaults to your personal organization.", + "description": "Name of an existing organization you administer to create the new project in. Defaults to your default organization.", "maxLength": 50, "minLength": 2, "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$", @@ -1141,6 +1722,7 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61V0eUvURNJSjPY2J5WfY", "provider_configuration_schema": { "properties": { "account": { @@ -1150,7 +1732,6 @@ }, "type": "object" }, - "provider_id": "prvdr_61V0eUvURNJSjPY2J5WfY", "provider_name": "Pydantic", "scope": "project", "service_id": "logfire", @@ -1200,8 +1781,8 @@ ], "type": "paid" }, + "provider": "prvdr_61V0tIZIwN9RMcR2T54Yi", "provider_configuration_schema": {}, - "provider_id": "prvdr_61V0tIZIwN9RMcR2T54Yi", "provider_name": "Composio", "scope": "account", "service_id": "starter", @@ -1239,8 +1820,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61V0tIZIwN9RMcR2T54Yi", "provider_configuration_schema": {}, - "provider_id": "prvdr_61V0tIZIwN9RMcR2T54Yi", "provider_name": "Composio", "scope": "account", "service_id": "hobby", @@ -1286,8 +1867,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61V0tIZIwN9RMcR2T54Yi", "provider_configuration_schema": {}, - "provider_id": "prvdr_61V0tIZIwN9RMcR2T54Yi", "provider_name": "Composio", "scope": "project", "service_id": "project", @@ -1339,11 +1920,11 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61V0NO7jETrcGDKod57JY", "provider_configuration_schema": { "properties": {}, "type": "object" }, - "provider_id": "prvdr_61V0NO7jETrcGDKod57JY", "provider_name": "customerio", "scope": "project", "service_id": "workspace", @@ -1355,11 +1936,11 @@ "allowed_updates": [ { "direction": "any", - "service": "beginner-monthly" + "service": "pro-monthly" }, { "direction": "any", - "service": "pro-monthly" + "service": "beginner-monthly" }, { "direction": "any", @@ -1399,14 +1980,14 @@ ], "type": "paid" }, + "provider": "prvdr_61V0eGC6sUPXoATb051se", "provider_configuration_schema": {}, - "provider_id": "prvdr_61V0eGC6sUPXoATb051se", "provider_name": "createos", "scope": "account", "service_id": "enterprise-monthly", "updateable_to": [ - "beginner-monthly", "pro-monthly", + "beginner-monthly", "free", "enterprise-monthly" ] @@ -1415,7 +1996,7 @@ "allowed_updates": [ { "direction": "any", - "service": "enterprise-monthly" + "service": "pro-monthly" }, { "direction": "any", @@ -1423,7 +2004,7 @@ }, { "direction": "any", - "service": "pro-monthly" + "service": "enterprise-monthly" } ], "availability": "available", @@ -1459,15 +2040,15 @@ ], "type": "paid" }, + "provider": "prvdr_61V0eGC6sUPXoATb051se", "provider_configuration_schema": {}, - "provider_id": "prvdr_61V0eGC6sUPXoATb051se", "provider_name": "createos", "scope": "account", "service_id": "beginner-monthly", "updateable_to": [ - "enterprise-monthly", - "free", "pro-monthly", + "free", + "enterprise-monthly", "beginner-monthly" ] }, @@ -1475,15 +2056,15 @@ "allowed_updates": [ { "direction": "any", - "service": "enterprise-monthly" + "service": "beginner-monthly" }, { "direction": "any", - "service": "beginner-monthly" + "service": "free" }, { "direction": "any", - "service": "free" + "service": "enterprise-monthly" } ], "availability": "available", @@ -1519,15 +2100,15 @@ ], "type": "paid" }, + "provider": "prvdr_61V0eGC6sUPXoATb051se", "provider_configuration_schema": {}, - "provider_id": "prvdr_61V0eGC6sUPXoATb051se", "provider_name": "createos", "scope": "account", "service_id": "pro-monthly", "updateable_to": [ - "enterprise-monthly", "beginner-monthly", "free", + "enterprise-monthly", "pro-monthly" ] }, @@ -1535,7 +2116,7 @@ "allowed_updates": [ { "direction": "any", - "service": "enterprise-monthly" + "service": "pro-monthly" }, { "direction": "any", @@ -1543,7 +2124,7 @@ }, { "direction": "any", - "service": "pro-monthly" + "service": "enterprise-monthly" } ], "availability": "available", @@ -1567,15 +2148,15 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61V0eGC6sUPXoATb051se", "provider_configuration_schema": {}, - "provider_id": "prvdr_61V0eGC6sUPXoATb051se", "provider_name": "createos", "scope": "account", "service_id": "free", "updateable_to": [ - "enterprise-monthly", - "beginner-monthly", "pro-monthly", + "beginner-monthly", + "enterprise-monthly", "free" ] }, @@ -1604,9 +2185,9 @@ "paid": null, "parent_services": [ "pro-monthly", - "enterprise-monthly", + "free", "beginner-monthly", - "free" + "enterprise-monthly" ], "type": "free" } @@ -1616,8 +2197,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61V0eGC6sUPXoATb051se", "provider_configuration_schema": {}, - "provider_id": "prvdr_61V0eGC6sUPXoATb051se", "provider_name": "createos", "scope": "project", "service_id": "project", @@ -1642,7 +2223,7 @@ "configuration_schema": { "properties": { "organization": { - "description": "Name of an existing organization you administer to put on this paid plan. A paid plan is not applied to your personal organization through provisioning; upgrade that in the Logfire app.", + "description": "Name of an existing organization you administer to put on this paid plan. Legacy personal organizations must still be upgraded in the Logfire app.", "maxLength": 50, "minLength": 2, "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$", @@ -1655,15 +2236,15 @@ "type": "object" }, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -1693,6 +2274,7 @@ ], "type": "paid" }, + "provider": "prvdr_61V0eUvURNJSjPY2J5WfY", "provider_configuration_schema": { "properties": { "account": { @@ -1702,7 +2284,6 @@ }, "type": "object" }, - "provider_id": "prvdr_61V0eUvURNJSjPY2J5WfY", "provider_name": "Pydantic", "scope": "account", "service_id": "growth", @@ -1728,7 +2309,7 @@ "configuration_schema": { "properties": { "organization": { - "description": "Name of an existing organization you administer to put on this paid plan. A paid plan is not applied to your personal organization through provisioning; upgrade that in the Logfire app.", + "description": "Name of an existing organization you administer to put on this paid plan. Legacy personal organizations must still be upgraded in the Logfire app.", "maxLength": 50, "minLength": 2, "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$", @@ -1744,18 +2325,18 @@ "required": [ "organization" ], - "type": "object" - }, - "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, + "type": "object" + }, + "constraints": [ { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -1785,6 +2366,7 @@ ], "type": "paid" }, + "provider": "prvdr_61V0eUvURNJSjPY2J5WfY", "provider_configuration_schema": { "properties": { "account": { @@ -1794,7 +2376,6 @@ }, "type": "object" }, - "provider_id": "prvdr_61V0eUvURNJSjPY2J5WfY", "provider_name": "Pydantic", "scope": "account", "service_id": "team", @@ -1807,11 +2388,11 @@ "allowed_updates": [ { "direction": "down", - "service": "hobby" + "service": "standard" }, { "direction": "down", - "service": "standard" + "service": "hobby" } ], "availability": "available", @@ -1820,15 +2401,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -1858,17 +2439,17 @@ ], "type": "paid" }, + "provider": "prvdr_61V0Na4Yx14hBk8Yw5WG8", "provider_configuration_schema": { "properties": {}, "type": "object" }, - "provider_id": "prvdr_61V0Na4Yx14hBk8Yw5WG8", "provider_name": "Chatbase", "scope": "account", "service_id": "pro", "updateable_to": [ - "hobby", "standard", + "hobby", "pro" ] }, @@ -1907,9 +2488,9 @@ "is_default": null, "paid": null, "parent_services": [ - "hobby", + "pro", "standard", - "pro" + "hobby" ], "type": "free" }, @@ -1929,11 +2510,11 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61V0Na4Yx14hBk8Yw5WG8", "provider_configuration_schema": { "properties": {}, "type": "object" }, - "provider_id": "prvdr_61V0Na4Yx14hBk8Yw5WG8", "provider_name": "Chatbase", "scope": "project", "service_id": "agent", @@ -1945,11 +2526,11 @@ "allowed_updates": [ { "direction": "up", - "service": "standard" + "service": "pro" }, { "direction": "up", - "service": "pro" + "service": "standard" } ], "availability": "available", @@ -1958,15 +2539,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -1996,29 +2577,29 @@ ], "type": "paid" }, + "provider": "prvdr_61V0Na4Yx14hBk8Yw5WG8", "provider_configuration_schema": { "properties": {}, "type": "object" }, - "provider_id": "prvdr_61V0Na4Yx14hBk8Yw5WG8", "provider_name": "Chatbase", "scope": "account", "service_id": "hobby", "updateable_to": [ - "standard", "pro", + "standard", "hobby" ] }, { "allowed_updates": [ - { - "direction": "down", - "service": "hobby" - }, { "direction": "up", "service": "pro" + }, + { + "direction": "down", + "service": "hobby" } ], "availability": "available", @@ -2027,15 +2608,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -2065,17 +2646,17 @@ ], "type": "paid" }, + "provider": "prvdr_61V0Na4Yx14hBk8Yw5WG8", "provider_configuration_schema": { "properties": {}, "type": "object" }, - "provider_id": "prvdr_61V0Na4Yx14hBk8Yw5WG8", "provider_name": "Chatbase", "scope": "account", "service_id": "standard", "updateable_to": [ - "hobby", "pro", + "hobby", "standard" ] }, @@ -2098,15 +2679,15 @@ "type": "object" }, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -2136,8 +2717,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UwKuCVtXVMFgprf59Ng", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UwKuCVtXVMFgprf59Ng", "provider_name": "Depot", "scope": "account", "service_id": "startup-plan", @@ -2176,8 +2757,8 @@ "is_default": null, "paid": null, "parent_services": [ - "developer-plan", - "startup-plan" + "startup-plan", + "developer-plan" ], "type": "free" } @@ -2187,8 +2768,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UwKuCVtXVMFgprf59Ng", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UwKuCVtXVMFgprf59Ng", "provider_name": "Depot", "scope": "project", "service_id": "api", @@ -2215,15 +2796,15 @@ "type": "object" }, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -2253,8 +2834,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UwKuCVtXVMFgprf59Ng", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UwKuCVtXVMFgprf59Ng", "provider_name": "Depot", "scope": "account", "service_id": "developer-plan", @@ -2348,8 +2929,8 @@ ], "type": "paid" }, + "provider": "prvdr_61Uuf4oXg8bVlDmma51z6", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Uuf4oXg8bVlDmma51z6", "provider_name": "Tabstack", "scope": "project", "service_id": "api", @@ -2405,8 +2986,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UvW0H6W4mhL335F54SW", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UvW0H6W4mhL335F54SW", "provider_name": "Spaceship", "scope": "project", "service_id": "domain", @@ -2438,11 +3019,8 @@ "paid_pricing": [], "type": "free" }, - "provider_configuration_schema": { - "properties": {}, - "type": "object" - }, - "provider_id": "prvdr_61UvIBCNECigaYpha53zM", + "provider": "prvdr_61UvIBCNECigaYpha53zM", + "provider_configuration_schema": {}, "provider_name": "RevenueCat", "scope": "project", "service_id": "app", @@ -2464,15 +3042,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -2502,8 +3080,8 @@ ], "type": "paid" }, + "provider": "prvdr_61Unj5D2LO6EYhGmo5DBQ", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Unj5D2LO6EYhGmo5DBQ", "provider_name": "Exa", "scope": "project", "service_id": "pay_as_you_go", @@ -2526,15 +3104,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -2552,8 +3130,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61Unj5D2LO6EYhGmo5DBQ", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Unj5D2LO6EYhGmo5DBQ", "provider_name": "Exa", "scope": "project", "service_id": "free", @@ -2613,8 +3191,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61Um10GcB4A0pdo6z56Bk", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Um10GcB4A0pdo6z56Bk", "provider_name": "E2B", "scope": "project", "service_id": "sandbox", @@ -2763,8 +3341,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UnUOEpxbShf2sSK5NYO", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnUOEpxbShf2sSK5NYO", "provider_name": "ClickHouse", "scope": "account", "service_id": "clickhouse", @@ -2822,8 +3400,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UnUOEpxbShf2sSK5NYO", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnUOEpxbShf2sSK5NYO", "provider_name": "ClickHouse", "scope": "account", "service_id": "scale", @@ -2994,8 +3572,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UnUOEpxbShf2sSK5NYO", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnUOEpxbShf2sSK5NYO", "provider_name": "ClickHouse", "scope": "account", "service_id": "postgres", @@ -3053,8 +3631,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UnUOEpxbShf2sSK5NYO", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnUOEpxbShf2sSK5NYO", "provider_name": "ClickHouse", "scope": "account", "service_id": "basic", @@ -3114,8 +3692,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UnUOEpxbShf2sSK5NYO", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnUOEpxbShf2sSK5NYO", "provider_name": "ClickHouse", "scope": "account", "service_id": "enterprise", @@ -3178,8 +3756,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UnoL4ZPCBLxqCQW5WJU", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnoL4ZPCBLxqCQW5WJU", "provider_name": "Blaxel", "scope": "project", "service_id": "agent-drive", @@ -3265,8 +3843,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UnoL4ZPCBLxqCQW5WJU", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnoL4ZPCBLxqCQW5WJU", "provider_name": "Blaxel", "scope": "project", "service_id": "sandbox", @@ -3278,11 +3856,11 @@ "allowed_updates": [ { "direction": "up", - "service": "tier-2" + "service": "tier-6" }, { "direction": "up", - "service": "tier-3" + "service": "tier-5" }, { "direction": "up", @@ -3290,11 +3868,11 @@ }, { "direction": "up", - "service": "tier-5" + "service": "tier-3" }, { "direction": "up", - "service": "tier-6" + "service": "tier-2" } ], "availability": "available", @@ -3336,41 +3914,41 @@ ], "type": "paid" }, + "provider": "prvdr_61UnoL4ZPCBLxqCQW5WJU", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnoL4ZPCBLxqCQW5WJU", "provider_name": "Blaxel", "scope": "account", "service_id": "tier-1", "updateable_to": [ - "tier-2", - "tier-3", - "tier-4", - "tier-5", "tier-6", + "tier-5", + "tier-4", + "tier-3", + "tier-2", "tier-1" ] }, { "allowed_updates": [ { - "direction": "down", - "service": "tier-1" + "direction": "up", + "service": "tier-6" }, { - "direction": "down", - "service": "tier-2" + "direction": "up", + "service": "tier-5" }, { "direction": "down", "service": "tier-3" }, { - "direction": "up", - "service": "tier-5" + "direction": "down", + "service": "tier-2" }, { - "direction": "up", - "service": "tier-6" + "direction": "down", + "service": "tier-1" } ], "availability": "available", @@ -3412,29 +3990,29 @@ ], "type": "paid" }, + "provider": "prvdr_61UnoL4ZPCBLxqCQW5WJU", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnoL4ZPCBLxqCQW5WJU", "provider_name": "Blaxel", "scope": "account", "service_id": "tier-4", "updateable_to": [ - "tier-1", - "tier-2", - "tier-3", - "tier-5", "tier-6", + "tier-5", + "tier-3", + "tier-2", + "tier-1", "tier-4" ] }, { "allowed_updates": [ { - "direction": "down", - "service": "tier-1" + "direction": "up", + "service": "tier-6" }, { "direction": "down", - "service": "tier-2" + "service": "tier-4" }, { "direction": "down", @@ -3442,11 +4020,11 @@ }, { "direction": "down", - "service": "tier-4" + "service": "tier-2" }, { - "direction": "up", - "service": "tier-6" + "direction": "down", + "service": "tier-1" } ], "availability": "available", @@ -3488,17 +4066,17 @@ ], "type": "paid" }, + "provider": "prvdr_61UnoL4ZPCBLxqCQW5WJU", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnoL4ZPCBLxqCQW5WJU", "provider_name": "Blaxel", "scope": "account", "service_id": "tier-5", "updateable_to": [ - "tier-1", - "tier-2", - "tier-3", - "tier-4", "tier-6", + "tier-4", + "tier-3", + "tier-2", + "tier-1", "tier-5" ] }, @@ -3506,11 +4084,7 @@ "allowed_updates": [ { "direction": "up", - "service": "tier-3" - }, - { - "direction": "down", - "service": "tier-1" + "service": "tier-6" }, { "direction": "up", @@ -3522,7 +4096,11 @@ }, { "direction": "up", - "service": "tier-6" + "service": "tier-3" + }, + { + "direction": "down", + "service": "tier-1" } ], "availability": "available", @@ -3564,17 +4142,17 @@ ], "type": "paid" }, + "provider": "prvdr_61UnoL4ZPCBLxqCQW5WJU", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnoL4ZPCBLxqCQW5WJU", "provider_name": "Blaxel", "scope": "account", "service_id": "tier-2", "updateable_to": [ - "tier-3", - "tier-1", + "tier-6", "tier-5", "tier-4", - "tier-6", + "tier-3", + "tier-1", "tier-2" ] }, @@ -3582,11 +4160,11 @@ "allowed_updates": [ { "direction": "down", - "service": "tier-1" + "service": "tier-5" }, { "direction": "down", - "service": "tier-2" + "service": "tier-4" }, { "direction": "down", @@ -3594,11 +4172,11 @@ }, { "direction": "down", - "service": "tier-4" + "service": "tier-2" }, { "direction": "down", - "service": "tier-5" + "service": "tier-1" } ], "availability": "available", @@ -3640,29 +4218,25 @@ ], "type": "paid" }, + "provider": "prvdr_61UnoL4ZPCBLxqCQW5WJU", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnoL4ZPCBLxqCQW5WJU", "provider_name": "Blaxel", "scope": "account", "service_id": "tier-6", "updateable_to": [ - "tier-1", - "tier-2", - "tier-3", - "tier-4", "tier-5", + "tier-4", + "tier-3", + "tier-2", + "tier-1", "tier-6" ] }, { "allowed_updates": [ { - "direction": "down", - "service": "tier-1" - }, - { - "direction": "down", - "service": "tier-2" + "direction": "up", + "service": "tier-6" }, { "direction": "up", @@ -3673,8 +4247,12 @@ "service": "tier-4" }, { - "direction": "up", - "service": "tier-6" + "direction": "down", + "service": "tier-2" + }, + { + "direction": "down", + "service": "tier-1" } ], "availability": "available", @@ -3716,17 +4294,17 @@ ], "type": "paid" }, + "provider": "prvdr_61UnoL4ZPCBLxqCQW5WJU", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnoL4ZPCBLxqCQW5WJU", "provider_name": "Blaxel", "scope": "account", "service_id": "tier-3", "updateable_to": [ - "tier-1", - "tier-2", + "tier-6", "tier-5", "tier-4", - "tier-6", + "tier-2", + "tier-1", "tier-3" ] }, @@ -3797,8 +4375,8 @@ ], "type": "paid" }, + "provider": "prvdr_61Uo1AQvDtb7Wseng5OHw", "provider_configuration_schema": null, - "provider_id": "prvdr_61Uo1AQvDtb7Wseng5OHw", "provider_name": "PostalForm", "scope": "project", "service_id": "mail", @@ -3870,8 +4448,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UnkAFYNcaD50TOY54Q4", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnkAFYNcaD50TOY54Q4", "provider_name": "HeyGen", "scope": "project", "service_id": "api", @@ -3924,8 +4502,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61Unj5D2LO6EYhGmo5DBQ", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Unj5D2LO6EYhGmo5DBQ", "provider_name": "Exa", "scope": "project", "service_id": "api", @@ -3946,15 +4524,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -3984,8 +4562,8 @@ ], "type": "paid" }, + "provider": "prvdr_61Um10GcB4A0pdo6z56Bk", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Um10GcB4A0pdo6z56Bk", "provider_name": "E2B", "scope": "project", "service_id": "hobby", @@ -4007,15 +4585,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -4045,8 +4623,8 @@ ], "type": "paid" }, + "provider": "prvdr_61Um10GcB4A0pdo6z56Bk", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Um10GcB4A0pdo6z56Bk", "provider_name": "E2B", "scope": "project", "service_id": "pro", @@ -4139,8 +4717,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UnTCu1qlHAWbYZU5Sv2", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnTCu1qlHAWbYZU5Sv2", "provider_name": "Supermemory", "scope": "project", "service_id": "memory", @@ -4194,9 +4772,9 @@ "is_default": null, "paid": null, "parent_services": [ - "hobbyist", + "startup", "developer", - "startup" + "hobbyist" ], "type": "free" } @@ -4206,8 +4784,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UnOfhF7jlP9Fcxr55Z2", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnOfhF7jlP9Fcxr55Z2", "provider_name": "KERNEL", "scope": "project", "service_id": "project", @@ -4232,15 +4810,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -4258,8 +4836,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UnOfhF7jlP9Fcxr55Z2", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnOfhF7jlP9Fcxr55Z2", "provider_name": "KERNEL", "scope": "account", "service_id": "developer", @@ -4286,15 +4864,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -4324,8 +4902,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UnOfhF7jlP9Fcxr55Z2", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnOfhF7jlP9Fcxr55Z2", "provider_name": "KERNEL", "scope": "account", "service_id": "startup", @@ -4337,13 +4915,13 @@ }, { "allowed_updates": [ - { - "direction": "down", - "service": "developer" - }, { "direction": "up", "service": "startup" + }, + { + "direction": "down", + "service": "developer" } ], "availability": "available", @@ -4352,15 +4930,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -4390,14 +4968,14 @@ ], "type": "paid" }, + "provider": "prvdr_61UnOfhF7jlP9Fcxr55Z2", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnOfhF7jlP9Fcxr55Z2", "provider_name": "KERNEL", "scope": "account", "service_id": "hobbyist", "updateable_to": [ - "developer", "startup", + "developer", "hobbyist" ] }, @@ -4476,8 +5054,8 @@ ], "type": "paid" }, + "provider": "prvdr_61Uj2YmiyLwllzQQX5Vui", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Uj2YmiyLwllzQQX5Vui", "provider_name": "Wix", "scope": "project", "service_id": "headless", @@ -4692,8 +5270,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UnKXcVflBIkLCbX54aW", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UnKXcVflBIkLCbX54aW", "provider_name": "Parallel", "scope": "project", "service_id": "api", @@ -4746,8 +5324,8 @@ ], "type": "paid" }, + "provider": "prvdr_61Ulotgugv9hEYa1b5HwO", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Ulotgugv9hEYa1b5HwO", "provider_name": "Laravel_Cloud", "scope": "account", "service_id": "growth", @@ -4819,8 +5397,8 @@ "type": "freeform" }, "parent_services": [ - "growth", - "starter" + "starter", + "growth" ], "type": "paid" } @@ -4830,8 +5408,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61Ulotgugv9hEYa1b5HwO", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Ulotgugv9hEYa1b5HwO", "provider_name": "Laravel_Cloud", "scope": "project", "service_id": "valkey", @@ -4921,8 +5499,8 @@ "type": "freeform" }, "parent_services": [ - "growth", - "starter" + "starter", + "growth" ], "type": "paid" } @@ -4932,8 +5510,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61Ulotgugv9hEYa1b5HwO", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Ulotgugv9hEYa1b5HwO", "provider_name": "Laravel_Cloud", "scope": "project", "service_id": "application", @@ -5004,8 +5582,8 @@ "type": "freeform" }, "parent_services": [ - "growth", - "starter" + "starter", + "growth" ], "type": "paid" } @@ -5015,8 +5593,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61Ulotgugv9hEYa1b5HwO", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Ulotgugv9hEYa1b5HwO", "provider_name": "Laravel_Cloud", "scope": "project", "service_id": "mysql", @@ -5069,8 +5647,8 @@ ], "type": "paid" }, + "provider": "prvdr_61Ulotgugv9hEYa1b5HwO", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Ulotgugv9hEYa1b5HwO", "provider_name": "Laravel_Cloud", "scope": "account", "service_id": "starter", @@ -5166,8 +5744,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UmxGkoAMSyI59y25SzA", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UmxGkoAMSyI59y25SzA", "provider_name": "WordPress.com", "scope": "project", "service_id": "site", @@ -5221,8 +5799,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UmxGkoAMSyI59y25SzA", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UmxGkoAMSyI59y25SzA", "provider_name": "WordPress.com", "scope": "project", "service_id": "domain", @@ -5276,8 +5854,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UlD0fxuDb9nsZ7c5VfE", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UlD0fxuDb9nsZ7c5VfE", "provider_name": "Base44_Projects", "scope": "project", "service_id": "app", @@ -5331,9 +5909,9 @@ "paid": null, "parent_services": [ "pro", - "starter", + "free", "business", - "free" + "starter" ], "type": "free" } @@ -5343,8 +5921,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61Ulq2NBoEkAzhMKC50vA", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Ulq2NBoEkAzhMKC50vA", "provider_name": "Prisma", "scope": "project", "service_id": "database", @@ -5355,16 +5933,16 @@ { "allowed_updates": [ { - "direction": "up", - "service": "business" + "direction": "any", + "service": "free" }, { "direction": "up", "service": "starter" }, { - "direction": "any", - "service": "free" + "direction": "up", + "service": "business" }, { "direction": "up", @@ -5392,20 +5970,24 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61Ulq2NBoEkAzhMKC50vA", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Ulq2NBoEkAzhMKC50vA", "provider_name": "Prisma", "scope": "account", "service_id": "free", "updateable_to": [ - "business", - "starter", "free", + "starter", + "business", "pro" ] }, { "allowed_updates": [ + { + "direction": "down", + "service": "free" + }, { "direction": "down", "service": "pro" @@ -5414,10 +5996,6 @@ "direction": "any", "service": "business" }, - { - "direction": "down", - "service": "free" - }, { "direction": "down", "service": "starter" @@ -5456,20 +6034,24 @@ ], "type": "paid" }, + "provider": "prvdr_61Ulq2NBoEkAzhMKC50vA", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Ulq2NBoEkAzhMKC50vA", "provider_name": "Prisma", "scope": "account", "service_id": "business", "updateable_to": [ + "free", "pro", "business", - "free", "starter" ] }, { "allowed_updates": [ + { + "direction": "any", + "service": "pro" + }, { "direction": "down", "service": "free" @@ -5478,10 +6060,6 @@ "direction": "up", "service": "business" }, - { - "direction": "any", - "service": "pro" - }, { "direction": "down", "service": "starter" @@ -5520,35 +6098,35 @@ ], "type": "paid" }, + "provider": "prvdr_61Ulq2NBoEkAzhMKC50vA", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Ulq2NBoEkAzhMKC50vA", "provider_name": "Prisma", "scope": "account", "service_id": "pro", "updateable_to": [ + "pro", "free", "business", - "pro", "starter" ] }, { "allowed_updates": [ { - "direction": "down", - "service": "free" + "direction": "up", + "service": "pro" }, { "direction": "any", "service": "starter" }, { - "direction": "up", - "service": "business" + "direction": "down", + "service": "free" }, { "direction": "up", - "service": "pro" + "service": "business" } ], "availability": "available", @@ -5584,16 +6162,16 @@ ], "type": "paid" }, + "provider": "prvdr_61Ulq2NBoEkAzhMKC50vA", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Ulq2NBoEkAzhMKC50vA", "provider_name": "Prisma", "scope": "account", "service_id": "starter", "updateable_to": [ - "free", + "pro", "starter", - "business", - "pro" + "free", + "business" ] }, { @@ -5626,8 +6204,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61Uko2Ae2S1CUgAxI54kS", "provider_configuration_schema": {}, - "provider_id": "prvdr_61Uko2Ae2S1CUgAxI54kS", "provider_name": "Metronome", "scope": "project", "service_id": "sandbox", @@ -5693,8 +6271,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UjQLgXIM0R40WnZ5S8m", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UjQLgXIM0R40WnZ5S8m", "provider_name": "AgentPhone", "scope": "project", "service_id": "number", @@ -5744,8 +6322,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UQsPLOiNuyFxFP45ADo", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQsPLOiNuyFxFP45ADo", "provider_name": "Twilio", "scope": "project", "service_id": "business", @@ -5795,8 +6373,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UQsPLOiNuyFxFP45ADo", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQsPLOiNuyFxFP45ADo", "provider_name": "Twilio", "scope": "project", "service_id": "hobbyist", @@ -5828,9 +6406,9 @@ "is_default": null, "paid": null, "parent_services": [ - "free", + "startup", "developer", - "startup" + "free" ], "type": "free" } @@ -5840,8 +6418,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UWNSVKoGlVDwbHX5IUK", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UWNSVKoGlVDwbHX5IUK", "provider_name": "AgentMail", "scope": "project", "service_id": "api", @@ -5898,8 +6476,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UacoeBnJSHilBZJ5FIm", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UacoeBnJSHilBZJ5FIm", "provider_name": "Squarespace", "scope": "project", "service_id": "domain", @@ -5930,8 +6508,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UYtnmm5DvySq8Ol56tE", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UYtnmm5DvySq8Ol56tE", "provider_name": "ElevenLabs", "scope": "project", "service_id": "tts", @@ -6021,8 +6599,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UU7UnQL58lBHk2p55uC", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UU7UnQL58lBHk2p55uC", "provider_name": "Algolia", "scope": "project", "service_id": "application", @@ -6071,6 +6649,7 @@ ], "type": "paid" }, + "provider": "prvdr_61UWLVjDZyzuP1BCY5EAi", "provider_configuration_schema": { "additionalProperties": false, "properties": { @@ -6084,7 +6663,6 @@ ], "type": "object" }, - "provider_id": "prvdr_61UWLVjDZyzuP1BCY5EAi", "provider_name": "Privy", "scope": "account", "service_id": "scale", @@ -6126,6 +6704,7 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UWLVjDZyzuP1BCY5EAi", "provider_configuration_schema": { "additionalProperties": false, "properties": { @@ -6139,7 +6718,6 @@ ], "type": "object" }, - "provider_id": "prvdr_61UWLVjDZyzuP1BCY5EAi", "provider_name": "Privy", "scope": "account", "service_id": "free", @@ -6190,6 +6768,7 @@ ], "type": "paid" }, + "provider": "prvdr_61UWLVjDZyzuP1BCY5EAi", "provider_configuration_schema": { "additionalProperties": false, "properties": { @@ -6203,7 +6782,6 @@ ], "type": "object" }, - "provider_id": "prvdr_61UWLVjDZyzuP1BCY5EAi", "provider_name": "Privy", "scope": "account", "service_id": "core", @@ -6271,8 +6849,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_name": "Cloudflare", "scope": "project", "service_id": "r2:bucket", @@ -6316,8 +6894,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UYA33tkF5l7Dkwz5KGG", "provider_configuration_schema": null, - "provider_id": "prvdr_61UYA33tkF5l7Dkwz5KGG", "provider_name": "Browserbase", "scope": "project", "service_id": "project", @@ -6329,19 +6907,19 @@ "allowed_updates": [ { "direction": "any", - "service": "b2c-professional" + "service": "free" }, { "direction": "any", - "service": "b2b-essentials" + "service": "b2c-essentials" }, { "direction": "any", - "service": "b2c-essentials" + "service": "b2b-essentials" }, { "direction": "any", - "service": "free" + "service": "b2c-professional" } ], "availability": "available", @@ -6377,6 +6955,7 @@ ], "type": "paid" }, + "provider": "prvdr_61UVctyxfLOj4FpVw5Bmi", "provider_configuration_schema": { "additionalProperties": false, "properties": { @@ -6406,15 +6985,14 @@ ], "type": "object" }, - "provider_id": "prvdr_61UVctyxfLOj4FpVw5Bmi", "provider_name": "Auth0", "scope": "project", "service_id": "b2b-professional", "updateable_to": [ - "b2c-professional", - "b2b-essentials", - "b2c-essentials", "free", + "b2c-essentials", + "b2b-essentials", + "b2c-professional", "b2b-professional" ] }, @@ -6422,19 +7000,19 @@ "allowed_updates": [ { "direction": "any", - "service": "b2b-professional" + "service": "free" }, { "direction": "any", - "service": "b2c-professional" + "service": "b2c-essentials" }, { "direction": "any", - "service": "b2c-essentials" + "service": "b2c-professional" }, { "direction": "any", - "service": "free" + "service": "b2b-professional" } ], "availability": "available", @@ -6470,6 +7048,7 @@ ], "type": "paid" }, + "provider": "prvdr_61UVctyxfLOj4FpVw5Bmi", "provider_configuration_schema": { "additionalProperties": false, "properties": { @@ -6499,15 +7078,14 @@ ], "type": "object" }, - "provider_id": "prvdr_61UVctyxfLOj4FpVw5Bmi", "provider_name": "Auth0", "scope": "project", "service_id": "b2b-essentials", "updateable_to": [ - "b2b-professional", - "b2c-professional", - "b2c-essentials", "free", + "b2c-essentials", + "b2c-professional", + "b2b-professional", "b2b-essentials" ] }, @@ -6515,19 +7093,19 @@ "allowed_updates": [ { "direction": "any", - "service": "b2b-professional" + "service": "free" }, { "direction": "any", - "service": "b2b-essentials" + "service": "b2c-essentials" }, { "direction": "any", - "service": "b2c-essentials" + "service": "b2b-essentials" }, { "direction": "any", - "service": "free" + "service": "b2b-professional" } ], "availability": "available", @@ -6563,6 +7141,7 @@ ], "type": "paid" }, + "provider": "prvdr_61UVctyxfLOj4FpVw5Bmi", "provider_configuration_schema": { "additionalProperties": false, "properties": { @@ -6592,15 +7171,14 @@ ], "type": "object" }, - "provider_id": "prvdr_61UVctyxfLOj4FpVw5Bmi", "provider_name": "Auth0", "scope": "project", "service_id": "b2c-professional", "updateable_to": [ - "b2b-professional", - "b2b-essentials", - "b2c-essentials", "free", + "b2c-essentials", + "b2b-essentials", + "b2b-professional", "b2c-professional" ] }, @@ -6608,19 +7186,19 @@ "allowed_updates": [ { "direction": "any", - "service": "b2b-professional" + "service": "b2c-essentials" }, { "direction": "any", - "service": "b2c-professional" + "service": "b2b-essentials" }, { "direction": "any", - "service": "b2b-essentials" + "service": "b2c-professional" }, { "direction": "any", - "service": "b2c-essentials" + "service": "b2b-professional" } ], "availability": "available", @@ -6644,6 +7222,7 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UVctyxfLOj4FpVw5Bmi", "provider_configuration_schema": { "additionalProperties": false, "properties": { @@ -6673,15 +7252,14 @@ ], "type": "object" }, - "provider_id": "prvdr_61UVctyxfLOj4FpVw5Bmi", "provider_name": "Auth0", "scope": "project", "service_id": "free", "updateable_to": [ - "b2b-professional", - "b2c-professional", - "b2b-essentials", "b2c-essentials", + "b2b-essentials", + "b2c-professional", + "b2b-professional", "free" ] }, @@ -6689,19 +7267,19 @@ "allowed_updates": [ { "direction": "any", - "service": "b2b-professional" + "service": "free" }, { "direction": "any", - "service": "b2c-professional" + "service": "b2b-essentials" }, { "direction": "any", - "service": "b2b-essentials" + "service": "b2c-professional" }, { "direction": "any", - "service": "free" + "service": "b2b-professional" } ], "availability": "available", @@ -6737,6 +7315,7 @@ ], "type": "paid" }, + "provider": "prvdr_61UVctyxfLOj4FpVw5Bmi", "provider_configuration_schema": { "additionalProperties": false, "properties": { @@ -6766,15 +7345,14 @@ ], "type": "object" }, - "provider_id": "prvdr_61UVctyxfLOj4FpVw5Bmi", "provider_name": "Auth0", "scope": "project", "service_id": "b2c-essentials", "updateable_to": [ - "b2b-professional", - "b2c-professional", - "b2b-essentials", "free", + "b2b-essentials", + "b2c-professional", + "b2b-professional", "b2c-essentials" ] }, @@ -6915,8 +7493,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UVwArXdJpejOfkn5POi", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UVwArXdJpejOfkn5POi", "provider_name": "Render", "scope": "project", "service_id": "web-service", @@ -6960,6 +7538,7 @@ ], "type": "paid" }, + "provider": "prvdr_61UWLVjDZyzuP1BCY5EAi", "provider_configuration_schema": { "additionalProperties": false, "properties": { @@ -6973,7 +7552,6 @@ ], "type": "object" }, - "provider_id": "prvdr_61UWLVjDZyzuP1BCY5EAi", "provider_name": "Privy", "scope": "account", "service_id": "enterprise", @@ -7085,8 +7663,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UVa3kQyvSOEnWgd5Naa", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UVa3kQyvSOEnWgd5Naa", "provider_name": "Upstash", "scope": "project", "service_id": "vector", @@ -7171,8 +7749,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UVa3kQyvSOEnWgd5Naa", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UVa3kQyvSOEnWgd5Naa", "provider_name": "Upstash", "scope": "project", "service_id": "search", @@ -7252,8 +7830,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UVa3kQyvSOEnWgd5Naa", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UVa3kQyvSOEnWgd5Naa", "provider_name": "Upstash", "scope": "project", "service_id": "qstash", @@ -7376,8 +7954,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UVa3kQyvSOEnWgd5Naa", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UVa3kQyvSOEnWgd5Naa", "provider_name": "Upstash", "scope": "project", "service_id": "redis", @@ -7393,11 +7971,11 @@ }, { "direction": "any", - "service": "top-up-1000" + "service": "top-up-0025" }, { "direction": "any", - "service": "top-up-0025" + "service": "top-up-1000" } ], "availability": "available", @@ -7435,15 +8013,15 @@ ], "type": "paid" }, + "provider": "prvdr_61UZ9SrkCMLr94xp859Vo", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UZ9SrkCMLr94xp859Vo", "provider_name": "Daytona", "scope": "project", "service_id": "top-up-0500", "updateable_to": [ "top-up-2000", - "top-up-1000", "top-up-0025", + "top-up-1000", "top-up-0500" ] }, @@ -7451,7 +8029,7 @@ "allowed_updates": [ { "direction": "any", - "service": "top-up-0500" + "service": "top-up-2000" }, { "direction": "any", @@ -7459,7 +8037,7 @@ }, { "direction": "any", - "service": "top-up-2000" + "service": "top-up-0500" } ], "availability": "available", @@ -7497,15 +8075,15 @@ ], "type": "paid" }, + "provider": "prvdr_61UZ9SrkCMLr94xp859Vo", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UZ9SrkCMLr94xp859Vo", "provider_name": "Daytona", "scope": "project", "service_id": "top-up-1000", "updateable_to": [ - "top-up-0500", - "top-up-0025", "top-up-2000", + "top-up-0025", + "top-up-0500", "top-up-1000" ] }, @@ -7513,7 +8091,7 @@ "allowed_updates": [ { "direction": "any", - "service": "top-up-0500" + "service": "top-up-2000" }, { "direction": "any", @@ -7521,7 +8099,7 @@ }, { "direction": "any", - "service": "top-up-2000" + "service": "top-up-0500" } ], "availability": "available", @@ -7559,15 +8137,15 @@ ], "type": "paid" }, + "provider": "prvdr_61UZ9SrkCMLr94xp859Vo", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UZ9SrkCMLr94xp859Vo", "provider_name": "Daytona", "scope": "project", "service_id": "top-up-0025", "updateable_to": [ - "top-up-0500", - "top-up-1000", "top-up-2000", + "top-up-1000", + "top-up-0500", "top-up-0025" ] }, @@ -7575,15 +8153,15 @@ "allowed_updates": [ { "direction": "any", - "service": "top-up-0500" + "service": "top-up-1000" }, { "direction": "any", - "service": "top-up-1000" + "service": "top-up-0025" }, { "direction": "any", - "service": "top-up-0025" + "service": "top-up-0500" } ], "availability": "available", @@ -7621,15 +8199,15 @@ ], "type": "paid" }, + "provider": "prvdr_61UZ9SrkCMLr94xp859Vo", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UZ9SrkCMLr94xp859Vo", "provider_name": "Daytona", "scope": "project", "service_id": "top-up-2000", "updateable_to": [ - "top-up-0500", "top-up-1000", "top-up-0025", + "top-up-0500", "top-up-2000" ] }, @@ -7752,9 +8330,9 @@ }, "parent_services": [ "top-up-0025", - "top-up-0500", + "top-up-1000", "top-up-2000", - "top-up-1000" + "top-up-0500" ], "type": "paid" } @@ -7764,8 +8342,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UZ9SrkCMLr94xp859Vo", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UZ9SrkCMLr94xp859Vo", "provider_name": "Daytona", "scope": "project", "service_id": "sandbox", @@ -7819,8 +8397,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UIXYHdsyF69pZbG52n2", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UIXYHdsyF69pZbG52n2", "provider_name": "Supabase", "scope": "project", "service_id": "pro", @@ -7834,11 +8412,11 @@ "allowed_updates": [ { "direction": "any", - "service": "free" + "service": "pro" }, { "direction": "any", - "service": "pro" + "service": "free" } ], "availability": "available", @@ -7876,14 +8454,14 @@ ], "type": "paid" }, + "provider": "prvdr_61UIXYHdsyF69pZbG52n2", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UIXYHdsyF69pZbG52n2", "provider_name": "Supabase", "scope": "project", "service_id": "team", "updateable_to": [ - "free", "pro", + "free", "team" ] }, @@ -7930,8 +8508,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UWhMpOMGYc7qQhs53su", "provider_configuration_schema": null, - "provider_id": "prvdr_61UWhMpOMGYc7qQhs53su", "provider_name": "Sentry", "scope": "account", "service_id": "developer", @@ -7996,8 +8574,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UWhMpOMGYc7qQhs53su", "provider_configuration_schema": null, - "provider_id": "prvdr_61UWhMpOMGYc7qQhs53su", "provider_name": "Sentry", "scope": "account", "service_id": "business", @@ -8062,8 +8640,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UWhMpOMGYc7qQhs53su", "provider_configuration_schema": null, - "provider_id": "prvdr_61UWhMpOMGYc7qQhs53su", "provider_name": "Sentry", "scope": "account", "service_id": "team", @@ -8117,8 +8695,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UYA33tkF5l7Dkwz5KGG", "provider_configuration_schema": null, - "provider_id": "prvdr_61UYA33tkF5l7Dkwz5KGG", "provider_name": "Browserbase", "scope": "project", "service_id": "developer", @@ -8160,8 +8738,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UYA33tkF5l7Dkwz5KGG", "provider_configuration_schema": null, - "provider_id": "prvdr_61UYA33tkF5l7Dkwz5KGG", "provider_name": "Browserbase", "scope": "project", "service_id": "free", @@ -8215,8 +8793,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UYA33tkF5l7Dkwz5KGG", "provider_configuration_schema": null, - "provider_id": "prvdr_61UYA33tkF5l7Dkwz5KGG", "provider_name": "Browserbase", "scope": "project", "service_id": "startup", @@ -8317,8 +8895,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UVwArXdJpejOfkn5POi", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UVwArXdJpejOfkn5POi", "provider_name": "Render", "scope": "project", "service_id": "postgres", @@ -8334,11 +8912,11 @@ }, { "direction": "any", - "service": "free" + "service": "plus-v3-50k-mtu-monthly" }, { "direction": "any", - "service": "plus-v3-50k-mtu-monthly" + "service": "free" } ], "availability": "available", @@ -8376,6 +8954,7 @@ ], "type": "paid" }, + "provider": "prvdr_61UQYwVkrCANKYQdE5BLM", "provider_configuration_schema": { "properties": { "marketing": { @@ -8397,14 +8976,13 @@ ], "type": "object" }, - "provider_id": "prvdr_61UQYwVkrCANKYQdE5BLM", "provider_name": "Amplitude", "scope": "project", "service_id": "plus-v3-10k-mtu-monthly", "updateable_to": [ "plus-v3-25k-mtu-monthly", - "free", "plus-v3-50k-mtu-monthly", + "free", "plus-v3-10k-mtu-monthly" ] }, @@ -8412,15 +8990,15 @@ "allowed_updates": [ { "direction": "any", - "service": "plus-v3-10k-mtu-monthly" + "service": "plus-v3-50k-mtu-monthly" }, { "direction": "any", - "service": "free" + "service": "plus-v3-10k-mtu-monthly" }, { "direction": "any", - "service": "plus-v3-50k-mtu-monthly" + "service": "free" } ], "availability": "available", @@ -8458,6 +9036,7 @@ ], "type": "paid" }, + "provider": "prvdr_61UQYwVkrCANKYQdE5BLM", "provider_configuration_schema": { "properties": { "marketing": { @@ -8479,14 +9058,13 @@ ], "type": "object" }, - "provider_id": "prvdr_61UQYwVkrCANKYQdE5BLM", "provider_name": "Amplitude", "scope": "project", "service_id": "plus-v3-25k-mtu-monthly", "updateable_to": [ + "plus-v3-50k-mtu-monthly", "plus-v3-10k-mtu-monthly", "free", - "plus-v3-50k-mtu-monthly", "plus-v3-25k-mtu-monthly" ] }, @@ -8498,11 +9076,11 @@ }, { "direction": "any", - "service": "free" + "service": "plus-v3-10k-mtu-monthly" }, { "direction": "any", - "service": "plus-v3-10k-mtu-monthly" + "service": "free" } ], "availability": "available", @@ -8540,6 +9118,7 @@ ], "type": "paid" }, + "provider": "prvdr_61UQYwVkrCANKYQdE5BLM", "provider_configuration_schema": { "properties": { "marketing": { @@ -8561,14 +9140,13 @@ ], "type": "object" }, - "provider_id": "prvdr_61UQYwVkrCANKYQdE5BLM", "provider_name": "Amplitude", "scope": "project", "service_id": "plus-v3-50k-mtu-monthly", "updateable_to": [ "plus-v3-25k-mtu-monthly", - "free", "plus-v3-10k-mtu-monthly", + "free", "plus-v3-50k-mtu-monthly" ] }, @@ -8602,8 +9180,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UXju1taz9UCvkk95GEK", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UXju1taz9UCvkk95GEK", "provider_name": "Netlify", "scope": "project", "service_id": "project", @@ -8654,8 +9232,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UK2uWsoydL7tUBp57Fg", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UK2uWsoydL7tUBp57Fg", "provider_name": "Railway", "scope": "project", "service_id": "hobby", @@ -8702,8 +9280,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UK2uWsoydL7tUBp57Fg", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UK2uWsoydL7tUBp57Fg", "provider_name": "Railway", "scope": "project", "service_id": "pro", @@ -8747,10 +9325,10 @@ "is_default": null, "paid": null, "parent_services": [ - "core", - "enterprise", + "free", "scale", - "free" + "enterprise", + "core" ], "type": "free" } @@ -8760,6 +9338,7 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UWLVjDZyzuP1BCY5EAi", "provider_configuration_schema": { "additionalProperties": false, "properties": { @@ -8773,7 +9352,6 @@ ], "type": "object" }, - "provider_id": "prvdr_61UWLVjDZyzuP1BCY5EAi", "provider_name": "Privy", "scope": "project", "service_id": "app", @@ -8827,8 +9405,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UWNSVKoGlVDwbHX5IUK", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UWNSVKoGlVDwbHX5IUK", "provider_name": "AgentMail", "scope": "project", "service_id": "developer", @@ -8842,11 +9420,11 @@ "allowed_updates": [ { "direction": "any", - "service": "developer" + "service": "free" }, { "direction": "any", - "service": "free" + "service": "developer" } ], "availability": "available", @@ -8884,14 +9462,14 @@ ], "type": "paid" }, + "provider": "prvdr_61UWNSVKoGlVDwbHX5IUK", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UWNSVKoGlVDwbHX5IUK", "provider_name": "AgentMail", "scope": "project", "service_id": "startup", "updateable_to": [ - "developer", "free", + "developer", "startup" ] }, @@ -8899,11 +9477,11 @@ "allowed_updates": [ { "direction": "any", - "service": "developer" + "service": "startup" }, { "direction": "any", - "service": "startup" + "service": "developer" } ], "availability": "available", @@ -8929,14 +9507,14 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UWNSVKoGlVDwbHX5IUK", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UWNSVKoGlVDwbHX5IUK", "provider_name": "AgentMail", "scope": "project", "service_id": "free", "updateable_to": [ - "developer", "startup", + "developer", "free" ] }, @@ -8995,8 +9573,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UVwArXdJpejOfkn5POi", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UVwArXdJpejOfkn5POi", "provider_name": "Render", "scope": "project", "service_id": "static-site", @@ -9061,8 +9639,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UWhMpOMGYc7qQhs53su", "provider_configuration_schema": null, - "provider_id": "prvdr_61UWhMpOMGYc7qQhs53su", "provider_name": "Sentry", "scope": "account", "service_id": "seer", @@ -9130,8 +9708,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UWhMpOMGYc7qQhs53su", "provider_configuration_schema": null, - "provider_id": "prvdr_61UWhMpOMGYc7qQhs53su", "provider_name": "Sentry", "scope": "project", "service_id": "project", @@ -9183,8 +9761,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UH8uNXFdoJUJOtT54AC", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UH8uNXFdoJUJOtT54AC", "provider_name": "Neon", "scope": "project", "service_id": "launch", @@ -9225,8 +9803,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UH8uNXFdoJUJOtT54AC", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UH8uNXFdoJUJOtT54AC", "provider_name": "Neon", "scope": "project", "service_id": "free", @@ -9276,8 +9854,8 @@ "is_default": null, "paid": null, "parent_services": [ - "hobby", - "pro" + "pro", + "hobby" ], "type": "free" } @@ -9287,8 +9865,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UQ7Ta2evjv111Sl5Tqa", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQ7Ta2evjv111Sl5Tqa", "provider_name": "Inngest", "scope": "project", "service_id": "app", @@ -9300,11 +9878,11 @@ "allowed_updates": [ { "direction": "any", - "service": "hobby" + "service": "pro" }, { "direction": "any", - "service": "pro" + "service": "hobby" } ], "availability": "available", @@ -9328,25 +9906,25 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UQ7Ta2evjv111Sl5Tqa", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQ7Ta2evjv111Sl5Tqa", "provider_name": "Inngest", "scope": "project", "service_id": "hobby", "updateable_to": [ - "hobby", - "pro" + "pro", + "hobby" ] }, { "allowed_updates": [ { "direction": "any", - "service": "team" + "service": "pro" }, { "direction": "any", - "service": "pro" + "service": "team" } ], "availability": "available", @@ -9372,14 +9950,14 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UIXYHdsyF69pZbG52n2", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UIXYHdsyF69pZbG52n2", "provider_name": "Supabase", "scope": "project", "service_id": "free", "updateable_to": [ - "team", "pro", + "team", "free" ] }, @@ -9440,8 +10018,8 @@ "type": "freeform" }, "parent_services": [ - "pro", - "team" + "team", + "pro" ], "type": "paid" } @@ -9451,8 +10029,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UIXYHdsyF69pZbG52n2", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UIXYHdsyF69pZbG52n2", "provider_name": "Supabase", "scope": "project", "service_id": "project", @@ -9464,11 +10042,11 @@ "allowed_updates": [ { "direction": "any", - "service": "workers:paid" + "service": "workers:free" }, { "direction": "any", - "service": "workers:free" + "service": "workers:paid" } ], "availability": "available", @@ -9515,14 +10093,14 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_name": "Cloudflare", "scope": "project", "service_id": "workers-ai", "updateable_to": [ - "workers:paid", "workers:free", + "workers:paid", "workers-ai" ] }, @@ -9530,11 +10108,11 @@ "allowed_updates": [ { "direction": "any", - "service": "workers:paid" + "service": "workers:free" }, { "direction": "any", - "service": "workers:free" + "service": "workers:paid" } ], "availability": "available", @@ -9585,14 +10163,14 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_name": "Cloudflare", "scope": "project", "service_id": "browser-run", "updateable_to": [ - "workers:paid", "workers:free", + "workers:paid", "browser-run" ] }, @@ -9600,11 +10178,11 @@ "allowed_updates": [ { "direction": "any", - "service": "workers:paid" + "service": "workers:free" }, { "direction": "any", - "service": "workers:free" + "service": "workers:paid" } ], "availability": "available", @@ -9740,14 +10318,14 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_name": "Cloudflare", "scope": "project", "service_id": "hyperdrive", "updateable_to": [ - "workers:paid", "workers:free", + "workers:paid", "hyperdrive" ] }, @@ -9755,11 +10333,11 @@ "allowed_updates": [ { "direction": "any", - "service": "workers:paid" + "service": "workers:free" }, { "direction": "any", - "service": "workers:free" + "service": "workers:paid" } ], "availability": "available", @@ -9819,14 +10397,14 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_name": "Cloudflare", "scope": "project", "service_id": "kv", "updateable_to": [ - "workers:paid", "workers:free", + "workers:paid", "kv" ] }, @@ -9834,11 +10412,11 @@ "allowed_updates": [ { "direction": "any", - "service": "workers:paid" + "service": "workers:free" }, { "direction": "any", - "service": "workers:free" + "service": "workers:paid" } ], "availability": "available", @@ -9910,14 +10488,14 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_name": "Cloudflare", "scope": "project", "service_id": "d1", "updateable_to": [ - "workers:paid", "workers:free", + "workers:paid", "d1" ] }, @@ -9925,11 +10503,11 @@ "allowed_updates": [ { "direction": "any", - "service": "workers:paid" + "service": "workers:free" }, { "direction": "any", - "service": "workers:free" + "service": "workers:paid" } ], "availability": "available", @@ -9989,14 +10567,14 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_name": "Cloudflare", "scope": "project", "service_id": "queues", "updateable_to": [ - "workers:paid", "workers:free", + "workers:paid", "queues" ] }, @@ -10004,11 +10582,11 @@ "allowed_updates": [ { "direction": "any", - "service": "workers:paid" + "service": "workers:free" }, { "direction": "any", - "service": "workers:free" + "service": "workers:paid" } ], "availability": "available", @@ -10051,14 +10629,14 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_name": "Cloudflare", "scope": "project", "service_id": "containers", "updateable_to": [ - "workers:paid", "workers:free", + "workers:paid", "containers" ] }, @@ -10097,11 +10675,11 @@ "is_default": null, "paid": null, "parent_services": [ - "b2c-professional", - "free", - "b2c-essentials", + "b2b-professional", "b2b-essentials", - "b2b-professional" + "b2c-essentials", + "free", + "b2c-professional" ], "type": "free" } @@ -10111,6 +10689,7 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UVctyxfLOj4FpVw5Bmi", "provider_configuration_schema": { "additionalProperties": false, "properties": { @@ -10140,7 +10719,6 @@ ], "type": "object" }, - "provider_id": "prvdr_61UVctyxfLOj4FpVw5Bmi", "provider_name": "Auth0", "scope": "project", "service_id": "client", @@ -10190,8 +10768,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61URImmFACEuDHEx651IO", "provider_configuration_schema": {}, - "provider_id": "prvdr_61URImmFACEuDHEx651IO", "provider_name": "OpenRouter", "scope": "project", "service_id": "api", @@ -10234,8 +10812,8 @@ ], "type": "paid" }, + "provider": "prvdr_61URImmFACEuDHEx651IO", "provider_configuration_schema": {}, - "provider_id": "prvdr_61URImmFACEuDHEx651IO", "provider_name": "OpenRouter", "scope": "project", "service_id": "pay_as_you_go", @@ -10299,8 +10877,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UVpYy9KwOpOlUVw5WD2", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UVpYy9KwOpOlUVw5WD2", "provider_name": "WorkOS", "scope": "project", "service_id": "auth", @@ -10312,11 +10890,11 @@ "allowed_updates": [ { "direction": "any", - "service": "standard" + "service": "free" }, { "direction": "any", - "service": "free" + "service": "standard" }, { "direction": "any", @@ -10387,14 +10965,14 @@ ], "type": "paid" }, + "provider": "prvdr_61URa0AjsVCYCdagK5Xqy", "provider_configuration_schema": {}, - "provider_id": "prvdr_61URa0AjsVCYCdagK5Xqy", "provider_name": "Firecrawl", "scope": "project", "service_id": "growth", "updateable_to": [ - "standard", "free", + "standard", "hobby", "api", "growth" @@ -10404,19 +10982,19 @@ "allowed_updates": [ { "direction": "any", - "service": "standard" + "service": "free" }, { "direction": "any", - "service": "free" + "service": "standard" }, { "direction": "any", - "service": "api" + "service": "growth" }, { "direction": "any", - "service": "growth" + "service": "api" } ], "availability": "available", @@ -10479,16 +11057,16 @@ ], "type": "paid" }, + "provider": "prvdr_61URa0AjsVCYCdagK5Xqy", "provider_configuration_schema": {}, - "provider_id": "prvdr_61URa0AjsVCYCdagK5Xqy", "provider_name": "Firecrawl", "scope": "project", "service_id": "hobby", "updateable_to": [ - "standard", "free", - "api", + "standard", "growth", + "api", "hobby" ] }, @@ -10500,15 +11078,15 @@ }, { "direction": "any", - "service": "hobby" + "service": "growth" }, { "direction": "any", - "service": "api" + "service": "hobby" }, { "direction": "any", - "service": "growth" + "service": "api" } ], "availability": "available", @@ -10571,16 +11149,16 @@ ], "type": "paid" }, + "provider": "prvdr_61URa0AjsVCYCdagK5Xqy", "provider_configuration_schema": {}, - "provider_id": "prvdr_61URa0AjsVCYCdagK5Xqy", "provider_name": "Firecrawl", "scope": "project", "service_id": "standard", "updateable_to": [ "free", + "growth", "hobby", "api", - "growth", "standard" ] }, @@ -10612,8 +11190,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61URImmFACEuDHEx651IO", "provider_configuration_schema": {}, - "provider_id": "prvdr_61URImmFACEuDHEx651IO", "provider_name": "OpenRouter", "scope": "project", "service_id": "free", @@ -10626,19 +11204,19 @@ "allowed_updates": [ { "direction": "any", - "service": "standard" + "service": "free" }, { "direction": "any", - "service": "free" + "service": "standard" }, { "direction": "any", - "service": "hobby" + "service": "growth" }, { "direction": "any", - "service": "growth" + "service": "hobby" } ], "availability": "available", @@ -10679,8 +11257,8 @@ "type": "freeform" }, "parent_services": [ - "standard", "growth", + "standard", "hobby" ], "type": "paid" @@ -10691,16 +11269,16 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61URa0AjsVCYCdagK5Xqy", "provider_configuration_schema": {}, - "provider_id": "prvdr_61URa0AjsVCYCdagK5Xqy", "provider_name": "Firecrawl", "scope": "project", "service_id": "api", "updateable_to": [ - "standard", "free", - "hobby", + "standard", "growth", + "hobby", "api" ] }, @@ -10712,15 +11290,15 @@ }, { "direction": "any", - "service": "hobby" + "service": "growth" }, { "direction": "any", - "service": "api" + "service": "hobby" }, { "direction": "any", - "service": "growth" + "service": "api" } ], "availability": "available", @@ -10748,16 +11326,16 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61URa0AjsVCYCdagK5Xqy", "provider_configuration_schema": {}, - "provider_id": "prvdr_61URa0AjsVCYCdagK5Xqy", "provider_name": "Firecrawl", "scope": "project", "service_id": "free", "updateable_to": [ "standard", + "growth", "hobby", "api", - "growth", "free" ] }, @@ -10793,8 +11371,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_name": "Cloudflare", "scope": "project", "service_id": "workers:free", @@ -10852,8 +11430,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UU5TYtG0f1neJCz5EwK", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UU5TYtG0f1neJCz5EwK", "provider_name": "GitLab", "scope": "project", "service_id": "project", @@ -10865,11 +11443,11 @@ "allowed_updates": [ { "direction": "any", - "service": "hobby" + "service": "pro" }, { "direction": "any", - "service": "pro" + "service": "hobby" } ], "availability": "available", @@ -10893,25 +11471,25 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61ULUAr4zlQgZkvXY5LsG", "provider_configuration_schema": {}, - "provider_id": "prvdr_61ULUAr4zlQgZkvXY5LsG", "provider_name": "Vercel", "scope": "project", "service_id": "hobby", "updateable_to": [ - "hobby", - "pro" + "pro", + "hobby" ] }, { "allowed_updates": [ { "direction": "any", - "service": "hobby" + "service": "pro" }, { "direction": "any", - "service": "pro" + "service": "hobby" } ], "availability": "available", @@ -10947,14 +11525,14 @@ ], "type": "paid" }, + "provider": "prvdr_61ULUAr4zlQgZkvXY5LsG", "provider_configuration_schema": {}, - "provider_id": "prvdr_61ULUAr4zlQgZkvXY5LsG", "provider_name": "Vercel", "scope": "project", "service_id": "pro", "updateable_to": [ - "hobby", - "pro" + "pro", + "hobby" ] }, { @@ -11003,8 +11581,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UTLwCr8KIRpEaZS54mu", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UTLwCr8KIRpEaZS54mu", "provider_name": "Mixpanel", "scope": "project", "service_id": "analytics", @@ -11016,19 +11594,19 @@ "allowed_updates": [ { "direction": "any", - "service": "free" + "service": "plus-v3-25k-mtu-monthly" }, { "direction": "any", - "service": "plus-v3-50k-mtu-monthly" + "service": "plus-v3-10k-mtu-monthly" }, { "direction": "any", - "service": "plus-v3-25k-mtu-monthly" + "service": "plus-v3-50k-mtu-monthly" }, { "direction": "any", - "service": "plus-v3-10k-mtu-monthly" + "service": "free" } ], "availability": "available", @@ -11101,6 +11679,7 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UQYwVkrCANKYQdE5BLM", "provider_configuration_schema": { "properties": { "marketing": { @@ -11122,15 +11701,14 @@ ], "type": "object" }, - "provider_id": "prvdr_61UQYwVkrCANKYQdE5BLM", "provider_name": "Amplitude", "scope": "project", "service_id": "analytics", "updateable_to": [ - "free", - "plus-v3-50k-mtu-monthly", "plus-v3-25k-mtu-monthly", "plus-v3-10k-mtu-monthly", + "plus-v3-50k-mtu-monthly", + "free", "analytics" ] }, @@ -11172,6 +11750,7 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UQYwVkrCANKYQdE5BLM", "provider_configuration_schema": { "properties": { "marketing": { @@ -11193,7 +11772,6 @@ ], "type": "object" }, - "provider_id": "prvdr_61UQYwVkrCANKYQdE5BLM", "provider_name": "Amplitude", "scope": "project", "service_id": "free", @@ -11247,6 +11825,7 @@ ], "type": "paid" }, + "provider": "prvdr_61UGMHNyOleb3A55m5Pg8", "provider_configuration_schema": { "additionalProperties": false, "properties": { @@ -11268,7 +11847,6 @@ ], "type": "object" }, - "provider_id": "prvdr_61UGMHNyOleb3A55m5Pg8", "provider_name": "PostHog", "scope": "project", "service_id": "pay_as_you_go", @@ -11308,6 +11886,7 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UGMHNyOleb3A55m5Pg8", "provider_configuration_schema": { "additionalProperties": false, "properties": { @@ -11329,7 +11908,6 @@ ], "type": "object" }, - "provider_id": "prvdr_61UGMHNyOleb3A55m5Pg8", "provider_name": "PostHog", "scope": "project", "service_id": "free", @@ -11382,8 +11960,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_name": "Cloudflare", "scope": "project", "service_id": "registrar:domain", @@ -11431,8 +12009,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UTLwCr8KIRpEaZS54mu", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UTLwCr8KIRpEaZS54mu", "provider_name": "Mixpanel", "scope": "account", "service_id": "growth", @@ -11469,8 +12047,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UTLwCr8KIRpEaZS54mu", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UTLwCr8KIRpEaZS54mu", "provider_name": "Mixpanel", "scope": "account", "service_id": "free", @@ -11523,8 +12101,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_name": "Cloudflare", "scope": "project", "service_id": "workers:paid", @@ -11651,8 +12229,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UQUoA4NItxbLNIU5FF2", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQUoA4NItxbLNIU5FF2", "provider_name": "Flyio", "scope": "project", "service_id": "mpg", @@ -11695,8 +12273,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UGOeSW4e0T9Etwn537w", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UGOeSW4e0T9Etwn537w", "provider_name": "Clerk", "scope": "project", "service_id": "pro", @@ -11758,8 +12336,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UQUoA4NItxbLNIU5FF2", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQUoA4NItxbLNIU5FF2", "provider_name": "Flyio", "scope": "project", "service_id": "sprite", @@ -11802,10 +12380,10 @@ "type": "freeform" }, "parent_services": [ - "62.5K_emails+auto-replenish", - "business", + "25K_emails+auto-replenish", "hobbyist", - "25K_emails+auto-replenish" + "business", + "62.5K_emails+auto-replenish" ], "type": "paid" } @@ -11815,8 +12393,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UQsPLOiNuyFxFP45ADo", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQsPLOiNuyFxFP45ADo", "provider_name": "Twilio", "scope": "project", "service_id": "email", @@ -11870,8 +12448,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UQUoA4NItxbLNIU5FF2", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQUoA4NItxbLNIU5FF2", "provider_name": "Flyio", "scope": "project", "service_id": "app", @@ -11883,11 +12461,11 @@ "allowed_updates": [ { "direction": "any", - "service": "hobby" + "service": "pro" }, { "direction": "any", - "service": "pro" + "service": "hobby" } ], "availability": "available", @@ -11923,25 +12501,25 @@ ], "type": "paid" }, + "provider": "prvdr_61UQ7Ta2evjv111Sl5Tqa", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQ7Ta2evjv111Sl5Tqa", "provider_name": "Inngest", "scope": "project", "service_id": "pro", "updateable_to": [ - "hobby", - "pro" + "pro", + "hobby" ] }, { "allowed_updates": [ { "direction": "any", - "service": "workers:paid" + "service": "workers:free" }, { "direction": "any", - "service": "workers:free" + "service": "workers:paid" } ], "availability": "available", @@ -11992,14 +12570,14 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UQRSWMdrciFdBNs5Ipc", "provider_name": "Cloudflare", "scope": "project", "service_id": "workers", "updateable_to": [ - "workers:paid", "workers:free", + "workers:paid", "workers" ] }, @@ -12055,8 +12633,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UH8uNXFdoJUJOtT54AC", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UH8uNXFdoJUJOtT54AC", "provider_name": "Neon", "scope": "project", "service_id": "postgres", @@ -12104,8 +12682,8 @@ "is_default": null, "paid": null, "parent_services": [ - "hobby", - "pro" + "pro", + "hobby" ], "type": "free" } @@ -12115,8 +12693,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61ULUAr4zlQgZkvXY5LsG", "provider_configuration_schema": {}, - "provider_id": "prvdr_61ULUAr4zlQgZkvXY5LsG", "provider_name": "Vercel", "scope": "project", "service_id": "project", @@ -12175,8 +12753,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UGhvzdmhefqNXre5WIS", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UGhvzdmhefqNXre5WIS", "provider_name": "Runloop", "scope": "account", "service_id": "sandbox", @@ -12238,6 +12816,7 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UGMHNyOleb3A55m5Pg8", "provider_configuration_schema": { "additionalProperties": false, "properties": { @@ -12259,7 +12838,6 @@ ], "type": "object" }, - "provider_id": "prvdr_61UGMHNyOleb3A55m5Pg8", "provider_name": "PostHog", "scope": "project", "service_id": "analytics", @@ -12332,8 +12910,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UGOeSW4e0T9Etwn537w", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UGOeSW4e0T9Etwn537w", "provider_name": "Clerk", "scope": "project", "service_id": "auth", @@ -12369,8 +12947,8 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UGOeSW4e0T9Etwn537w", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UGOeSW4e0T9Etwn537w", "provider_name": "Clerk", "scope": "project", "service_id": "hobby", @@ -13601,8 +14179,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UGL5sd8z0WkMArr5Jlo", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UGL5sd8z0WkMArr5Jlo", "provider_name": "PlanetScale", "scope": "project", "service_id": "mysql", @@ -15030,8 +15608,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UGL5sd8z0WkMArr5Jlo", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UGL5sd8z0WkMArr5Jlo", "provider_name": "PlanetScale", "scope": "project", "service_id": "postgresql", @@ -15087,8 +15665,8 @@ "type": "freeform" }, "parent_services": [ - "hobby", - "pro" + "pro", + "hobby" ], "type": "paid" } @@ -15098,8 +15676,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UK2uWsoydL7tUBp57Fg", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UK2uWsoydL7tUBp57Fg", "provider_name": "Railway", "scope": "project", "service_id": "bucket", @@ -15152,8 +15730,8 @@ "type": "freeform" }, "parent_services": [ - "hobby", - "pro" + "pro", + "hobby" ], "type": "paid" } @@ -15163,8 +15741,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UK2uWsoydL7tUBp57Fg", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UK2uWsoydL7tUBp57Fg", "provider_name": "Railway", "scope": "project", "service_id": "redis", @@ -15176,11 +15754,11 @@ "allowed_updates": [ { "direction": "any", - "service": "hobby" + "service": "pro" }, { "direction": "any", - "service": "pro" + "service": "hobby" } ], "availability": "available", @@ -15207,14 +15785,14 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UK2uWsoydL7tUBp57Fg", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UK2uWsoydL7tUBp57Fg", "provider_name": "Railway", "scope": "project", "service_id": "free", "updateable_to": [ - "hobby", "pro", + "hobby", "free" ] }, @@ -15262,8 +15840,8 @@ "type": "freeform" }, "parent_services": [ - "hobby", - "pro" + "pro", + "hobby" ], "type": "paid" } @@ -15273,8 +15851,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UK2uWsoydL7tUBp57Fg", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UK2uWsoydL7tUBp57Fg", "provider_name": "Railway", "scope": "project", "service_id": "postgres", @@ -15321,8 +15899,8 @@ "type": "freeform" }, "parent_services": [ - "hobby", - "pro" + "pro", + "hobby" ], "type": "paid" } @@ -15332,8 +15910,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UK2uWsoydL7tUBp57Fg", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UK2uWsoydL7tUBp57Fg", "provider_name": "Railway", "scope": "project", "service_id": "hosting", @@ -15385,8 +15963,8 @@ "type": "freeform" }, "parent_services": [ - "hobby", - "pro" + "pro", + "hobby" ], "type": "paid" } @@ -15396,8 +15974,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UK2uWsoydL7tUBp57Fg", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UK2uWsoydL7tUBp57Fg", "provider_name": "Railway", "scope": "project", "service_id": "mongo", @@ -15446,8 +16024,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UGhvzdmhefqNXre5WIS", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UGhvzdmhefqNXre5WIS", "provider_name": "Runloop", "scope": "account", "service_id": "pro", @@ -15497,8 +16075,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UGhvzdmhefqNXre5WIS", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UGhvzdmhefqNXre5WIS", "provider_name": "Runloop", "scope": "account", "service_id": "basic", @@ -15555,8 +16133,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UIblE5uGbHmAZLq5BgG", "provider_configuration_schema": null, - "provider_id": "prvdr_61UIblE5uGbHmAZLq5BgG", "provider_name": "Chroma", "scope": "project", "service_id": "database", @@ -15566,17 +16144,13 @@ }, { "allowed_updates": [ - { - "direction": "any", - "service": "scaler" - }, { "direction": "any", "service": "scaler_overages" }, { "direction": "any", - "service": "pro" + "service": "scaler" }, { "direction": "any", @@ -15585,6 +16159,10 @@ { "direction": "any", "service": "pro_overages" + }, + { + "direction": "any", + "service": "pro" } ], "availability": "available", @@ -15593,15 +16171,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -15631,17 +16209,17 @@ ], "type": "paid" }, + "provider": "prvdr_61UGLtrGjcXK8rTq15RWq", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UGLtrGjcXK8rTq15RWq", "provider_name": "Turso", "scope": "account", "service_id": "developer", "updateable_to": [ - "scaler", "scaler_overages", - "pro", + "scaler", "developer_overages", "pro_overages", + "pro", "developer" ] }, @@ -15649,11 +16227,11 @@ "allowed_updates": [ { "direction": "any", - "service": "pro_overages" + "service": "pro" }, { "direction": "any", - "service": "pro" + "service": "pro_overages" } ], "availability": "available", @@ -15662,15 +16240,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -15700,14 +16278,14 @@ ], "type": "paid" }, + "provider": "prvdr_61UGLtrGjcXK8rTq15RWq", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UGLtrGjcXK8rTq15RWq", "provider_name": "Turso", "scope": "account", "service_id": "scaler_overages", "updateable_to": [ - "pro_overages", "pro", + "pro_overages", "scaler_overages" ] }, @@ -15724,15 +16302,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -15762,8 +16340,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UGLtrGjcXK8rTq15RWq", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UGLtrGjcXK8rTq15RWq", "provider_name": "Turso", "scope": "account", "service_id": "pro", @@ -15776,7 +16354,7 @@ "allowed_updates": [ { "direction": "any", - "service": "pro" + "service": "scaler_overages" }, { "direction": "any", @@ -15784,7 +16362,7 @@ }, { "direction": "any", - "service": "scaler_overages" + "service": "pro" } ], "availability": "available", @@ -15793,15 +16371,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -15831,15 +16409,15 @@ ], "type": "paid" }, + "provider": "prvdr_61UGLtrGjcXK8rTq15RWq", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UGLtrGjcXK8rTq15RWq", "provider_name": "Turso", "scope": "account", "service_id": "scaler", "updateable_to": [ - "pro", - "pro_overages", "scaler_overages", + "pro_overages", + "pro", "scaler" ] }, @@ -15891,12 +16469,12 @@ "is_default": null, "paid": null, "parent_services": [ - "scaler", - "starter", - "developer_overages", - "developer", - "pro", "scaler_overages", + "pro", + "developer", + "developer_overages", + "starter", + "scaler", "pro_overages" ], "type": "free" @@ -15907,8 +16485,8 @@ "paid_pricing": [], "type": "component" }, + "provider": "prvdr_61UGLtrGjcXK8rTq15RWq", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UGLtrGjcXK8rTq15RWq", "provider_name": "Turso", "scope": "project", "service_id": "database", @@ -15924,7 +16502,7 @@ }, { "direction": "any", - "service": "pro_overages" + "service": "scaler_overages" }, { "direction": "any", @@ -15932,7 +16510,7 @@ }, { "direction": "any", - "service": "scaler_overages" + "service": "pro_overages" } ], "availability": "available", @@ -15941,15 +16519,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -15979,16 +16557,16 @@ ], "type": "paid" }, + "provider": "prvdr_61UGLtrGjcXK8rTq15RWq", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UGLtrGjcXK8rTq15RWq", "provider_name": "Turso", "scope": "account", "service_id": "developer_overages", "updateable_to": [ "pro", - "pro_overages", - "scaler", "scaler_overages", + "scaler", + "pro_overages", "developer_overages" ] }, @@ -16000,15 +16578,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -16038,8 +16616,8 @@ ], "type": "paid" }, + "provider": "prvdr_61UGLtrGjcXK8rTq15RWq", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UGLtrGjcXK8rTq15RWq", "provider_name": "Turso", "scope": "account", "service_id": "pro_overages", @@ -16055,7 +16633,7 @@ }, { "direction": "any", - "service": "scaler" + "service": "pro" }, { "direction": "any", @@ -16063,15 +16641,15 @@ }, { "direction": "any", - "service": "pro_overages" + "service": "scaler_overages" }, { "direction": "any", - "service": "scaler_overages" + "service": "scaler" }, { "direction": "any", - "service": "pro" + "service": "pro_overages" } ], "availability": "available", @@ -16080,15 +16658,15 @@ ], "configuration_schema": {}, "constraints": [ - { - "mutual_exclusion_allowed_updates": true, - "type": "mutual_exclusion_allowed_updates" - }, { "count": { "at_most": 1 }, "type": "count" + }, + { + "mutual_exclusion_allowed_updates": true, + "type": "mutual_exclusion_allowed_updates" } ], "created": null, @@ -16106,18 +16684,18 @@ "paid_pricing": [], "type": "free" }, + "provider": "prvdr_61UGLtrGjcXK8rTq15RWq", "provider_configuration_schema": {}, - "provider_id": "prvdr_61UGLtrGjcXK8rTq15RWq", "provider_name": "Turso", "scope": "account", "service_id": "starter", "updateable_to": [ "developer_overages", - "scaler", + "pro", "developer", - "pro_overages", "scaler_overages", - "pro", + "scaler", + "pro_overages", "starter" ] } diff --git a/crates/stackless-stripe-projects/tests/fixtures/command-surface.txt b/crates/stackless-stripe-projects/tests/fixtures/command-surface.txt index 6f99b8b..d891b36 100644 --- a/crates/stackless-stripe-projects/tests/fixtures/command-surface.txt +++ b/crates/stackless-stripe-projects/tests/fixtures/command-surface.txt @@ -1,9 +1,9 @@ # stripe projects command surface -# plugin-version: 0.39.1 +# plugin-version: 0.45.0 # DO NOT EDIT — regenerated by CI (mise run stripe-refresh) ===== stripe projects --help ===== -Stripe Projects (v0.39.1) +Stripe Projects (v0.45.0) Provision third-party services, manage credentials, and pull environment variables. GET STARTED @@ -115,6 +115,8 @@ Options: CLAUDE.md) [boolean] --template Template entry ID or template slug to use directly and skip interactive template selection [string] + --testmode Create provisioned Resources in Stripe test mode + [boolean] --mode Initialization mode: `manual` scaffolds a workspace, `guided` creates a starter app, and `template` browses templates directly. @@ -127,10 +129,14 @@ Options: --preflight Check all preconditions (auth, eligibility, confirmation) without executing. Reports all blockers at once. [boolean] + --account Live-mode account to use, when the signed-in + session is authorized for more than one [string] Examples: stripe projects init Initialize a project workspace in the current directory + stripe projects init --account acct_123 Initialize using a specific + authorized account stripe projects init --mode guided Create a starter app with guided setup stripe projects init --mode template Browse starter templates directly @@ -418,6 +424,8 @@ Options: --stream Enable streaming output animations [boolean] --debug Enable debug logging for Stripe API requests [boolean] + --testmode Create provisioned Resources in Stripe test mode + [boolean] --name Logical resource name used for local resource references and environment variable prefixes [string] diff --git a/crates/stackless-stripe-projects/tests/fixtures/plugin-version.txt b/crates/stackless-stripe-projects/tests/fixtures/plugin-version.txt index d2e2400..bcce5d0 100644 --- a/crates/stackless-stripe-projects/tests/fixtures/plugin-version.txt +++ b/crates/stackless-stripe-projects/tests/fixtures/plugin-version.txt @@ -1 +1 @@ -0.39.1 +0.45.0 diff --git a/crates/stackless/src/authoring.rs b/crates/stackless/src/authoring.rs index 090fdf1..14b3936 100644 --- a/crates/stackless/src/authoring.rs +++ b/crates/stackless/src/authoring.rs @@ -8,7 +8,7 @@ use stackless_core::types::DnsName; use crate::error::Error; /// The Stripe Projects plugin version stackless is tested against. -pub const STRIPE_PROJECTS_PINNED: &str = "0.39.1"; +pub const STRIPE_PROJECTS_PINNED: &str = "0.45.0"; pub fn default_output_path() -> PathBuf { PathBuf::from("stackless.toml") diff --git a/docs/ADDING-A-PROVIDER.md b/docs/ADDING-A-PROVIDER.md index 62e00a5..42f07b0 100644 --- a/docs/ADDING-A-PROVIDER.md +++ b/docs/ADDING-A-PROVIDER.md @@ -186,8 +186,10 @@ fixture dir (see "One-time setup" above) — the smoke fails at the first `mise run catalog-orphans` (also part of `mise run check`) fails on new unowned deployables. Current exclusions: - `cloudflare/containers` — `PRICE_CONFIRMATION_REQUIRED` / unknown cost - - `cloudflare/registrar:domain`, `squarespace/domain`, `wordpress.com/domain`, - `spaceship/domain` — non-refundable domain purchases + - `cloudflare/registrar:domain`, `squarespace/domain`, `squarespace/website`, + `wordpress.com/domain`, `spaceship/domain` — non-refundable domain purchases. + `squarespace/website` is the subscription, and its provision still pauses to + buy a domain (`needs_information`), which this lifecycle does not handle - `createos/project` — catalog orphan; no stackless surface (do not register) - External pin blockers below (unregistered so users cannot select them) diff --git a/scripts/generate_catalog_integrations.py b/scripts/generate_catalog_integrations.py index 0f6e362..2e6b2e5 100644 --- a/scripts/generate_catalog_integrations.py +++ b/scripts/generate_catalog_integrations.py @@ -29,6 +29,10 @@ "squarespace/domain": ( "Non-refundable domain purchase; never in the leased lifecycle" ), + "squarespace/website": ( + "Provision pauses on needs_information to buy a domain; " + "non-refundable domain purchases stay out of the leased lifecycle" + ), "wordpress.com/domain": ( "Non-refundable domain purchase; never in the leased lifecycle" ), @@ -90,6 +94,9 @@ "turso/database": "turso", "prisma/database": "prisma", "chroma/database": "chroma", + "chatbase/agent": "chatbase", + "churnkey/retention": "churnkey", + "athena/agents": "athena", "algolia/application": "algolia", "openrouter/api": "openrouter", "exa/api": "exa", @@ -121,6 +128,8 @@ "sentry/project": "sentry", "sentry/seer": "sentry-seer", "render/postgres": "render-postgres", + "resend/email": "resend", + "quo/app": "quo-app", "railway/hosting": "railway-hosting", "railway/postgres": "railway-postgres", "railway/redis": "railway-redis", @@ -188,6 +197,22 @@ "clickhouse/clickhouse": [("CONNECTION_STRING", "connection_string", True)], "clickhouse/postgres": [("CONNECTION_STRING", "connection_string", True)], "chroma/database": [("API_KEY", "api_key", True)], + "athena/agents": [ + ("AGENT_ID", "agent_id", True), + ("API_KEY", "api_key", True), + ("API_URL", "api_url", True), + ], + "chatbase/agent": [ + ("CHATBASE_AGENT_ID", "chatbase_agent_id", True), + ("CHATBASE_API_KEY", "chatbase_api_key", True), + ("CHATBASE_API_URL", "chatbase_api_url", True), + ], + "churnkey/retention": [ + ("APP_ID", "app_id", True), + ("API_KEY", "api_key", True), + ("DATA_API_KEY", "data_api_key", True), + ("MODE", "mode", True), + ], "sentry/project": [ ("AUTH_TOKEN", "auth_token", True), ("DSN", "dsn", True), @@ -234,6 +259,8 @@ "metronome/sandbox": [("API_KEY", "api_key", True)], "supermemory/memory": [("API_KEY", "api_key", True)], "render/postgres": [("DATABASE_URL", "database_url", True)], + "resend/email": [("API_KEY", "api_key", True)], + "quo/app": [("API_KEY", "api_key", True)], "flyio/mpg": [("DATABASE_URL", "database_url", True)], "flyio/sprite": [("SPRITE_URL", "sprite_url", True)], }