# Alternate Futures Docs > Documentation hub for Alternate Futures products. Alternate Clouds is the decentralized cloud platform: deploy containers, AI agents, GPU and confidential workloads from the web app, the acc CLI, or the SDK. Alternate Clouds is the Alternate Futures cloud platform. It deploys containers, AI agents, GPU workloads, and confidential (TEE) services on decentralized infrastructure from the web app, the acc CLI, or the TypeScript SDK. - Docs index for agents: https://docs.alternatefutures.ai/llms.txt - Every page in one file: https://docs.alternatefutures.ai/llms-full.txt - Any page as Markdown: https://docs.alternatefutures.ai/llms.mdx//content.md (CLI reference: https://docs.alternatefutures.ai/llms.mdx/cli/commands/content.md) - Agent guide: https://docs.alternatefutures.ai/ai-agents - Web app: https://clouds.alternatefutures.ai (sign in with email or an Ethereum wallet; 14-day trial, no card) - CLI: npm install -g @alternatefutures/acc && acc login. Command groups: projects, services, deployments, regions, templates, ssh, cp, attest, chat, billing, pat. Any command accepts --help. - Non-interactive use: export AF_TOKEN (from acc pat create) and AF_PROJECT_ID, add -y to skip prompts, run acc whoami --json as a pre-flight check. - Agent skills plugin for Claude Code, Cursor, and Codex: https://github.com/alternatefutures/alternate-clouds-skills - Pages in the Legacy section describe the retired af CLI. Those commands do not exist in acc. --- # Docs for AI agents (/ai-agents) This site is built to be read by models as well as people. Use this page to point any agent (Claude, ChatGPT, Cursor, Codex, or your own) at the right resources so it can act on the platform without guessing. ## Give an agent this site [#give-an-agent-this-site] | Resource | URL | Use it for | | ---------- | ---------------------------------- | ---------------------------------------------------------------------------------------------------------------- | | Index | [`/llms.txt`](/llms.txt) | A map of every page with one-line descriptions, preceded by the platform facts below. Start here. | | Everything | [`/llms-full.txt`](/llms-full.txt) | All pages in one Markdown file, for large-context models or for building an index. | | One page | `/llms.mdx//content.md` | The Markdown behind any page. Example: [`/llms.mdx/cli/commands/content.md`](/llms.mdx/cli/commands/content.md). | Every page also has two buttons at the top right: * **Copy for AI** copies the page as Markdown and appends the platform context block shown below, so the agent knows where the app, the CLI, and the rest of the docs live without a second lookup. Paste it into any chat. * **Open in** opens the page in Claude, ChatGPT, or Cursor with a prompt that points at the Markdown endpoint, or copies just the page. ## Install the agent plugin [#install-the-agent-plugin] For agents that work on your machine (Claude Code, Cursor, Codex), install the skills plugin. It bundles the `acc` reference and task skills: first-time setup, deploy a Docker app, deploy from a template, deploy a server, troubleshoot a deployment. ```bash git clone https://github.com/alternatefutures/alternate-clouds-skills ~/.alternate-skills bash ~/.alternate-skills/install.sh ``` The installer detects which agents you have and links each skill into place. ## Let an agent run the CLI [#let-an-agent-run-the-cli] `acc` works without a terminal prompt when it has a token and a project: ```bash export AF_TOKEN="" # acc pat create --name my-agent export AF_PROJECT_ID="" # acc projects list acc whoami --json # pre-flight: exits non-zero when not signed in acc services create --kind docker --image nginx:latest --port 80 -y ``` * Add `-y` to any command that would ask for confirmation. * Use `--json` where a command offers it for machine-readable output. * Without a TTY, commands that would prompt exit non-zero instead of hanging. * Give each agent its own token so you can revoke it on its own. See [Access tokens](/guides/api-keys). * `acc --help` prints the options for any command. The full list is in the [command reference](/cli/commands). ## Platform context block [#platform-context-block] This is the text **Copy for AI** appends to every page. Put it in a system prompt, a `CLAUDE.md`, or an `AGENTS.md` when you want an agent to know the platform before it reads anything else. ## What is not machine-operable yet [#what-is-not-machine-operable-yet] * Signing up and adding a payment method happen in the web app. * Composite (multi-service) templates deploy from the web app only. * Pages in the Archive section describe the retired `af` CLI. Agents should not run those commands. # Changelog (/changelog) All notable changes to the Alternate Futures platform are documented here in reverse chronological order. ## February 2026 [#february-2026] ### Platform Launch (Public Beta) [#platform-launch-public-beta] **Released: February 2026** The Alternate Futures platform enters public beta, providing decentralized cloud infrastructure for static sites, AI agents, cloud functions, and storage management. * **Web App** - Dashboard for managing projects, sites, agents, and billing at [clouds.alternatefutures.ai](https://clouds.alternatefutures.ai) * **Multi-Auth Support** - Sign in with email (magic link), Google, GitHub, Twitter, Discord, or Web3 wallets (MetaMask, WalletConnect, Phantom) * **Three Storage Networks** - Deploy to IPFS, Filecoin, or Arweave from a unified interface * **AI Agent Hosting** - Deploy and manage Eliza, ComfyUI, and custom AI agents * **Cloud Functions** - Serverless functions on decentralized infrastructure * **Observability** - Distributed tracing, metrics, and logging for all deployments * **Billing** - Usage-based pricing with Stripe integration and credit system ### CLI v1.0 [#cli-v10] **Released: February 2026** The `@alternatefutures/cli` package is now available on npm. The CLI binary is `af`. * `af login` - Interactive browser-based authentication * `af sites init` - Initialize site configuration with framework detection * `af sites deploy` - Deploy to IPFS, Filecoin, or Arweave * `af sites list` - View all sites and deployments * `af storage add` - Upload files to decentralized storage * `af pat create` - Generate Personal Access Tokens for automation * `af projects list` - Manage projects and organizations * Automatic framework detection for React, Next.js, Vue, Astro, SvelteKit, Hugo, and more * JSON output mode for scripting and CI/CD integration * Environment variable support (`AF_TOKEN`, `AF_PROJECT_ID`) ```bash npm install -g @alternatefutures/cli ``` ### SDK v1.0 [#sdk-v10] **Released: February 2026** The `@alternatefutures/sdk` package is now available on npm with full TypeScript support. * `AlternateFuturesSdk` - Main SDK class with fluent API * `PersonalAccessTokenService` - Token-based authentication * `StaticAccessTokenService` - Static token authentication for serverless * IPFS upload and pinning (`af.ipfs().add()`) * Site management (`af.sites().list()`, `af.sites().get()`) * Storage management across all three networks * Full TypeScript type definitions * Browser and Node.js support ```bash npm install @alternatefutures/sdk ``` ### Template Repositories [#template-repositories] **Released: February 2026** Starter templates for popular frameworks, pre-configured for Alternate Futures deployment: * [template-react](https://github.com/alternatefutures/template-react) - React + Vite starter * [template-nextjs](https://github.com/alternatefutures/template-nextjs) - Next.js static export starter * [template-vue](https://github.com/alternatefutures/template-vue) - Vue.js + Vite starter * [template-astro](https://github.com/alternatefutures/template-astro) - Astro starter * [template-sveltekit](https://github.com/alternatefutures/template-sveltekit) - SvelteKit static adapter starter * [template-hugo](https://github.com/alternatefutures/template-hugo) - Hugo static site starter * [template-vitepress](https://github.com/alternatefutures/template-vitepress) - VitePress documentation starter Each template includes an `af.config.json` with the correct build command and output directory pre-configured. ### Documentation Site [#documentation-site] **Released: February 2026** Comprehensive documentation at [docs.alternatefutures.ai](https://docs.alternatefutures.ai) covering: * Getting started guides and quickstart tutorial * Framework-specific deployment guides (Next.js, React, Astro) * CLI command reference * SDK API reference (auto-generated from TypeDoc) * Migration guides from other static hosting platforms * CI/CD integration for GitHub Actions, GitLab CI, CircleCI, and Jenkins * Infrastructure guides for the decentralized container registry * Brand guidelines and design system ### Infrastructure [#infrastructure] **Released: February 2026** * **SSL Proxy** - Pingap-based SSL termination proxy on decentralized compute with a dedicated IP * **Auth Service** - Hono + SQLite authentication service on decentralized compute * **Secrets Management** - Infisical deployment for secure credential storage * **Decentralized Container Registry** - Self-hosted registry with IPFS-backed storage * **DNS** - Multi-provider DNS configuration (Cloudflare, Google, deSEC) # Overview (/) Documentation for **Alternate Futures** products. Start with Alternate Clouds, the decentralized cloud platform: deploy AI agents, containers, GPU and confidential workloads from the web app, the `acc` CLI, or the SDK. ## Alternate Clouds [#alternate-clouds] A plain-language overview for first-time visitors. Install the CLI and deploy your first service in about five minutes. Projects, billing, custom domains, access tokens, troubleshooting. Every acc command and flag, generated from the CLI source. The TypeScript SDK for programmatic access. llms.txt, Markdown endpoints, the agent plugin, and the non-interactive CLI contract. ### Install the CLI [#install-the-cli] ```bash npm install -g @alternatefutures/acc acc login ``` ## Alternate Futures [#alternate-futures] The Alternate Futures visual identity system: colors, typography, logo usage, and voice. Platform, CLI, SDK, and infrastructure releases. # Troubleshoot common problems (/troubleshooting) This page shows how to fix the problems people hit most. Each entry names the symptom, the usual cause, and the commands that resolve it. For the reasoning behind statuses and suspensions, read [How billing works](/guides/how-billing-works). ## CLI and sign-in [#cli-and-sign-in] ### `command not found: acc` [#command-not-found-acc] The CLI is not installed, or npm's global bin directory is not on your `PATH`. ```bash npm install -g @alternatefutures/acc acc --version ``` If the second command still fails, add npm's global bin directory to your `PATH`: ```bash export PATH="$(npm config get prefix)/bin:$PATH" ``` ### `acc login` cannot open a browser [#acc-login-cannot-open-a-browser] You are on a server or in a container. Use the email code flow instead: ```bash acc login --email acc whoami ``` ### The CLI prints its help instead of running a command [#the-cli-prints-its-help-instead-of-running-a-command] You ran a command that does not exist in `acc`, most often one from an old tutorial written for the retired `af` CLI (`af sites deploy`, `af storage`, `af functions`). See [Retired af CLI guides](/legacy) for what replaced each one, and [Command reference](/cli/commands) for the current commands. ### "Authentication failed" or "Invalid token" [#authentication-failed-or-invalid-token] Your stored login expired, or `AF_TOKEN` holds a bad value. ```bash acc logout && acc login # interactive machines echo -n "$AF_TOKEN" | wc -c # CI: a copied token must have no trailing whitespace acc pat create --name ci-runner # issue a fresh token if needed ``` ### Commands act on the wrong project [#commands-act-on-the-wrong-project] The CLI uses your active project, or `AF_PROJECT_ID` if it is set. ```bash acc whoami # shows the active project acc projects switch # change it acc services list -p # or name the project for one command ``` ## Deployments [#deployments] ### The deployment stays in a waiting or creating state [#the-deployment-stays-in-a-waiting-or-creating-state] A deployment waits for a provider to offer capacity. Most start within a few minutes. One that makes no progress for about 25 minutes is marked failed automatically, and you are not charged for it. If it happens repeatedly, the request is hard to place: ```bash acc regions # availability and price per region acc regions --gpu h100 # for a specific GPU model ``` Then deploy again with a different region, smaller resources, or a different GPU model: ```bash acc services deploy --region us-west acc services deploy --gpu-model a100 --gpu-count 1 ``` ### The deployment fails right away [#the-deployment-fails-right-away] Check the log and the deployment list: ```bash acc services logs --tail 200 acc deployments --service --status failed ``` Common causes: * **The image cannot be pulled.** The image name or tag is wrong, or the image is private. Images on GitHub Container Registry are private by default; make the package public in its GitHub settings. * **The wrong port.** Pass the port your container listens on with `--port`. * **A required environment variable is missing.** Templates list the variables they need. Set them with `--env KEY=VALUE` when you deploy, or afterwards: ```bash acc services env set KEY VALUE acc services deploy ``` ### A new image version does not show up after redeploying [#a-new-image-version-does-not-show-up-after-redeploying] Providers cache images by tag. A moving tag such as `latest` or `main` keeps serving the cached build, and the platform refuses those two tags when you change a service's image. Push a versioned tag (`myimage:1.4.2`) and deploy that. ### The CLI refuses a template [#the-cli-refuses-a-template] Templates that start several services at once deploy from the web app only. Open **Deploy** at [clouds.alternatefutures.ai](https://clouds.alternatefutures.ai) and choose the template there. ### The URL does not respond [#the-url-does-not-respond] The URL (`https://-app.alternatefutures.ai`) answers once the deployment is active and the container is listening on the port you exposed. ```bash acc services info # status and URL acc services logs --tail 100 acc ssh # a shell inside the running container ``` ## Suspended services and billing [#suspended-services-and-billing] ### A service shows as suspended [#a-service-shows-as-suspended] Your organization's credit wallet dropped below about one hour of total spend, so services were paused to protect the balance. Nothing was deleted. ```bash acc billing balance acc billing topup --crypto --amount 25 # or top up by card in the web app ``` Suspended services resume on their own after the topup. To stop paying for one instead, run `acc services close `. ### A deploy is refused for insufficient balance [#a-deploy-is-refused-for-insufficient-balance] Before every deploy the platform checks that the wallet covers at least one hour of everything you would then be running. Top up, or close services you no longer need, then deploy again. ### A service stopped on its own [#a-service-stopped-on-its-own] It reached a spend control you set: a total or monthly budget cap, or an auto-stop timer. `acc services info ` shows the stop reason. Deploy again with a higher cap, or with none: ```bash acc services deploy --spend payg ``` ### You cannot deploy after the trial [#you-cannot-deploy-after-the-trial] The 14-day trial has ended and the three-day grace period has passed. An owner or admin needs to choose a plan under **Billing** in the web app. ### You cannot see Billing or Members in the web app [#you-cannot-see-billing-or-members-in-the-web-app] Those pages are shown to owners and admins only. Ask an owner to change your role or to do the task for you. ### You cannot invite people [#you-cannot-invite-people] Invitations require an active paid subscription on the organization. Choose a plan first; see [Manage billing and credits](/guides/billing). ### A card topup is not offered in the CLI [#a-card-topup-is-not-offered-in-the-cli] Card payments are web only. Open **Billing** in the web app. The CLI supports stablecoin topups with `acc billing topup --crypto`. ## Custom domains [#custom-domains] Custom domains are in early access. See [Custom domains](/guides/custom-domains) for the current state and the DNS records to use. ## Still stuck [#still-stuck] Run the failing command with `--debug` and keep the output, along with `acc --version` and the service id, when you ask for help. # Accounts, organizations, and projects (/guides/account-model) This page explains how the pieces of an account fit together. For the steps, see [Manage projects](/guides/projects) and [Manage billing and credits](/guides/billing). ## The hierarchy [#the-hierarchy] ``` You (sign in with email or wallet) └── Organization billing, credits, members, roles └── Project a workspace for related services └── Service one deployed thing: a container, a template, a GPU job └── Deployment one release of that service ``` Everything you pay for or share belongs to an **organization**, never to you directly. Projects sort the work inside it. ## Organizations [#organizations] An organization owns the subscription, the credit wallet, and the list of people who can use it. * **Your personal organization** is created when you sign up. It cannot be renamed or deleted. * **Team organizations** are ones you create to work with other people. You can belong to several and switch between them in the web app. * Inviting people requires an active paid subscription on that organization. ### Roles [#roles] | Role | Can do | | ---------- | ---------------------------------------------------------------------------- | | **Owner** | Everything: billing, members, settings, deploy, and delete the organization. | | **Admin** | Deploy, and add or remove members. No billing access. | | **Member** | Deploy and view. | Owners and admins see every project. A member can be given access to all projects or only to the ones you pick when you invite them. The **Members**, **Billing**, and **Settings** pages in the web app are visible to owners and admins only. ## Projects [#projects] A project is a folder for services that belong together: one application, one customer, or one environment such as staging and production. * Every service lives in exactly one project. * The CLI always acts on one **active project**. `acc whoami` shows which, and `acc projects switch` changes it. In scripts, set `AF_PROJECT_ID` instead. * Deleting a project deletes all of its services. ## Services [#services] A service is the thing you deploy. It is created from a template, a Docker image, or as an empty server, and it carries its settings: * **Where and how it runs:** region (`us-east`, `us-west`, `eu`, `asia`, or Any), CPU, memory, storage, an optional GPU, and whether it runs confidentially inside a trusted execution environment (TEE). * **Configuration:** environment variables, and links to other services in the same project so they can find each other. * **Spend controls:** pay as you go, a budget cap, or an auto-stop timer. * **Its URL:** `https://-app.alternatefutures.ai`, assigned when the first deployment comes up. ## Deployments [#deployments] A deployment is one release of a service. Deploying again creates a new deployment rather than changing the old one, so each service has a history. A deployment moves through stages: it is created, waits for a provider to offer capacity, is handed to that provider, starts its containers, and becomes **active**. If it stops, it is **closed** (you closed it), **suspended** (your organization ran out of credits, and it resumes on topup), or **failed**. The [troubleshooting](/troubleshooting) page covers what to do in each case. ## Where to find each piece [#where-to-find-each-piece] | Piece | Web app | CLI | | -------------------- | ------------------------------------------------------------- | ------------------------------------------ | | Organization | Organization switcher, **Settings**, **Members**, **Billing** | `acc billing balance`, `--org` on topups | | Project | **Projects** | `acc projects list`, `acc projects switch` | | Service | Project page, **Deploy** | `acc services list`, `acc services info` | | Deployment | **Deployments** | `acc deployments`, `acc services logs` | | Your sign-in methods | **Account settings** | `acc login`, `acc whoami` | ## Next steps [#next-steps] * [Manage projects](/guides/projects) * [How billing works](/guides/how-billing-works) * [Web app overview](/guides/dashboard) * [Quick start](/guides/quickstart) # Managing AI agents (/guides/agents) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. The web interface for managing agents is currently under development. Use the [CLI](../cli/) or [SDK](../sdk/) to deploy and manage AI agents. Deploy and manage AI agents on decentralized infrastructure using the CLI or SDK. ## Agent Types [#agent-types] ### Eliza [#eliza] Autonomous AI agents with personality and memory: * Conversational AI with persistent memory * Multi-platform support (Discord, Twitter, Telegram) * Custom personality configuration via characterfile * Plugin ecosystem for extended capabilities ### ComfyUI [#comfyui] AI image and video generation workflows: * Stable Diffusion image generation * Custom workflow support * GPU-accelerated processing * API access for programmatic generation ### Custom [#custom] Build your own AI agents: * Deploy custom LangChain/LangGraph agents * Full control over agent logic * Connect to external APIs and services * Custom runtime environments ## Creating an Agent [#creating-an-agent] \ ```bash # Create an Eliza agent af agents create --name "My Agent" --type eliza --character ./character.json # List agents af agents list # Get agent status af agents status ``` ```typescript import { AlternateFutures } from '@alternatefutures/sdk'; const af = new AlternateFutures({ apiKey: process.env.AF_API_KEY }); // Create an agent const agent = await af.agents.create({ name: 'My Agent', type: 'eliza', config: { // Agent configuration } }); ``` ## Managing Agents [#managing-agents] \ ```bash # Start an agent af agents start # Stop an agent af agents stop # View logs af agents logs # Delete an agent af agents delete ``` ```typescript // Start an agent await af.agents.start(agentId); // Stop an agent await af.agents.stop(agentId); // Get logs const logs = await af.agents.logs(agentId); // Delete an agent await af.agents.delete(agentId); ``` ## Agent Configuration [#agent-configuration] ### Environment Variables [#environment-variables] Environment variables allow you to configure your agents with API keys, model settings, and other sensitive information without hardcoding them. #### Using .env Files [#using-env-files] Create a `.env` file in your project directory: ```bash # API Keys OPENAI_API_KEY=sk-... ANTHROPIC_API_KEY=sk-ant-... # Model Configuration MODEL=gpt-4 TEMPERATURE=0.7 MAX_TOKENS=2000 # Platform Credentials DISCORD_BOT_TOKEN=... TWITTER_API_KEY=... ``` #### Using CLI Flags [#using-cli-flags] Pass environment variables directly when creating or updating agents: ```bash # Set variables during agent creation af agents create \ --name "My Agent" \ --type eliza \ --env OPENAI_API_KEY=sk-... \ --env MODEL=gpt-4 # Update existing agent variables af agents update \ --env TEMPERATURE=0.8 ``` ```typescript // Set variables during agent creation const agent = await af.agents.create({ name: 'My Agent', type: 'eliza', env: { OPENAI_API_KEY: process.env.OPENAI_API_KEY, MODEL: 'gpt-4', TEMPERATURE: '0.7' } }); // Update existing agent variables await af.agents.update(agentId, { env: { TEMPERATURE: '0.8' } }); ``` #### Using Character Files [#using-character-files] For Eliza agents, include environment variables in your `character.json`: ```json { "name": "My Agent", "modelProvider": "openai", "settings": { "env": { "OPENAI_API_KEY": "sk-...", "MODEL": "gpt-4" } } } ``` #### Best Practices [#best-practices] * **Never commit** `.env` files or API keys to version control * Add `.env` to your `.gitignore` file * Use separate keys for development and production * Rotate keys regularly Environment variables are stored securely and encrypted at rest. However, they will be accessible to your running agent, so only use trusted code. ### Platform Integrations [#platform-integrations] Connect agents to: * **Discord** - Bot token and permissions * **Twitter** - OAuth credentials * **Telegram** - Bot token * **Slack** - Webhook URL ### Memory Settings [#memory-settings] Configure agent memory: * **Short-term** - Conversation context * **Long-term** - Persistent knowledge * **Vector DB** - Embeddings storage ## Next Steps [#next-steps] * [CLI Commands](../cli/commands.md) - Manage agents via CLI * [SDK API](../sdk/api.md) - Programmatic agent management * [Best Practices](./best-practices.md) - Optimization tips # Create and use access tokens (/guides/api-keys) This page shows how to create and use a personal access token (PAT). A token authenticates as you and works everywhere the CLI and SDK do, without a browser. ## Create a token [#create-a-token] ```bash acc pat create --name ci-runner ``` The token is printed once. Copy it now; it cannot be shown again. If you omit `--name`, the CLI asks for one. Create one token per machine or pipeline, named after where it runs, so you can revoke each one on its own. ## Use a token [#use-a-token] ### CLI, CI, and agents [#cli-ci-and-agents] ```bash export AF_TOKEN="..." # the token you copied export AF_PROJECT_ID="..." # from acc projects list acc whoami --json # confirms the identity and project acc services list ``` With both variables set, every command runs without prompts. Add `-y` to commands that ask for confirmation. ### SDK [#sdk] ```typescript import { AlternateFuturesSdk, PersonalAccessTokenService } from '@alternatefutures/sdk/node'; const af = new AlternateFuturesSdk({ accessTokenService: new PersonalAccessTokenService({ personalAccessToken: process.env.AF_TOKEN, projectId: process.env.AF_PROJECT_ID, }), }); ``` ## List and revoke tokens [#list-and-revoke-tokens] ```bash acc pat list # names, ids, and expiry dates acc pat delete # revoke one ``` Revoke a token immediately if it may have leaked, then create a new one. Token management in the web app is not available yet. Use the commands above. ## Keep tokens safe [#keep-tokens-safe] * Store tokens in a secrets manager or your CI's secret store, never in source control. * Give each pipeline its own token and rotate them periodically. * The CLI keeps your own login in `~/.alternate-futures/` with owner-only permissions; `acc logout` clears it. ## Next steps [#next-steps] * [Manage projects](/guides/projects) * [Docs for AI agents](/ai-agents) * [Sign in and accounts](/guides/authentication) # Applications (/guides/applications) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. Applications in Alternate Futures allow you to create OAuth applications and manage whitelisted domains for CORS and authentication purposes. ## What are Applications? [#what-are-applications] Applications are OAuth 2.0 applications that can authenticate users and access the Alternate Futures API on their behalf. Each application has: * **Client ID** - Public identifier for your application * **Name** - Human-readable application name * **Whitelist Domains** - Allowed domains for CORS and OAuth redirects ## Creating an Application [#creating-an-application] ```bash # Create a new application af applications create # You'll be prompted for: # - Application name # - Whitelist domains (comma-separated) ``` ```typescript import { AlternateFuturesSdk } from '@alternatefutures/sdk/node'; const af = new AlternateFuturesSdk({ personalAccessToken: process.env.AF_TOKEN }); // Create an application const app = await af.applications().create({ name: 'My Web App', whitelistDomains: ['https://myapp.com', 'https://staging.myapp.com'] }); console.log('Client ID:', app.clientId); ``` ## Listing Applications [#listing-applications] ```bash # List all applications af applications list ``` ```typescript // List all applications const applications = await af.applications().list(); applications.forEach(app => { console.log(`${app.name} (${app.clientId})`); console.log(`Domains: ${app.whitelistDomains.join(', ')}`); }); ``` ## Updating an Application [#updating-an-application] ```bash # Update an application af applications update # You'll be prompted to: # 1. Select the application # 2. Update name and/or whitelist domains ``` ```typescript // Update application await af.applications().update({ id: 'app-id', name: 'Updated Name', whitelistDomains: ['https://newdomain.com'] }); ``` ## Deleting an Application [#deleting-an-application] ```bash # Delete an application af applications delete # You'll be prompted to select which application to delete ``` ```typescript // Delete an application await af.applications().delete({ id: 'app-id' }); ``` ## Use Cases [#use-cases] ### Web Application Authentication [#web-application-authentication] Use applications to authenticate users in your web application: 1. Create an application with your production and staging domains whitelisted 2. Use the Client ID in your OAuth flow 3. Users can sign in with their Alternate Futures account 4. Your application receives an access token to make API calls ### CORS Configuration [#cors-configuration] Whitelist domains are automatically allowed for CORS requests: ```typescript // This request will succeed if the origin is whitelisted fetch('https://api.alternatefutures.ai/v1/sites', { headers: { 'Authorization': `Bearer ${accessToken}` } }); ``` ### Multi-Environment Setup [#multi-environment-setup] Create separate applications for different environments: ```bash # Development app af applications create # Name: My App (Dev) # Domains: http://localhost:3000 # Production app af applications create # Name: My App (Prod) # Domains: https://myapp.com, https://www.myapp.com ``` ## Security Best Practices [#security-best-practices] * Only whitelist domains you control * Use HTTPS for all production domains * Create separate applications for different environments * Regularly audit your whitelist domains * Delete unused applications ## Next Steps [#next-steps] * [Authentication](./authentication.md) - Set up authentication methods * [API Keys](./api-keys.md) - Generate API keys for server-side access * [CLI Commands](../cli/commands.md) - Complete CLI reference # Sign in and accounts (/guides/authentication) Sign in at [clouds.alternatefutures.ai](https://clouds.alternatefutures.ai). The same form handles sign-up and sign-in - your account is created on first successful verification. ## Authentication Methods [#authentication-methods] ### Email Code [#email-code] Passwordless authentication via email: 1. Enter your email address 2. Receive a 6-digit verification code in your inbox 3. Enter the code to sign in ### SMS Code [#sms-code] SMS sign-in is built but not yet enabled in production. Use email or a wallet for now. ### Web3 Wallets [#web3-wallets] Sign in with an Ethereum wallet using the "Sign in with Ethereum" (SIWE) standard: * **Browser extension wallets** (MetaMask, Coinbase Wallet, Rainbow, and any other EIP-6963 wallet installed in your browser) * **WalletConnect** for mobile and remote wallets You'll be asked to sign a one-time challenge message - no transaction, no gas. ## Restricted Access [#restricted-access] If sign-in ever tells you access is restricted for your email or wallet, submit the **Request Access** form shown on the page and you'll be notified when your account is approved. (Signup is currently open; this only applies when access control is enabled.) ## Account Linking [#account-linking] Manage your sign-in methods under **Account Settings** - you can link multiple methods (email, phone, wallet) to one account and sign in with any of them. ## CLI Authentication [#cli-authentication] ```bash acc login # browser flow: approve the CLI from your signed-in web session acc login --email # email code flow, no browser needed acc whoami # verify ``` ## API Authentication (CI, agents, SDK) [#api-authentication-ci-agents-sdk] For programmatic access, create a personal access token: ```bash acc pat create --name ci-runner acc pat list acc pat delete ``` **CLI:** ```bash export AF_TOKEN="your-personal-access-token" export AF_PROJECT_ID="your-project-id" acc services list ``` **SDK:** ```typescript import { AlternateFuturesSdk, PersonalAccessTokenService } from '@alternatefutures/sdk/node'; const af = new AlternateFuturesSdk({ accessTokenService: new PersonalAccessTokenService({ personalAccessToken: process.env.AF_TOKEN, projectId: process.env.AF_PROJECT_ID, }), }); ``` ## Security Best Practices [#security-best-practices] * Treat personal access tokens like passwords - store them in a secrets manager, never in source control. * Create one token per machine or pipeline (`acc pat create --name `) so you can revoke them individually. * Revoke tokens you no longer use: `acc pat delete `. * The CLI stores its token in `~/.alternate-futures/` with owner-only file permissions; `acc logout` clears it. # Best practices (/guides/best-practices) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. Optimize your Alternate Futures deployments for performance, cost, and reliability. ## Storage Optimization [#storage-optimization] ### Choose the Right Network [#choose-the-right-network] **IPFS:** * ✅ Frequently updated content * ✅ Fast content delivery * ✅ Mutable via IPNS * ❌ Recurring monthly costs **Filecoin:** * ✅ Large datasets * ✅ Long-term archival * ✅ Lower cost than IPFS * ❌ Slower retrieval **Arweave:** * ✅ Permanent, immutable content * ✅ One-time payment * ✅ NFT metadata, legal docs * ❌ Higher upfront cost ### File Optimization [#file-optimization] **Images:** ```bash # Compress images before uploading pngquant *.png --quality=65-80 jpegoptim --max=85 *.jpg # Use modern formats cwebp -q 80 image.jpg -o image.webp # Generate responsive sizes convert image.jpg -resize 800x image-800.jpg ``` **JavaScript/CSS:** ```bash # Minify assets npm run build # Most frameworks do this automatically # Tree-shaking (remove unused code) # Configure in your build tool (Vite, Webpack, etc.) ``` **Enable Compression:** ```javascript // In your build config { build: { compress: true, // gzip/brotli compression minify: true } } ``` ### Content Deduplication [#content-deduplication] IPFS and Filecoin use content-addressing, so identical files are stored only once: ```bash # Same file content = same CID = no extra storage cost echo "hello" > file1.txt echo "hello" > file2.txt # Both result in same CID: QmT78z... ``` ## Performance Optimization [#performance-optimization] ### CDN and Caching [#cdn-and-caching] **Use Multiple Gateways:** ```html ``` **Set Cache Headers:** ```javascript // In your static site // .htaccess or server config Header set Cache-Control "max-age=31536000, public" ``` ### Asset Loading [#asset-loading] **Lazy Loading:** ```html ``` **Preload Critical Resources:** ```html ``` ### Framework Optimization [#framework-optimization] **SvelteKit:** ```javascript // svelte.config.js export default { kit: { adapter: adapter({ pages: 'build', assets: 'build', fallback: null, precompress: true // Enables gzip/brotli }) } }; ``` **Next.js:** ```javascript // next.config.js module.exports = { output: 'export', // Static export for IPFS images: { unoptimized: true // Required for static export }, compress: true }; ``` ## Cost Optimization [#cost-optimization] ### Storage Costs [#storage-costs] **Unpin Unused Content (IPFS):** ```bash # List all pinned content af storage list --network ipfs --pinned # Unpin old deployments af storage unpin QmOldCID ``` **Use Filecoin for Archives:** ```bash # Move old content from IPFS to Filecoin af storage migrate QmXxx --from ipfs --to filecoin ``` **Compress Before Upload:** ```bash # Create compressed archive tar -czf site.tar.gz dist/ # Deploy compressed (auto-extracted) af sites deploy site.tar.gz ``` ### Bandwidth Costs [#bandwidth-costs] **Optimize Images:** * Use WebP format (30% smaller than JPEG) * Serve responsive sizes * Lazy load off-screen images **Enable CDN Caching:** * Use Cloudflare or similar in front of IPFS gateway * Set long cache times for immutable content **Avoid Unnecessary Requests:** * Combine CSS/JS files * Use CSS sprites for icons * Implement service worker for offline support ### Compute Costs [#compute-costs] **Agent Optimization:** ```javascript // Stop agents when not needed af agents stop agent-id // Start on-demand af agents start agent-id // Use smaller models { model: "gpt-3.5-turbo" // vs gpt-4 } ``` ## Security Best Practices [#security-best-practices] ### API Keys [#api-keys] ```bash # Use environment variables export AF_API_KEY="af_xxx" # Never commit to git echo "AF_API_KEY=*" >> .gitignore # Rotate regularly af api-keys create --expires 90d af api-keys revoke old-key-id # Use minimal permissions af api-keys create --permissions agents:read,sites:write ``` ### Content Security [#content-security] **Verify Content:** ```bash # Check CID matches content ipfs add --only-hash file.txt # Compare with retrieved CID ``` **Sign Deployments:** ```bash # Sign with private key for verification af sites deploy ./dist --sign ``` ## Reliability Best Practices [#reliability-best-practices] ### Redundancy [#redundancy] **Pin on Multiple Services:** ```bash # Primary pinning service af storage pin QmXxx --provider pinata # Backup pinning af storage pin QmXxx --provider web3storage ``` **Use Multiple Networks:** ```bash # Deploy to both IPFS and Arweave af sites deploy ./dist --network ipfs af sites deploy ./dist --network arweave ``` ### Monitoring [#monitoring] **Set Up Alerts:** ```bash # Monitor agent uptime af agents monitor agent-id --alert-email you@example.com # Monitor bandwidth usage acc billing alert --type bandwidth --threshold 1TB ``` **Check Deployment Health:** ```bash # Verify site accessibility curl -I https://gateway.ipfs.io/ipfs/QmXxx # Check all gateways af sites check site-id --all-gateways ``` ## Development Workflow [#development-workflow] ### Local Development [#local-development] ```bash # Use local IPFS node ipfs daemon # Test locally before deploying af sites preview ./dist --local # Deploy to staging first af sites deploy ./dist --name staging # Test thoroughly, then deploy to production af sites deploy ./dist --name production ``` ### CI/CD [#cicd] ```yaml # .github/workflows/deploy.yml - name: Deploy to staging if: github.ref == 'refs/heads/staging' run: af sites deploy ./dist --network ipfs - name: Deploy to production if: github.ref == 'refs/heads/main' run: af sites deploy ./dist --network arweave ``` ## Content Organization [#content-organization] ### Naming Conventions [#naming-conventions] ```bash # Use descriptive names af sites deploy ./dist --name "marketing-website-prod" af agents create --name "discord-bot-support" # Include version numbers af sites deploy ./dist --name "app-v1.2.0" # Use tags for organization af sites deploy ./dist --tags production,public ``` ### Project Structure [#project-structure] ``` my-project/ ├── dist/ # Built static files ├── .env # API keys (not in git!) ├── .gitignore # Include .env ├── af-config.json # Alternate Futures config └── deploy.sh # Deployment script ``` ## Next Steps [#next-steps] * [Storage Management](./storage.md) - Manage storage efficiently * [Billing](./billing.md) - Understand costs * [CI/CD Integration](./cicd.md) - Automate deployments # Manage billing and credits (/guides/billing) This page shows how to do the billing tasks. To understand the model behind them, read [How billing works](/guides/how-billing-works) first. You need to be an owner or admin of the organization for the web app tasks. The CLI commands work for anyone who can deploy. ## Check your balance [#check-your-balance] ```bash acc billing balance ``` In the web app, open **Billing** and look at **Credits wallet**. ## Top up credits [#top-up-credits] ### By card [#by-card] Card payments are web only. Open **Billing**, choose **Credits wallet**, then **Top up**, and pay with a card or a saved method. Credits appear as soon as the payment succeeds. ### By stablecoin [#by-stablecoin] From the web app, choose the crypto option on the same **Top up** screen. From the CLI: ```bash acc billing topup --crypto --amount 25 ``` The CLI prints a deposit address and waits for the transfer to confirm. It asks for a refund address if you do not pass one; that address receives the difference if the amount you send does not match the quote exactly. | Option | Description | | ---------------------------- | ------------------------------------------------------------------ | | `--amount ` | Amount in US dollars | | `--chain ` | `base` (default), `ethereum`, `arbitrum`, `optimism`, or `polygon` | | `--token ` | `USDC` (default), `USDT`, or `DAI` | | `--refund-address
` | Where to send any difference between the transfer and the quote | | `--org ` | Organization to credit, if you belong to more than one | | `--no-wait` | Print the deposit address and exit without waiting | ## Choose or change a plan [#choose-or-change-a-plan] Open **Billing**, then **Plans**. | Plan | Price | | ------- | ---------------------- | | Monthly | $25 per seat per month | | Yearly | $240 per seat per year | Pay by card, or select the option to fund the subscription from your credit wallet. Your 14-day trial continues until it ends; subscribing early does not shorten it. ## Set spend controls on a service [#set-spend-controls-on-a-service] Add a limit when you create or deploy a service. Without one, the service pays as you go. ```bash # Stop the service once it has spent $20 in a month acc services create --kind docker --image nginx:1.27 --port 80 --budget-monthly 20 # Stop the service after eight hours acc services deploy --stop-hours 8 ``` | Option | Description | | ------------------------------------- | ----------------------------- | | `--spend ` | `payg`, `budget`, or `stop` | | `--budget-total ` | Lifetime cap for this service | | `--budget-monthly ` | Monthly cap for this service | | `--stop-hours `, `--stop-days ` | Auto-stop timer | ## Get suspended services running again [#get-suspended-services-running-again] Services are suspended when the wallet cannot cover their next hour. Top up, and they resume on their own. To stop paying for a service instead: ```bash acc services close ``` `acc services list` shows what is running now; `acc deployments --all` includes closed and old deployments. ## See usage and invoices [#see-usage-and-invoices] Open **Billing** in the web app: * **Usage** lists what each service consumed and what it cost. * **Payments** lists topups and subscription payments. * **Invoices** holds past invoices. ## Next steps [#next-steps] * [How billing works](/guides/how-billing-works) * [Troubleshoot common problems](/troubleshooting) * [Command reference: billing](/cli/commands#billing) # CI/CD integration (/guides/cicd) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. Automate deployments with continuous integration and delivery pipelines. ## GitHub Actions [#github-actions] ### Basic Workflow [#basic-workflow] Create `.github/workflows/deploy.yml`: ```yaml name: Deploy to Alternate Futures on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: npm install - name: Build run: npm run build - name: Deploy to Alternate Futures run: npx @alternatefutures/cli sites deploy ./dist --network ipfs env: AF_API_KEY: ${{ secrets.AF_API_KEY }} ``` ### Add API Key Secret [#add-api-key-secret] 1. Go to repository **Settings** → **Secrets and variables** → **Actions** 2. Click **New repository secret** 3. Name: `AF_API_KEY` 4. Value: Your API key from [clouds.alternatefutures.ai/api-keys](https://clouds.alternatefutures.ai/api-keys) 5. Click **Add secret** ### Multi-Environment Workflow [#multi-environment-workflow] Deploy to staging and production: ```yaml name: Deploy on: push: branches: [main, staging] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install and build run: | npm install npm run build - name: Deploy to Staging if: github.ref == 'refs/heads/staging' run: npx @alternatefutures/cli sites deploy ./dist --network ipfs --name staging env: AF_API_KEY: ${{ secrets.AF_API_KEY_STAGING }} - name: Deploy to Production if: github.ref == 'refs/heads/main' run: npx @alternatefutures/cli sites deploy ./dist --network arweave --name production env: AF_API_KEY: ${{ secrets.AF_API_KEY_PROD }} ``` ## GitLab CI/CD [#gitlab-cicd] Create `.gitlab-ci.yml`: ```yaml image: node:20 stages: - build - deploy cache: paths: - node_modules/ build: stage: build script: - npm install - npm run build artifacts: paths: - dist/ expire_in: 1 hour deploy: stage: deploy only: - main script: - npm install -g @alternatefutures/cli - af sites deploy ./dist --network ipfs variables: AF_API_KEY: $AF_API_KEY ``` Add `AF_API_KEY` in GitLab project settings: * **Settings** → **CI/CD** → **Variables** ## CircleCI [#circleci] Create `.circleci/config.yml`: ```yaml version: 2.1 jobs: deploy: docker: - image: cimg/node:20.0 steps: - checkout - restore_cache: keys: - deps-{{ checksum "package-lock.json" }} - run: name: Install dependencies command: npm install - save_cache: key: deps-{{ checksum "package-lock.json" }} paths: - node_modules - run: name: Build command: npm run build - run: name: Deploy command: | npm install -g @alternatefutures/cli af sites deploy ./dist --network ipfs workflows: deploy: jobs: - deploy: filters: branches: only: main ``` Add `AF_API_KEY` in CircleCI project settings. ## Vercel Integration [#vercel-integration] Deploy from Vercel to Alternate Futures: ```json { "buildCommand": "npm run build", "outputDirectory": "dist", "installCommand": "npm install", "devCommand": "npm run dev", "ignoreCommand": "echo 'Building on Vercel'" } ``` Then add deployment hook: ```json { "scripts": { "vercel-build": "npm run build && npm run deploy:af" "deploy:af": "npx @alternatefutures/cli sites deploy ./dist --network ipfs" } } ``` Set `AF_API_KEY` in Vercel environment variables. ## Jenkins [#jenkins] Create `Jenkinsfile`: ```groovy pipeline { agent any environment { AF_API_KEY = credentials('af-api-key') } stages { stage('Install') { steps { sh 'npm install' } } stage('Build') { steps { sh 'npm run build' } } stage('Deploy') { when { branch 'main' } steps { sh 'npm install -g @alternatefutures/cli' sh 'af sites deploy ./dist --network ipfs' } } } } ``` Add `af-api-key` credential in Jenkins credentials manager. ## CLI Options [#cli-options] Common deployment options: ```bash # Deploy with custom name af sites deploy ./dist --name "My Site" --network ipfs # Deploy with metadata af sites deploy ./dist --description "Production v1.2.0" # Deploy to specific network af sites deploy ./dist --network arweave # or ipfs, filecoin # Wait for deployment completion af sites deploy ./dist --wait # Get deployment URL in JSON af sites deploy ./dist --json | jq -r '.url' ``` ## Environment Variables [#environment-variables] CLI reads these environment variables: * `AF_API_KEY` - API key for authentication * `AF_SITE_ID` - Default site ID (optional) * `AF_NETWORK` - Default network (optional) ## Best Practices [#best-practices] ### Security [#security] * ✅ Use secrets/encrypted variables for API keys * ✅ Use separate keys for staging and production * ✅ Rotate keys regularly * ✅ Set minimal permissions on API keys * ❌ Never commit API keys to repository ### Performance [#performance] * ✅ Cache dependencies between runs * ✅ Only deploy on specific branches * ✅ Use build artifacts to pass between jobs * ✅ Deploy to IPFS for staging (faster) * ✅ Deploy to Arweave for production (permanent) ### Reliability [#reliability] * ✅ Add status checks before deploying * ✅ Run tests before deployment * ✅ Use `--wait` flag for deployment confirmation * ✅ Monitor deployment success/failure * ✅ Set up notifications for failed deployments ## Deployment Notifications [#deployment-notifications] ### Slack [#slack] Send deployment notifications: ```yaml - name: Notify Slack if: success() uses: slackapi/slack-github-action@v1 with: payload: | { "text": "🚀 Deployed to ${{ secrets.DEPLOY_URL }}" } env: SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }} ``` ### Discord [#discord] ```yaml - name: Notify Discord if: success() run: | curl -X POST ${{ secrets.DISCORD_WEBHOOK }} \ -H "Content-Type: application/json" \ -d '{"content": "🚀 Deployed to production!"}' ``` ## Next Steps [#next-steps] * [API Keys](./api-keys.md) - Generate API keys for CI/CD * [Best Practices](./best-practices.md) - Optimization strategies * [CLI Commands](../cli/commands.md) - Full CLI reference # Custom domains (/guides/custom-domains) Domain management (connect your own domain, or purchase one in the dashboard) is rolling out and not yet enabled for all accounts. Parts of this guide describe the earlier sites flow and will be updated as the feature ships. Bring your own domain from any registrar (GoDaddy, Namecheap, Cloudflare, etc.) and point it to your Alternate Clouds services. ## Overview [#overview] By default, sites are accessible via: * **IPFS**: `https://gateway.ipfs.io/ipfs/{CID}` * **Arweave**: `https://arweave.net/{TX_ID}` * **Filecoin**: `https://ipfs.io/ipfs/{CID}` Custom domains provide: * Branded URLs (e.g., `https://example.com`) * Easier to remember and share * SEO benefits * Professional appearance * Automatic SSL/TLS certificates via Let's Encrypt ## Adding a Custom Domain [#adding-a-custom-domain] ### Step 1: Create Domain [#step-1-create-domain] Use the GraphQL API or SDK to add your domain: ```graphql mutation { createDomain(input: { hostname: "example.com" siteId: "site-123" verificationMethod: TXT }) { id hostname txtVerificationToken verified } } ``` **Verification Methods:** * `TXT` - TXT record verification (works with root domains and subdomains) * `CNAME` - CNAME record verification (subdomains only) * `A` - A record verification (points to platform IP) ### Step 2: Configure DNS Records [#step-2-configure-dns-records] Based on your chosen verification method, add the appropriate DNS record at your domain registrar: ## DNS Configuration Methods [#dns-configuration-methods] ### Method 1: TXT Record Verification (Recommended) [#method-1-txt-record-verification-recommended] Add a TXT record to verify domain ownership: ``` Type: TXT Name: @ (or your hostname) Value: af-site-verification=xxxxx (from createDomain response) TTL: 3600 ``` **Example:** ```graphql mutation { createDomain(input: { hostname: "example.com" siteId: "site-123" verificationMethod: TXT }) { id txtVerificationToken # Use this value } } ``` **Pros:** * Works with root domains and subdomains * Non-intrusive (doesn't affect current DNS) * Easy to verify **Use Case:** Best for initial verification before changing DNS routing ### Method 2: CNAME Record Verification [#method-2-cname-record-verification] Point your subdomain to the platform: ``` Type: CNAME Name: www (or subdomain) Value: cname.alternatefutures.ai TTL: 3600 ``` **Example:** ```graphql mutation { createDomain(input: { hostname: "www.example.com" siteId: "site-123" verificationMethod: CNAME }) { id expectedCname # Points to platform } } ``` **Pros:** * Verifies and routes traffic in one step * Automatic deployment updates * CDN benefits **Cons:** * Only works with subdomains (not root domains) **Use Case:** Best for `www.example.com` or other subdomains ### Method 3: A Record Verification [#method-3-a-record-verification] Point directly to the platform IP: ``` Type: A Name: @ (for root domain) Value: [Platform IP Address] TTL: 3600 ``` **Example:** ```graphql mutation { createDomain(input: { hostname: "example.com" siteId: "site-123" verificationMethod: A }) { id expectedARecord # Platform IP } } ``` **Pros:** * Works with root domains * Verifies and routes in one step * Fast DNS resolution **Use Case:** Best for apex/root domains like `example.com` ### Step 3: Verify Domain [#step-3-verify-domain] After adding DNS records, verify your domain: ```graphql mutation { verifyDomain(domainId: "domain-123") } ``` This checks DNS propagation and updates the domain status. You may need to wait a few minutes for DNS changes to propagate globally. **Check verification status:** ```graphql query { domain(id: "domain-123") { id hostname verified txtVerificationStatus dnsCheckAttempts lastDnsCheck } } ``` ## SSL/TLS Certificates [#ssltls-certificates] Once your domain is verified, provision an SSL certificate: ```graphql mutation { provisionSsl( domainId: "domain-123" email: "admin@example.com" ) { id sslStatus sslIssuedAt sslExpiresAt } } ``` **SSL Features:** * Automatic Let's Encrypt certificate provisioning * Auto-renewal 30 days before expiry * HTTP-01 and DNS-01 ACME challenges supported * Free SSL for all domains **Certificate Process:** 1. Domain must be verified first 2. Request SSL certificate via `provisionSsl` mutation 3. Wait 5-10 minutes for Let's Encrypt validation 4. Certificate automatically installed and renewed ## Domain Status [#domain-status] **Verification Status:** * `PENDING` - DNS not yet propagated * `VERIFIED` - Domain ownership confirmed * `FAILED` - DNS misconfigured or verification failed **SSL Status:** * `NONE` - No certificate requested * `PENDING` - Certificate being provisioned * `ACTIVE` - SSL certificate active and working * `FAILED` - Certificate provisioning failed **Check status:** ```graphql query { domain(id: "domain-123") { verified txtVerificationStatus sslStatus sslExpiresAt } } ``` ## Managing Multiple Domains [#managing-multiple-domains] ### List All Domains [#list-all-domains] Get all domains for a site: ```graphql query { site(id: "site-123") { id domains { id hostname verified sslStatus createdAt } } } ``` ### Set Primary Domain [#set-primary-domain] Set a verified domain as the primary domain for your site: ```graphql mutation { setPrimaryDomain( siteId: "site-123" domainId: "domain-123" ) { id primaryDomain { hostname } } } ``` **Requirements:** * Domain must be verified * Only verified domains can be primary ### Remove Domain [#remove-domain] Remove a custom domain: ```graphql mutation { removeDomain(domainId: "domain-123") } ``` **Note:** Cannot remove a domain that is set as primary. Set a different primary domain first. ### Common Multi-Domain Setup [#common-multi-domain-setup] Add multiple domains for different purposes: * **Primary domain**: `example.com` * **WWW subdomain**: `www.example.com` * **Regional domains**: `example.co.uk`, `example.ca` * **Staging domains**: `staging.example.com` Each domain can have its own SSL certificate and verification method. ## Troubleshooting [#troubleshooting] ### Verification Failing [#verification-failing] **1. Check DNS propagation:** ```bash dig example.com TXT dig www.example.com CNAME dig example.com A ``` DNS changes can take 5 minutes to 48 hours to propagate globally. **2. Verify correct DNS values:** For TXT verification: ```bash dig example.com TXT | grep "af-site-verification" ``` For CNAME verification: ```bash dig www.example.com CNAME # Should show: cname.alternatefutures.ai ``` For A record verification: ```bash dig example.com A # Should show platform IP ``` **3. Common verification issues:** * DNS not propagated yet (wait 5-60 minutes) * Wrong record type (TXT vs CNAME vs A) * Incorrect hostname (@ vs www vs subdomain) * Typo in verification token * TTL too high (recommended: 3600 seconds) **4. Check verification attempts:** ```graphql query { domain(id: "domain-123") { dnsCheckAttempts lastDnsCheck txtVerificationStatus } } ``` If attempts > 10 and still failing, double-check DNS configuration. ### SSL Certificate Issues [#ssl-certificate-issues] **Check certificate status:** ```graphql query { domain(id: "domain-123") { sslStatus sslIssuedAt sslExpiresAt } } ``` **Common issues:** 1. **Domain not verified** * Error: "Domain must be verified before provisioning SSL" * Solution: Complete DNS verification first 2. **Certificate provisioning stuck on PENDING** * DNS not fully propagated * CAA records blocking Let's Encrypt * Port 80/443 not accessible for HTTP-01 challenge * Wait 10-15 minutes and check again 3. **Certificate expired** * Certificates auto-renew 30 days before expiry * Check: `sslExpiresAt` field * Re-provision if needed: Run `provisionSsl` mutation again **Test SSL certificate:** ```bash curl -vI https://example.com openssl s_client -connect example.com:443 -servername example.com ``` ### DNS Provider Specific Issues [#dns-provider-specific-issues] **Cloudflare:** * Disable "orange cloud" proxy for verification * Use "DNS only" (grey cloud) mode initially * Re-enable proxy after verification completes **GoDaddy:** * DNS propagation can be slow (24-48 hours) * Use shorter TTL values (600-3600 seconds) **Namecheap:** * Use `@` for root domain TXT records * Use `www` for CNAME records (not `www.example.com`) **Google Domains / Cloud DNS:** * Include trailing dot in CNAME if required * Example: `cname.alternatefutures.ai.` ## Supported DNS Providers [#supported-dns-providers] Tested and working with: * **Cloudflare** - Fast propagation (5-15 min), excellent DNS management * **Namecheap** - Good propagation (30-60 min) * **GoDaddy** - Slower propagation (2-24 hours) * **Google Domains** - Fast and reliable * **AWS Route53** - Enterprise-grade, fast propagation * **DigitalOcean DNS** - Fast and simple * **Vercel DNS** - Fast propagation All major DNS providers support TXT, CNAME, and A records needed for domain verification. ## Web3 Domains [#web3-domains] ### ArNS (Arweave Name System) [#arns-arweave-name-system] Register permanent domains on Arweave: ```graphql mutation { registerArnsName( siteId: "site-123" arnsName: "my-site" ) { name transactionId contentId } } ``` **Features:** * Permanent, immutable domains * Stored on Arweave blockchain * Access via: `my-site.arweave.net` ### ENS (Ethereum Name System) [#ens-ethereum-name-system] Link ENS domains to your content: ```graphql mutation { linkEnsDomain( siteId: "site-123" ensName: "mysite.eth" ) { ensName contentHash resolverAddress } } ``` **Features:** * Ethereum-based domain names * Decentralized DNS alternative * Access via ENS-compatible browsers ### IPNS (IPFS Name System) [#ipns-ipfs-name-system] Create mutable IPNS pointers: ```graphql mutation { createIpnsName( siteId: "site-123" ipnsName: "my-ipns-site" ) { ipnsName ipnsHash currentCid } } ``` **Features:** * Mutable pointers to IPFS content * Update content without changing address * Access via: `/ipns/{hash}` ## Complete Example Workflow [#complete-example-workflow] Here's a complete example of adding a custom domain with SSL: ```graphql # Step 1: Create domain with TXT verification mutation CreateDomain { createDomain(input: { hostname: "example.com" siteId: "site-abc123" verificationMethod: TXT }) { id hostname txtVerificationToken } } # Response: # { # "id": "domain-xyz789", # "hostname": "example.com", # "txtVerificationToken": "af-site-verification=abc123def456" # } # Step 2: Add DNS TXT record at your registrar # Type: TXT # Name: @ # Value: af-site-verification=abc123def456 # TTL: 3600 # Step 3: Wait 5-60 minutes for DNS propagation # Test with: dig example.com TXT # Step 4: Verify domain mutation VerifyDomain { verifyDomain(domainId: "domain-xyz789") } # Step 5: Check verification status query CheckDomain { domain(id: "domain-xyz789") { verified txtVerificationStatus } } # Step 6: Provision SSL certificate mutation ProvisionSSL { provisionSsl( domainId: "domain-xyz789" email: "admin@example.com" ) { sslStatus sslIssuedAt sslExpiresAt } } # Step 7: Wait 5-10 minutes for Let's Encrypt # Your site is now live at https://example.com! # Step 8: Set as primary domain (optional) mutation SetPrimary { setPrimaryDomain( siteId: "site-abc123" domainId: "domain-xyz789" ) { id primaryDomain { hostname } } } ``` ## API Reference [#api-reference] ### Mutations [#mutations] **createDomain** - Add a custom domain * Input: `CreateDomainInput` * Returns: `Domain` **verifyDomain** - Verify domain ownership * Input: `domainId: ID!` * Returns: `Boolean` **provisionSsl** - Request SSL certificate * Input: `domainId: ID!`, `email: String!` * Returns: `Domain` **setPrimaryDomain** - Set primary domain for site * Input: `siteId: ID!`, `domainId: ID!` * Returns: `Site` **removeDomain** - Remove custom domain * Input: `domainId: ID!` * Returns: `Boolean` ### Queries [#queries] **domain** - Get domain by ID * Input: `id: ID!` * Returns: `Domain` **domains** - List all domains for a site * Input: `siteId: ID!` * Returns: `[Domain!]!` ## Next steps [#next-steps] * [Projects](/guides/projects) - Organize services and members * [Troubleshooting](/troubleshooting) - DNS and certificate issues * [Quick start](/guides/quickstart) - Deploy a service to point a domain at # Web app overview (/guides/dashboard) This page explains what you find where in the web app at [clouds.alternatefutures.ai](https://clouds.alternatefutures.ai). It is the same platform the `acc` CLI and the SDK drive, so anything you create here shows up there and the other way round. ## Organizations first [#organizations-first] The web app always shows one organization at a time. Use the switcher at the top of the sidebar to move between your personal organization and any teams you belong to. Billing, members, and settings belong to the organization; see [Accounts, organizations, and projects](/guides/account-model). ## The sidebar [#the-sidebar] | Page | What it shows | Who sees it | | --------------- | -------------------------------------------------------------------------------------------------------------------- | ----------------- | | **Overview** | Running services and current spend at a glance. | Everyone | | **Projects** | Your projects and the services inside each one. Create a project here. | Everyone | | **Deployments** | Every deployment across the organization, with live progress while one is coming up. | Everyone | | **Members** | Who belongs to the organization, their role, and which projects a member can access. Invitations are sent from here. | Owners and admins | | **Billing** | Usage, payments, invoices, plans, and the credits wallet. | Owners and admins | | **Settings** | Organization name and details. | Owners and admins | ## Deploy [#deploy] **Deploy** is where a new service starts. Choose a template from the catalog (AI agents, databases, inference servers, and more), or bring a Docker image. The form asks for the same things the CLI asks for: project, region, resources, required environment variables, and a spend control. Multi-service templates can only be deployed from the web app. ## A service's page [#a-services-page] Open a service from its project to see its status, public URL, logs, and environment variables, and to redeploy or close it. ## Account settings [#account-settings] Your own account, separate from any organization: the sign-in methods linked to it (email, wallet, phone), and your profile. Add a verified email here to collect the signup credit if you signed up with a wallet. Custom domains and token management pages are not shown in the web app yet. Manage tokens with `acc pat` and see [Custom domains](/guides/custom-domains) for the current state of domains. ## Next steps [#next-steps] * [Quick start](/guides/quickstart) * [Accounts, organizations, and projects](/guides/account-model) * [Manage billing and credits](/guides/billing) # Decentralized container registry (/guides/decentralized-registry) This is a registry **you deploy and own** on your Alternate Clouds infrastructure (see [Deploy Your Registry](/guides/registry-deployment)). Alternate Futures does not operate a shared public registry - replace `registry.` below with the domain you attach to your deployment. ## Overview [#overview] Run a **fully decentralized container registry** for storing and distributing Docker images. Unlike centralized services like Docker Hub, your container images are stored on your own infrastructure running on Akash Network with IPFS storage. ## Architecture [#architecture] ``` ┌───────────────── Akash Network ─────────────────┐ │ │ │ PostgreSQL → OpenRegistry → IPFS Node │ │ (metadata) (OCI API) (storage) │ │ │ └──────────────────────────────────────────────────┘ ↓ ↓ registry. ipfs. ``` ### Components [#components] **PostgreSQL**: Stores registry metadata (image names, tags, manifests) **OpenRegistry**: OCI-compliant container registry providing Docker-compatible API **IPFS Node (Kubo)**: Decentralized storage for container image layers **Akash Network**: Decentralized compute platform hosting all services ## Why Use a Decentralized Registry? [#why-use-a-decentralized-registry] ### Complete Sovereignty [#complete-sovereignty] * **No Docker Hub**: Eliminate dependency on centralized registries * **No Third Parties**: No Pinata, Filebase, or other IPFS services * **You Control the Data**: Full ownership of your container images * **Censorship Resistant**: Images stored on IPFS cannot be taken down ### Cost Savings [#cost-savings] * **Traditional Stack**: $77-307/month (Docker Hub + IPFS service + cloud hosting) * **Decentralized Stack**: $40-70/month (Akash only) * **Savings**: 40-85% cost reduction ### Performance [#performance] * **Global Distribution**: IPFS enables P2P delivery * **Persistent Storage**: 100GB+ storage on Akash * **Fast Pulls**: Content-addressed retrieval * **High Availability**: Multi-provider redundancy on Akash ### Developer Benefits [#developer-benefits] * **OCI Compatible**: Works with Docker, containerd, Kubernetes, etc. * **Standard Workflow**: `docker push` and `docker pull` just work * **CI/CD Ready**: Integrate with GitHub Actions, GitLab CI, etc. * **Web3 Native**: Aligns with decentralization mission ## Quick Start [#quick-start] ### Push Your First Image [#push-your-first-image] ```bash # Tag your image with the registry domain docker tag myapp:latest registry./myapp:latest # Push to the decentralized registry docker push registry./myapp:latest ``` The image layers are automatically stored on IPFS and distributed across the network! ### Pull an Image [#pull-an-image] ```bash # Pull from the decentralized registry docker pull registry./myapp:latest # Run it docker run registry./myapp:latest ``` ### Use in Akash Deployments [#use-in-akash-deployments] ```yaml # deploy.yaml services: app: image: registry./myapp:latest expose: - port: 8080 to: - global: true ``` ## How It Works [#how-it-works] ### 1. Image Push Flow [#1-image-push-flow] ``` Developer → Docker CLI → OpenRegistry → IPFS Node ↓ Stores layers ↓ Returns CID ↓ PostgreSQL (metadata) ``` When you push an image: 1. Docker client sends image layers to OpenRegistry 2. OpenRegistry splits image into layers 3. Each layer is stored on IPFS node 4. IPFS returns content identifier (CID) for each layer 5. OpenRegistry stores mapping in PostgreSQL 6. Image is pinned to ensure persistence ### 2. Image Pull Flow [#2-image-pull-flow] ``` User → Docker CLI → OpenRegistry → IPFS Node ↓ Fetches layers ↓ Returns image ``` When you pull an image: 1. Docker client requests image from OpenRegistry 2. OpenRegistry looks up layer CIDs in PostgreSQL 3. Fetches layers from IPFS node 4. Returns layers to Docker client 5. Docker assembles the image ### 3. IPFS Storage [#3-ipfs-storage] All container layers are stored on IPFS with these benefits: * **Content Addressing**: Layers are identified by their hash (CID) * **Deduplication**: Identical layers are stored once * **Distributed**: Layers can be fetched from multiple peers * **Immutable**: Content cannot be tampered with * **Verifiable**: CID proves authenticity ## Storage Management [#storage-management] ### IPFS Node Details [#ipfs-node-details] * **Storage**: 100GB persistent volume on Akash * **API**: Port 5001 (internal only) * **Gateway**: Port 8080 (public at `ipfs.`) * **Swarm**: Port 4001 (P2P connections) ### Viewing IPFS Content [#viewing-ipfs-content] Access any layer directly via IPFS gateway: ``` https://ipfs./ipfs/ ``` ### Storage Limits [#storage-limits] * **Per Image**: No limit (automatically managed) * **Total Storage**: 100GB initially (expandable) * **Garbage Collection**: Automatic cleanup of unused layers ## Working with Images [#working-with-images] The registry speaks the standard OCI protocol, so the plain Docker CLI works against it. (A dedicated `acc registry` command group is not shipped yet.) ### Push Image [#push-image] ```bash docker tag myapp:latest registry./myapp:latest docker push registry./myapp:latest ``` ### Pull Image [#pull-image] ```bash docker pull registry./myapp:latest ``` ### Image Details [#image-details] ```bash docker manifest inspect registry./myapp:latest ``` Displays the manifest, layer digests, and total size. ## CI/CD Integration [#cicd-integration] ### GitHub Actions [#github-actions] ```yaml name: Build and Push on: push: branches: [main] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Build image run: docker build -t myapp . - name: Login to registry run: docker login registry. env: REGISTRY_USERNAME: ${{ secrets.REGISTRY_USER }} REGISTRY_PASSWORD: ${{ secrets.REGISTRY_TOKEN }} - name: Push to decentralized registry run: | docker tag myapp registry./myapp:latest docker push registry./myapp:latest ``` ### GitLab CI [#gitlab-ci] ```yaml build: stage: build script: - docker build -t myapp . - docker login registry. - docker tag myapp registry./myapp:latest - docker push registry./myapp:latest ``` ## Best Practices [#best-practices] ### Image Naming [#image-naming] Use semantic naming: ``` registry.//: ``` Examples: * `registry./myorg/api:v1.0.0` * `registry./myorg/frontend:latest` * `registry./myorg/worker:staging` ### Tagging Strategy [#tagging-strategy] Use multiple tags: ```bash # Version tag docker tag myapp registry./myapp:v1.2.3 # Environment tag docker tag myapp registry./myapp:production # Latest tag docker tag myapp registry./myapp:latest # Push all docker push registry./myapp --all-tags ``` ### Image Optimization [#image-optimization] Reduce storage costs: **Multi-stage builds:** ```dockerfile FROM node:18 AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build FROM node:18-alpine WORKDIR /app COPY --from=builder /app/dist ./dist CMD ["node", "dist/index.js"] ``` **Use Alpine images:** ```dockerfile FROM node:18-alpine # ~50MB instead of ~1GB ``` **Clean up in single layer:** ```dockerfile RUN apt-get update && \ apt-get install -y packages && \ apt-get clean && \ rm -rf /var/lib/apt/lists/* ``` ## Security [#security] ### Authentication [#authentication] Token-based authentication is enabled: ```bash # Login docker login registry. Username: your-username Password: your-token ``` ### Access Control [#access-control] Images are private by default. Access requires: * Valid authentication token * Proper permissions ### Image Scanning [#image-scanning] Scan images for vulnerabilities before pushing: ```bash # Using Docker Scout docker scout cve myapp:latest # Using Trivy trivy image myapp:latest ``` ## Monitoring [#monitoring] ### Registry Health [#registry-health] Check registry status: ```bash curl https://registry./v2/ # Returns: {} ``` ### IPFS Health [#ipfs-health] Check IPFS node: ```bash curl https://ipfs./ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn ``` ### Storage Usage [#storage-usage] View IPFS storage stats via API: ```bash curl http://ipfs.:5001/api/v0/repo/stat ``` ## Troubleshooting [#troubleshooting] ### Push Fails [#push-fails] **Symptom**: `denied: requested access to the resource is denied` **Solution**: Login first ```bash docker login registry. ``` ### Slow Pulls [#slow-pulls] **Symptom**: Image pull takes a long time **Possible Causes**: * Large image size * IPFS node syncing * Network latency **Solutions**: * Optimize image size (use Alpine, multi-stage builds) * Pre-pull common base images * Use layer caching ### Image Not Found [#image-not-found] **Symptom**: `manifest unknown` **Solution**: Verify image name and tag ```bash docker manifest inspect registry./myapp:latest ``` ## Next Steps [#next-steps] * [Deploy Your Own Registry](/guides/registry-deployment) - Self-host the entire stack * [Registry architecture](/guides/registry-architecture) - How the stack fits together ## Support [#support] Need help? * [Discord Community](https://discord.gg/alternatefutures) * [GitHub Issues](https://github.com/alternatefutures/registry/issues) * [Email Support](mailto:support@alternatefutures.ai) # Deploy an Astro Site (/guides/deploy-astro) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. Deploy your Astro site to decentralized infrastructure using Alternate Futures. Astro's static-first architecture makes it an excellent fit for decentralized hosting. ## Prerequisites [#prerequisites] Before you begin, make sure you have: * **An Alternate Futures account** - [Sign up here](https://clouds.alternatefutures.ai) (free, no credit card required) * **The AF CLI installed** - `npm install -g @alternatefutures/cli` * **Node.js 18 or later** - [Download here](https://nodejs.org/en/download) * **An Astro project** (or we will create one below) ## Quick Deploy (Existing Astro Project) [#quick-deploy-existing-astro-project] If you already have an Astro project, deploy it in three commands: ```bash # Build the production output npm run build # Initialize AF configuration af sites init # Deploy to IPFS af sites deploy ``` Astro outputs to `./dist` by default. When running `af sites init`, set the output directory to `dist`. ## Step 1: Create a New Astro Project [#step-1-create-a-new-astro-project] If you do not have a project yet, start from our template or create one from scratch. ### Option A: Use the AF Template (Recommended) [#option-a-use-the-af-template-recommended] ```bash # Clone the AF-optimized Astro template git clone https://github.com/alternatefutures/template-astro my-astro-site cd my-astro-site # Install dependencies npm install ``` ### Option B: Create from Scratch [#option-b-create-from-scratch] ```bash # Create a new Astro project npm create astro@latest my-astro-site cd my-astro-site # Install dependencies npm install ``` When prompted by the Astro CLI, choose your preferred template (blog, portfolio, minimal, etc.). ## Step 2: Verify Static Output [#step-2-verify-static-output] Astro generates static HTML by default, which is exactly what you need for decentralized hosting. Verify your `astro.config.mjs` is set to static output: ```js import { defineConfig } from 'astro/config'; export default defineConfig({ // Static output is the default - no 'output' setting needed // output: 'static', // This is the default // Optional: Set the site URL for canonical links and sitemap site: 'https://my-astro-site.com', // Optional: Set a base path if deploying to a subdirectory // base: '/my-site/', }); ``` If your project uses `output: 'server'` or `output: 'hybrid'`, you will need to change it to `output: 'static'` (or remove the `output` option entirely) for decentralized hosting. Server-rendered pages require a runtime server, which is not available on static hosting. To convert SSR pages to static: * Replace `export const prerender = false` with `export const prerender = true` (or remove it) * Move dynamic data fetching to client-side JavaScript * Use `getStaticPaths()` for dynamic routes ### What Works with Static Astro [#what-works-with-static-astro] | Feature | Supported | Notes | | ------------------------ | --------- | ----------------------------------- | | Static pages (`.astro`) | Yes | Full support | | Markdown/MDX content | Yes | Full support | | Content Collections | Yes | Full support | | View Transitions | Yes | Client-side navigation | | React/Vue/Svelte islands | Yes | Hydration works normally | | `getStaticPaths()` | Yes | Dynamic routes at build time | | Image optimization | Yes | Built-in `` component | | CSS/Tailwind | Yes | Full support | | SSR (`output: 'server'`) | No | Use static output instead | | Server endpoints | No | Use external API or cloud functions | ## Step 3: Build Your Project [#step-3-build-your-project] ```bash # Build the static output npm run build # Preview locally (optional) npm run preview ``` The build output will be in the `./dist` directory. ## Step 4: Authenticate with AF [#step-4-authenticate-with-af] If you have not already authenticated: ```bash # Interactive login (opens browser) af login # Or use a Personal Access Token export AF_TOKEN=pat_your_token_here ``` ## Step 5: Initialize and Deploy [#step-5-initialize-and-deploy] ```bash # Initialize AF site configuration af sites init # When prompted, configure: # Site name: my-astro-site # Build command: npm run build # Output directory: dist # Storage network: ipfs (recommended for getting started) # Deploy to decentralized storage af sites deploy ``` You should see output like: ``` Building site... Uploading files to IPFS... Deployment successful! CID: bafybei... URL: https://ipfs.io/ipfs/bafybei... ``` ## Step 6: Set Up a Custom Domain (Optional) [#step-6-set-up-a-custom-domain-optional] Point your own domain to your deployment: ```bash # Add a custom domain af domains add my-astro-site.com --site my-astro-site ``` Then configure your DNS: | Record Type | Name | Value | | ----------- | ---------- | -------------------------- | | CNAME | `@` | Your AF gateway URL | | TXT | `_dnslink` | `dnslink=/ipfs/` | See [Custom Domains](./custom-domains.md) for detailed DNS configuration. ## Using Astro Integrations [#using-astro-integrations] Astro's integration ecosystem works seamlessly with Alternate Futures. Here are common setups: ### Tailwind CSS [#tailwind-css] ```bash # Add Tailwind integration npx astro add tailwind ``` No additional configuration needed for deployment. ### React Components (Islands) [#react-components-islands] ```bash # Add React integration npx astro add react ``` Use React components as interactive islands within your Astro pages: ```astro --- import Counter from '../components/Counter.tsx'; ---

My Astro Site

``` ### Sitemap [#sitemap] ```bash # Add sitemap integration npx astro add sitemap ``` Make sure to set the `site` property in `astro.config.mjs`: ```js import { defineConfig } from 'astro/config'; import sitemap from '@astrojs/sitemap'; export default defineConfig({ site: 'https://my-astro-site.com', integrations: [sitemap()], }); ``` ## Automating Deployments with CI/CD [#automating-deployments-with-cicd] Deploy automatically on every push using GitHub Actions: ```yaml # .github/workflows/deploy.yml name: Deploy to Alternate Futures on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: npm install - name: Build run: npm run build - name: Deploy to AF run: npx @alternatefutures/cli sites deploy ./dist --network ipfs env: AF_TOKEN: ${{ secrets.AF_TOKEN }} ``` See [CI/CD Integration](./cicd.md) for more providers. ## Using the SDK [#using-the-sdk] Deploy programmatically with the Alternate Futures SDK: ```typescript import { AlternateFuturesSdk, PersonalAccessTokenService } from '@alternatefutures/sdk/node'; const af = new AlternateFuturesSdk({ accessTokenService: new PersonalAccessTokenService({ personalAccessToken: process.env.AF_TOKEN, projectId: process.env.AF_PROJECT_ID, }), }); // Deploy the build output const result = await af.ipfs().add('./dist'); console.log('Deployed! CID:', result.pin.cid); ``` ## Common Issues [#common-issues] ### "Build fails with 'Cannot use import statement outside a module'" [#build-fails-with-cannot-use-import-statement-outside-a-module] Make sure your `package.json` includes `"type": "module"` (Astro requires ESM). ### "Images not loading after deployment" [#images-not-loading-after-deployment] * Use Astro's built-in `` component for optimized images * Make sure image paths are relative, not absolute * If using `public/` folder images, reference them with a leading `/` ```astro --- import { Image } from 'astro:assets'; import myImage from '../assets/hero.png'; --- Hero image Logo ``` ### "Dynamic routes return 404" [#dynamic-routes-return-404] Make sure all dynamic routes use `getStaticPaths()`: ```astro --- // src/pages/blog/[slug].astro export async function getStaticPaths() { const posts = await getCollection('blog'); return posts.map(post => ({ params: { slug: post.slug }, props: { post }, })); } const { post } = Astro.props; ---

{post.data.title}

``` ### "Content Collections not building" [#content-collections-not-building] * Verify your content is in the `src/content/` directory * Check that `src/content/config.ts` defines your collections correctly * Run `astro check` to validate your project ### "Build output is unexpectedly large" [#build-output-is-unexpectedly-large] * Use `astro build --verbose` to see what is being included * Remove unused integrations * Optimize images before adding them to your project * Use Astro's built-in image optimization ## Next Steps [#next-steps] * [Custom Domains](./custom-domains.md) - Connect your own domain * [CI/CD Integration](./cicd.md) - Automate deployments * [Storage Management](./storage.md) - Choose the right storage network * [Deploy Next.js](./deploy-nextjs.md) - Deploy a Next.js app * [Deploy React](./deploy-react.md) - Deploy a React/Vite app # Deploy a Next.js app (/guides/deploy-nextjs) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. Deploy your Next.js application to decentralized infrastructure using Alternate Futures. This guide covers both static export and server-side rendering configurations. ## Prerequisites [#prerequisites] Before you begin, make sure you have: * **An Alternate Futures account** - [Sign up here](https://clouds.alternatefutures.ai) (free, no credit card required) * **The AF CLI installed** - `npm install -g @alternatefutures/cli` * **Node.js 18 or later** - [Download here](https://nodejs.org/en/download) * **A Next.js project** (or we will create one below) ## Quick Deploy (Existing Next.js Project) [#quick-deploy-existing-nextjs-project] If you already have a Next.js project, deploy it in three commands: ```bash # Build the static export npm run build # Initialize AF configuration af sites init # Deploy to IPFS af sites deploy ``` Next.js static export outputs to `./out` by default. When running `af sites init`, set the output directory to `out`. ## Step 1: Create a New Next.js Project [#step-1-create-a-new-nextjs-project] If you do not have a project yet, start from our template or create one from scratch. ### Option A: Use the AF Template (Recommended) [#option-a-use-the-af-template-recommended] ```bash # Clone the AF-optimized Next.js template git clone https://github.com/alternatefutures/template-nextjs my-nextjs-app cd my-nextjs-app # Install dependencies npm install ``` ### Option B: Create from Scratch [#option-b-create-from-scratch] ```bash # Create a new Next.js project npx create-next-app@latest my-nextjs-app cd my-nextjs-app ``` ## Step 2: Configure for Static Export [#step-2-configure-for-static-export] Alternate Futures hosts static sites on decentralized storage. Next.js needs to be configured for static export. Edit your `next.config.js` (or `next.config.mjs`): ```js /** @type {import('next').NextConfig} */ const nextConfig = { output: 'export', // Optional: Change the output directory (default is 'out') // distDir: 'dist', // Optional: Add a trailing slash to all routes trailingSlash: true, // Optional: Disable image optimization (not supported in static export) images: { unoptimized: true, }, }; module.exports = nextConfig; ``` Static export does not support these Next.js features: * Server-Side Rendering (SSR) with `getServerSideProps` * API Routes (`/pages/api/*`) * Middleware * Incremental Static Regeneration (ISR) * Image Optimization (use `unoptimized: true`) If your app uses these features, you will need to refactor to use client-side data fetching or static generation (`getStaticProps`) instead. ### What Works in Static Export [#what-works-in-static-export] | Feature | Supported | Notes | | -------------------- | --------- | ----------------------------------- | | Static pages | Yes | All pages render at build time | | `getStaticProps` | Yes | Data fetched at build time | | `getStaticPaths` | Yes | Dynamic routes with known paths | | Client-side fetching | Yes | `useEffect`, SWR, React Query | | CSS Modules | Yes | Full support | | Tailwind CSS | Yes | Full support | | Next.js App Router | Yes | With `generateStaticParams` | | `next/image` | Partial | Set `unoptimized: true` | | `next/link` | Yes | Client-side navigation works | | `getServerSideProps` | No | Use `getStaticProps` instead | | API Routes | No | Use external API or cloud functions | | Middleware | No | Handle in client or at CDN level | ## Step 3: Build Your Project [#step-3-build-your-project] ```bash # Build the static export npm run build ``` This generates your static site in the `./out` directory. You can preview it locally: ```bash # Preview the build output npx serve out ``` ## Step 4: Authenticate with AF [#step-4-authenticate-with-af] If you have not already authenticated: ```bash # Interactive login (opens browser) af login # Or use a Personal Access Token export AF_TOKEN=pat_your_token_here ``` ## Step 5: Initialize and Deploy [#step-5-initialize-and-deploy] ```bash # Initialize AF site configuration af sites init # When prompted, configure: # Site name: my-nextjs-app # Build command: npm run build # Output directory: out # Storage network: ipfs (recommended for getting started) # Deploy to decentralized storage af sites deploy ``` You should see output like: ``` Building site... Uploading files to IPFS... Deployment successful! CID: bafybei... URL: https://ipfs.io/ipfs/bafybei... ``` ## Step 6: Set Up a Custom Domain (Optional) [#step-6-set-up-a-custom-domain-optional] Point your own domain to your deployment: ```bash # Add a custom domain af domains add my-nextjs-app.com --site my-nextjs-app ``` Then configure your DNS: | Record Type | Name | Value | | ----------- | ---------- | -------------------------- | | CNAME | `@` | Your AF gateway URL | | TXT | `_dnslink` | `dnslink=/ipfs/` | See [Custom Domains](./custom-domains.md) for detailed DNS configuration. ## Automating Deployments with CI/CD [#automating-deployments-with-cicd] Deploy automatically on every push to your main branch using GitHub Actions: ```yaml # .github/workflows/deploy.yml name: Deploy to Alternate Futures on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: npm install - name: Build run: npm run build - name: Deploy to AF run: npx @alternatefutures/cli sites deploy ./out --network ipfs env: AF_TOKEN: ${{ secrets.AF_TOKEN }} ``` See [CI/CD Integration](./cicd.md) for GitLab CI, CircleCI, and other providers. ## Using the SDK [#using-the-sdk] You can also deploy programmatically with the Alternate Futures SDK: ```typescript import { AlternateFuturesSdk, PersonalAccessTokenService } from '@alternatefutures/sdk/node'; const af = new AlternateFuturesSdk({ accessTokenService: new PersonalAccessTokenService({ personalAccessToken: process.env.AF_TOKEN, projectId: process.env.AF_PROJECT_ID, }), }); // Deploy the build output const result = await af.ipfs().add('./out'); console.log('Deployed! CID:', result.pin.cid); ``` ## Common Issues [#common-issues] ### "Error: Image Optimization is not compatible with `output: 'export'`" [#error-image-optimization-is-not-compatible-with-output-export] Add `images: { unoptimized: true }` to your `next.config.js`. See Step 2 above. ### "Error: `getServerSideProps` is not supported with `output: 'export'`" [#error-getserversideprops-is-not-supported-with-output-export] Replace `getServerSideProps` with `getStaticProps` for data that can be fetched at build time, or use client-side fetching with `useEffect` or a library like SWR: ```tsx import useSWR from 'swr'; const fetcher = (url: string) => fetch(url).then(res => res.json()); export default function Page() { const { data, error } = useSWR('/api/data', fetcher); if (error) return
Failed to load
; if (!data) return
Loading...
; return
{data.message}
; } ``` ### "Build output is empty" [#build-output-is-empty] * Verify `output: 'export'` is set in `next.config.js` * Check that your build command is `next build` (not `next start`) * Make sure the `out` directory exists after running `npm run build` ### "404 errors on page refresh" [#404-errors-on-page-refresh] Static exports need trailing slashes for proper routing. Add `trailingSlash: true` to your `next.config.js`. ## Next Steps [#next-steps] * [Custom Domains](./custom-domains.md) - Connect your own domain * [CI/CD Integration](./cicd.md) - Automate deployments * [Storage Management](./storage.md) - Choose the right storage network * [Deploy React](./deploy-react.md) - Deploy a React/Vite app * [Deploy Astro](./deploy-astro.md) - Deploy an Astro site # Deploy a React app (/guides/deploy-react) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. Deploy your React application to decentralized infrastructure using Alternate Futures. This guide covers both Vite-based and Create React App projects. ## Prerequisites [#prerequisites] Before you begin, make sure you have: * **An Alternate Futures account** - [Sign up here](https://clouds.alternatefutures.ai) (free, no credit card required) * **The AF CLI installed** - `npm install -g @alternatefutures/cli` * **Node.js 18 or later** - [Download here](https://nodejs.org/en/download) * **A React project** (or we will create one below) ## Quick Deploy (Existing React Project) [#quick-deploy-existing-react-project] If you already have a React project, deploy it in three commands: ```bash # Build the production bundle npm run build # Initialize AF configuration af sites init # Deploy to IPFS af sites deploy ``` ```bash # Build the production bundle npm run build # Initialize AF configuration (set output directory to 'build') af sites init # Deploy to IPFS af sites deploy ``` * **Vite projects** output to `./dist` by default * **Create React App projects** output to `./build` by default Set the correct directory when running `af sites init`. ## Step 1: Create a New React Project [#step-1-create-a-new-react-project] If you do not have a project yet, start from our template or create one from scratch. ### Option A: Use the AF Template (Recommended) [#option-a-use-the-af-template-recommended] ```bash # Clone the AF-optimized React template git clone https://github.com/alternatefutures/template-react my-react-app cd my-react-app # Install dependencies npm install ``` ### Option B: Create with Vite (Recommended) [#option-b-create-with-vite-recommended] ```bash # Create a new React + Vite project npm create vite@latest my-react-app -- --template react-ts cd my-react-app # Install dependencies npm install ``` ### Option C: Create with Create React App [#option-c-create-with-create-react-app] ```bash # Create a new CRA project npx create-react-app my-react-app --template typescript cd my-react-app # Install dependencies npm install ``` ## Step 2: Configure for Deployment [#step-2-configure-for-deployment] ### Vite Configuration [#vite-configuration] Vite projects work out of the box with Alternate Futures. No additional configuration is needed for basic deployments. If you need a custom base path, edit `vite.config.ts`: ```ts import { defineConfig } from 'vite'; import react from '@vitejs/plugin-react'; export default defineConfig({ plugins: [react()], // Set base path if deploying to a subdirectory // base: '/my-app/', build: { // Output directory (default: 'dist') outDir: 'dist', // Generate source maps for debugging (optional) sourcemap: false, }, }); ``` ### Create React App Configuration [#create-react-app-configuration] CRA projects also work out of the box. If you need a custom base path, set the `homepage` field in `package.json`: ```json { "homepage": ".", "scripts": { "build": "react-scripts build" } } ``` Setting `homepage` to `"."` ensures all asset paths are relative, which is important for IPFS deployments where your site may be served from different gateway URLs. ## Step 3: Build Your Project [#step-3-build-your-project] ```bash # Build the production bundle npm run build # Preview locally (optional) npm run preview ``` ```bash # Build the production bundle npm run build # Preview locally (optional) npx serve build ``` ## Step 4: Authenticate with AF [#step-4-authenticate-with-af] If you have not already authenticated: ```bash # Interactive login (opens browser) af login # Or use a Personal Access Token export AF_TOKEN=pat_your_token_here ``` ## Step 5: Initialize and Deploy [#step-5-initialize-and-deploy] ```bash # Initialize AF site configuration af sites init # When prompted, configure: # Site name: my-react-app # Build command: npm run build # Output directory: dist # Storage network: ipfs # Deploy to decentralized storage af sites deploy ``` ```bash # Initialize AF site configuration af sites init # When prompted, configure: # Site name: my-react-app # Build command: npm run build # Output directory: build # Storage network: ipfs # Deploy to decentralized storage af sites deploy ``` You should see output like: ``` Building site... Uploading files to IPFS... Deployment successful! CID: bafybei... URL: https://ipfs.io/ipfs/bafybei... ``` ## Step 6: Handle Client-Side Routing [#step-6-handle-client-side-routing] If your React app uses React Router (or any client-side routing), you need to handle the case where users navigate directly to a route like `/about`. On a traditional server, this would return a 404 because `/about/index.html` does not exist. ### Solution: Add a 404 Redirect [#solution-add-a-404-redirect] Create a `public/_redirects` file (for Vite) or a `_redirects` file in your `public/` folder (for CRA): ``` /* /index.html 200 ``` This tells the gateway to serve `index.html` for all routes, letting React Router handle the routing. ### Alternative: Use Hash Router [#alternative-use-hash-router] If redirects are not available, switch to `HashRouter`: ```tsx import { HashRouter, Routes, Route } from 'react-router-dom'; function App() { return ( } /> } /> ); } ``` Hash-based URLs (e.g., `/#/about`) work on any static server without configuration. ## Automating Deployments with CI/CD [#automating-deployments-with-cicd] Deploy automatically on every push using GitHub Actions: ```yaml # .github/workflows/deploy.yml name: Deploy to Alternate Futures on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: npm install - name: Build run: npm run build - name: Deploy to AF run: npx @alternatefutures/cli sites deploy ./dist --network ipfs env: AF_TOKEN: ${{ secrets.AF_TOKEN }} ``` See [CI/CD Integration](./cicd.md) for more providers. ## Using the SDK [#using-the-sdk] Deploy programmatically with the Alternate Futures SDK: ```typescript import { AlternateFuturesSdk, PersonalAccessTokenService } from '@alternatefutures/sdk/node'; const af = new AlternateFuturesSdk({ accessTokenService: new PersonalAccessTokenService({ personalAccessToken: process.env.AF_TOKEN, projectId: process.env.AF_PROJECT_ID, }), }); // Deploy the build output const result = await af.ipfs().add('./dist'); console.log('Deployed! CID:', result.pin.cid); ``` ## Environment Variables [#environment-variables] ### Vite [#vite] Vite exposes environment variables prefixed with `VITE_` to your application: ```bash # .env VITE_API_URL=https://api.example.com VITE_APP_TITLE=My App ``` Access them in your code: ```tsx const apiUrl = import.meta.env.VITE_API_URL; ``` ### Create React App [#create-react-app] CRA exposes variables prefixed with `REACT_APP_`: ```bash # .env REACT_APP_API_URL=https://api.example.com REACT_APP_TITLE=My App ``` Access them in your code: ```tsx const apiUrl = process.env.REACT_APP_API_URL; ``` Environment variables prefixed with `VITE_` or `REACT_APP_` are embedded in your build output and visible to anyone who inspects your site. Never put secrets (API keys, tokens) in client-side environment variables. ## Common Issues [#common-issues] ### "Page not found" on route refresh [#page-not-found-on-route-refresh] Your app uses client-side routing but the static server cannot find the route. See the [Handle Client-Side Routing](#step-6-handle-client-side-routing) section above. ### "Build output is too large" [#build-output-is-too-large] * Enable code splitting (Vite does this automatically) * Use `React.lazy()` for route-based code splitting * Analyze your bundle: `npx vite-bundle-visualizer` (Vite) or `npx source-map-explorer build/static/js/*.js` (CRA) * Remove unused dependencies ### "Assets not loading after deployment" [#assets-not-loading-after-deployment] * Make sure `base` in `vite.config.ts` is set to `'/'` or `'./'` * For CRA, set `"homepage": "."` in `package.json` * Check that asset paths are relative, not absolute ### "Blank white page after deployment" [#blank-white-page-after-deployment] * Open the browser console for JavaScript errors * Verify the `index.html` file references the correct bundle paths * Try building with `npm run build` and testing locally with `npx serve dist` before deploying ## Next Steps [#next-steps] * [Custom Domains](./custom-domains.md) - Connect your own domain * [CI/CD Integration](./cicd.md) - Automate deployments * [Storage Management](./storage.md) - Choose the right storage network * [Deploy Next.js](./deploy-nextjs.md) - Deploy a Next.js app * [Deploy Astro](./deploy-astro.md) - Deploy an Astro site # ENS (Ethereum Name Service) (/guides/ens) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. Connect your Alternate Futures sites to Ethereum Name Service (ENS) domains for decentralized, human-readable URLs. ## What is ENS? [#what-is-ens] ENS (Ethereum Name Service) is a distributed, open naming system based on the Ethereum blockchain. It allows you to: * Map human-readable names (like `mysite.eth`) to content hashes * Point ENS domains to your IPFS/IPNS content * Create truly decentralized websites accessible via ENS-compatible browsers ## Prerequisites [#prerequisites] * An ENS domain you own (e.g., purchased from [app.ens.domains](https://app.ens.domains)) * A deployed site with an IPNS record * Access to manage your ENS domain's content hash ## Creating an ENS Record [#creating-an-ens-record] ```bash # Create an ENS record for your site af ens create # You'll be prompted for: # - ENS name (e.g., mysite.eth) # - Site to link # - IPNS record to use ``` ```typescript import { AlternateFuturesSdk } from '@alternatefutures/sdk/node'; const af = new AlternateFuturesSdk({ personalAccessToken: process.env.AF_TOKEN }); // Create an ENS record const ensRecord = await af.ens().create({ name: 'mysite.eth', siteId: 'site-id', ipnsRecordId: 'ipns-record-id' }); console.log('ENS Record created:', ensRecord.name); console.log('Content hash:', ensRecord.ipnsRecord.hash); ``` ## Listing ENS Records [#listing-ens-records] ```bash # List all ENS records af ens list ``` ```typescript // List all ENS records const records = await af.ens().list(); records.forEach(record => { console.log(`${record.name} -> ${record.ipnsRecord.name}`); console.log(`Status: ${record.status}`); }); ``` ## Viewing ENS Record Details [#viewing-ens-record-details] ```bash # Get details for a specific ENS record af ens detail # You'll be prompted to select the ENS record ``` ```typescript // Get ENS record by name const record = await af.ens().getByName({ name: 'mysite.eth' }); console.log('ENS Name:', record.name); console.log('IPNS Name:', record.ipnsRecord.name); console.log('Content Hash:', record.ipnsRecord.hash); console.log('Status:', record.status); ``` ## Verifying ENS Setup [#verifying-ens-setup] After creating an ENS record, you need to manually update your ENS domain's content hash: ```bash # Verify your ENS setup af ens verify # This checks if your ENS domain's content hash # matches the IPNS record from Alternate Futures ``` ```typescript // Get the content hash you need to set const record = await af.ens().getByName({ name: 'mysite.eth' }); console.log('Set your ENS content hash to:', record.ipnsRecord.hash); // The SDK doesn't automatically update ENS // You must do this manually via ENS interface ``` ## Setting Up ENS Content Hash [#setting-up-ens-content-hash] 1. **Get your IPNS hash** from Alternate Futures: ```bash af ens detail # Note the IPNS hash (starts with /ipns/...) ``` 2. **Go to ENS Manager** at [app.ens.domains](https://app.ens.domains) 3. **Find your domain** and click "Set Content Hash" 4. **Paste the IPNS hash** from step 1 5. **Confirm the transaction** on Ethereum 6. **Verify** the setup: ```bash af ens verify ``` ## Deleting an ENS Record [#deleting-an-ens-record] ```bash # Delete an ENS record af ens delete # You'll be prompted to select which ENS record to delete ``` ```typescript // Delete an ENS record await af.ens().delete({ id: 'ens-record-id' }); ``` ## How ENS Integration Works [#how-ens-integration-works] ```mermaid graph LR A[Your Site] --> B[IPFS Deployment] B --> C[IPNS Record] C --> D[ENS Record] D --> E[mysite.eth] E --> F[ENS-Compatible Browser] ``` 1. Your site is deployed to IPFS 2. An IPNS record points to your latest deployment 3. Alternate Futures creates an ENS record linking to the IPNS 4. You update your ENS domain's content hash 5. Users can access your site at `mysite.eth` ## Accessing ENS Sites [#accessing-ens-sites] Users can access your ENS site through: ### ENS-Compatible Browsers [#ens-compatible-browsers] * [Brave Browser](https://brave.com) - Built-in ENS support * [Opera](https://www.opera.com) - Native ENS resolution * [MetaMask](https://metamask.io) - Browser extension with ENS ### ENS Gateways [#ens-gateways] * `https://mysite.eth.link` - Public gateway * `https://mysite.eth.limo` - Alternative gateway ### IPFS Gateways [#ipfs-gateways] Users can also access via IPNS: ``` https://ipfs.io/ipns/your-ipns-name https://gateway.ipfs.io/ipns/your-ipns-name ``` ## Automatic Updates [#automatic-updates] When you deploy new versions of your site: 1. IPFS deployment creates new CID 2. IPNS record automatically updates to point to new CID 3. ENS content hash continues to point to IPNS name 4. Users automatically see latest version at `mysite.eth` No manual ENS updates needed after initial setup! ## Best Practices [#best-practices] * Use IPNS records for dynamic content (regularly updated sites) * Set up ENS during initial site launch for consistent branding * Test access through multiple ENS gateways * Keep your ENS domain registration current * Document your ENS setup for team members ## Troubleshooting [#troubleshooting] ### ENS Verification Fails [#ens-verification-fails] **Problem:** `af ens verify` shows mismatch **Solutions:** * Wait 5-10 minutes for Ethereum blockchain confirmation * Check you pasted the correct IPNS hash * Verify transaction was confirmed on Etherscan * Try clearing your browser cache ### Site Not Loading on ENS [#site-not-loading-on-ens] **Problem:** `mysite.eth` doesn't load in browser **Solutions:** * Confirm browser has ENS support (try Brave) * Use `.eth.link` gateway: `mysite.eth.link` * Check IPNS record is published: `af ipns list` * Verify content hash in ENS manager ### Content Not Updating [#content-not-updating] **Problem:** ENS shows old version of site **Solutions:** * Check IPNS record updated: `af ipns list` * IPNS propagation can take 5-10 minutes * Clear browser cache * Try different ENS gateway ## Next Steps [#next-steps] * [IPNS Records](./ipns.md) - Manage IPNS records * [Sites](./sites.md) - Deploy and manage sites * [Custom Domains](./custom-domains.md) - Use traditional domains # Cloud functions (/guides/functions) Cloud Functions are live in the web app: add a service, pick **Function**, and edit the source right in the dashboard. The `af functions` CLI commands on this page are retired, and `acc services create --kind function` is not wired up yet - use the dashboard until CLI support ships. Deploy serverless edge functions on decentralized infrastructure with Alternate Clouds Functions. ## What are Cloud Functions? [#what-are-cloud-functions] Cloud Functions are serverless compute that runs on the edge, close to your users. They enable: * **API Endpoints** - Create backend APIs without managing servers * **Dynamic Content** - Generate personalized content at the edge * **Data Processing** - Transform and process data on-demand * **Webhooks** - Handle incoming webhook events * **Form Handling** - Process form submissions ## Function Runtime [#function-runtime] Functions run in a secure JavaScript/TypeScript runtime with: * Node.js-compatible APIs * Access to Web APIs (fetch, Request, Response) * Optional SGX (Software Guard Extensions) for enhanced security * Automatic scaling based on demand ## Creating a Function [#creating-a-function] ```bash # Create a new function af functions create --name my-function # Create and attach to a site af functions create --name my-function --site-id ``` ```typescript import { AlternateFuturesSdk } from '@alternatefutures/sdk/node'; const af = new AlternateFuturesSdk({ personalAccessToken: process.env.AF_TOKEN }); // Create a function const func = await af.functions().create({ name: 'my-function', siteId: 'site-id', // optional routes: { '/api/*': 'index.js' // route patterns } }); console.log('Function created:', func.name); console.log('Function ID:', func.id); ``` ## Writing Function Code [#writing-function-code] Create an `index.js` file with your function logic: ```javascript // Simple API endpoint export default async function handler(request) { const url = new URL(request.url); // Handle different routes if (url.pathname === '/api/hello') { return new Response(JSON.stringify({ message: 'Hello from Alternate Futures!' }), { headers: { 'Content-Type': 'application/json' } }); } // Default response return new Response('Not Found', { status: 404 }); } ``` ### Advanced Example [#advanced-example] ```javascript // Function with database and external API export default async function handler(request) { const url = new URL(request.url); // Parse request body if (request.method === 'POST') { const data = await request.json(); // Call external API const response = await fetch('https://api.example.com/data', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(data) }); const result = await response.json(); return new Response(JSON.stringify(result), { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } }); } return new Response('Method Not Allowed', { status: 405 }); } ``` ## Deploying a Function [#deploying-a-function] ```bash # Deploy function code af functions deploy \ --function-id \ --code ./dist # Deploy with SGX security af functions deploy \ --function-id \ --code ./dist \ --sgx # Deploy with assets af functions deploy \ --function-id \ --code ./dist \ --assets ./public ``` ```typescript // First, upload your code to IPFS const codeUpload = await af.uploadProxy().uploadDirectory({ path: './dist' }); // Deploy the function const deployment = await af.functions().deploy({ functionId: 'function-id', cid: codeUpload.pin.cid, sgx: true, // optional: enable SGX blake3Hash: 'hash', // optional: for verification assetsCid: 'assets-cid' // optional: static assets }); console.log('Deployment ID:', deployment.id); ``` ## Listing Functions [#listing-functions] ```bash # List all functions af functions list ``` ```typescript // List all functions const functions = await af.functions().list(); functions.forEach(func => { console.log(`${func.name} (${func.slug})`); console.log(`Status: ${func.status}`); console.log(`URL: https://${func.slug}.af-functions.app`); }); ``` ## Viewing Function Deployments [#viewing-function-deployments] ```bash # List deployments for a function af functions list-deployments --function-id ``` ```typescript // List function deployments const deployments = await af.functions().listDeployments({ functionId: 'function-id' }); deployments.forEach(dep => { console.log(`Deployment ${dep.id}`); console.log(`CID: ${dep.cid}`); console.log(`Created: ${dep.createdAt}`); }); ``` ## Updating a Function [#updating-a-function] ```bash # Update function configuration af functions update \ --function-id \ --name new-name \ --routes '/api/v2/*=handler.js' ``` ```typescript // Update function await af.functions().update({ id: 'function-id', name: 'New Name', routes: { '/api/v2/*': 'handler.js' }, status: 'ACTIVE' // or 'INACTIVE' }); ``` ## Deleting a Function [#deleting-a-function] ```bash # Delete a function af functions delete --function-id ``` ```typescript // Delete a function await af.functions().delete({ id: 'function-id' }); ``` ## Route Configuration [#route-configuration] Functions support flexible route matching: ```typescript { routes: { '/api/*': 'api.js', // Wildcard matching '/users/:id': 'users.js', // Path parameters '/blog/**': 'blog.js', // Recursive wildcard '/exact': 'exact.js' // Exact match } } ``` ## Environment Variables [#environment-variables] Set environment variables for your functions: ```javascript export default async function handler(request) { const apiKey = process.env.API_KEY; const dbUrl = process.env.DATABASE_URL; // Use environment variables const response = await fetch('https://api.example.com', { headers: { 'Authorization': `Bearer ${apiKey}` } }); return new Response(await response.text()); } ``` Set variables during deployment or in your build process. ## SGX (Software Guard Extensions) [#sgx-software-guard-extensions] Enable SGX for enhanced security and privacy: ```bash af functions deploy \ --function-id \ --code ./dist \ --sgx ``` SGX provides: * **Encrypted Execution** - Code runs in encrypted memory * **Attestation** - Verify code hasn't been tampered with * **Confidential Computing** - Protect sensitive data during processing ## Function URLs [#function-urls] Access your functions via: * **Default URL**: `https://.af-functions.app` * **Custom Domain**: Configure custom domains for your functions * **Site Integration**: Mount functions on specific routes within your site ## Use Cases [#use-cases] ### API Backend [#api-backend] ```javascript // REST API endpoint export default async function handler(request) { const url = new URL(request.url); const id = url.searchParams.get('id'); const data = await fetchFromDatabase(id); return new Response(JSON.stringify(data), { headers: { 'Content-Type': 'application/json' } }); } ``` ### Form Processing [#form-processing] ```javascript // Contact form handler export default async function handler(request) { if (request.method !== 'POST') { return new Response('Method Not Allowed', { status: 405 }); } const formData = await request.formData(); const email = formData.get('email'); const message = formData.get('message'); // Send email or store in database await sendEmail({ to: 'contact@example.com', email, message }); return new Response(JSON.stringify({ success: true }), { headers: { 'Content-Type': 'application/json' } }); } ``` ### Image Processing [#image-processing] ```javascript // Dynamic image resizing export default async function handler(request) { const url = new URL(request.url); const imageUrl = url.searchParams.get('url'); const width = url.searchParams.get('width'); const response = await fetch(imageUrl); const image = await response.arrayBuffer(); // Resize image const resized = await resizeImage(image, { width }); return new Response(resized, { headers: { 'Content-Type': 'image/jpeg' } }); } ``` ### Authentication Middleware [#authentication-middleware] ```javascript // JWT authentication export default async function handler(request) { const token = request.headers.get('Authorization')?.split(' ')[1]; if (!token) { return new Response('Unauthorized', { status: 401 }); } try { const user = await verifyToken(token); return new Response(JSON.stringify({ user }), { headers: { 'Content-Type': 'application/json' } }); } catch (error) { return new Response('Invalid Token', { status: 401 }); } } ``` ## Best Practices [#best-practices] * **Keep functions small** - One function per route or feature * **Use caching** - Cache responses when possible * **Handle errors** - Always return appropriate status codes * **Set CORS headers** - Allow cross-origin requests when needed * **Monitor performance** - Track function execution time and errors * **Use environment variables** - Never hardcode secrets ## Performance Tips [#performance-tips] 1. **Minimize dependencies** - Only import what you need 2. **Use streaming** - Stream large responses 3. **Cache responses** - Set appropriate Cache-Control headers 4. **Optimize cold starts** - Keep initialization code minimal 5. **Use edge caching** - Leverage CDN caching ## Troubleshooting [#troubleshooting] ### Function Not Responding [#function-not-responding] **Problem:** Function returns 500 or times out **Solutions:** * Check function logs for errors * Verify all dependencies are included * Test function locally first * Check external API availability ### CORS Errors [#cors-errors] **Problem:** Browser blocks requests to function with errors like: * "Access to fetch has been blocked by CORS policy" * "No 'Access-Control-Allow-Origin' header is present" * "CORS preflight request failed" **What is CORS?** CORS (Cross-Origin Resource Sharing) is a security feature that browsers use to prevent websites from making requests to different domains without permission. When your web app (e.g., `myapp.com`) tries to call your function (e.g., `function.af-functions.app`), the browser blocks it unless your function explicitly allows it. **Solution 1: Basic CORS Headers** Add CORS headers to all responses: ```javascript export default async function handler(request) { const data = { message: 'Hello' }; return new Response(JSON.stringify(data), { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', // Allow all origins 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization' } }); } ``` **Solution 2: Handle Preflight Requests** Browsers send an OPTIONS request before the actual request (called "preflight"). You must handle this: ```javascript export default async function handler(request) { // Handle preflight requests if (request.method === 'OPTIONS') { return new Response(null, { status: 204, headers: { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization', 'Access-Control-Max-Age': '86400', // Cache preflight for 24 hours } }); } // Handle actual request const data = { message: 'Hello' }; return new Response(JSON.stringify(data), { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization' } }); } ``` **Solution 3: Specific Origin (Recommended for Production)** Instead of allowing all origins (`*`), specify your domain: ```javascript const allowedOrigins = [ 'https://myapp.com', 'https://staging.myapp.com', 'http://localhost:3000' // For development ]; export default async function handler(request) { const origin = request.headers.get('Origin'); const corsHeaders = { 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization', }; // Check if origin is allowed if (origin && allowedOrigins.includes(origin)) { corsHeaders['Access-Control-Allow-Origin'] = origin; } // Handle preflight if (request.method === 'OPTIONS') { return new Response(null, { status: 204, headers: corsHeaders }); } // Handle actual request const data = { message: 'Hello' }; return new Response(JSON.stringify(data), { headers: { 'Content-Type': 'application/json', ...corsHeaders } }); } ``` **Solution 4: Helper Function** Create a reusable helper: ```javascript function corsResponse(body, options = {}) { return new Response(body, { ...options, headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS', 'Access-Control-Allow-Headers': 'Content-Type, Authorization', ...options.headers } }); } export default async function handler(request) { if (request.method === 'OPTIONS') { return corsResponse(null, { status: 204 }); } const data = { message: 'Hello' }; return corsResponse(JSON.stringify(data)); } ``` **Common CORS Headers Explained:** * `Access-Control-Allow-Origin`: Which domains can access your function * `*` = all domains (use for public APIs) * `https://myapp.com` = specific domain (use for private APIs) * `Access-Control-Allow-Methods`: Which HTTP methods are allowed (GET, POST, etc.) * `Access-Control-Allow-Headers`: Which headers the client can send * `Access-Control-Max-Age`: How long (in seconds) to cache the preflight response For production, always specify exact origins instead of using `*`. This prevents unauthorized websites from calling your functions. ### Slow Performance [#slow-performance] **Problem:** Function execution is slow **Solutions:** * Optimize database queries * Add caching layer * Reduce payload size * Use connection pooling ## Next Steps [#next-steps] * [Sites](./sites.md) - Deploy static sites * [Storage](./storage.md) - Store function data * [Custom Domains](./custom-domains.md) - Add custom domains * [Best Practices](./best-practices.md) - Optimization tips # Private gateways (/guides/gateways) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. Create dedicated IPFS gateways with custom domains for fast, reliable access to your decentralized content. ## What are Private Gateways? [#what-are-private-gateways] Private Gateways are dedicated IPFS gateway infrastructure that provides: * **Custom Domains** - Access content via your own domain * **Enhanced Performance** - Dedicated resources for faster loading * **CDN Integration** - Global edge caching * **Access Control** - Restrict who can access your content * **Custom Configuration** - Configure caching, headers, and more ## Why Use Private Gateways? [#why-use-private-gateways] ### Public Gateways vs Private Gateways [#public-gateways-vs-private-gateways] **Public Gateways:** * Shared infrastructure * Rate limited * Generic domains (ipfs.io, dweb.link) * Best for: Testing, public content **Private Gateways:** * Dedicated resources * No rate limits * Custom domains * Enhanced security * Best for: Production applications, branded experiences ## Creating a Private Gateway [#creating-a-private-gateway] ```bash # Create a new private gateway af gateways create # You'll be prompted for: # - Gateway name # - Zone/Domain to use ``` ```typescript import { AlternateFuturesSdk } from '@alternatefutures/sdk/node'; const af = new AlternateFuturesSdk({ personalAccessToken: process.env.AF_TOKEN }); // Create a private gateway const gateway = await af.privateGateway().create({ name: 'My Gateway', zoneId: 'zone-id' // DNS zone for your domain }); console.log('Gateway created:', gateway.name); console.log('Gateway slug:', gateway.slug); ``` ## Listing Gateways [#listing-gateways] ```bash # List all private gateways af gateways list ``` ```typescript // List all gateways const gateways = await af.privateGateway().list(); gateways.forEach(gw => { console.log(`${gw.name} (${gw.slug})`); console.log(`Zone: ${gw.zone.id}`); }); ``` ## Viewing Gateway Details [#viewing-gateway-details] ```bash # Get details for a specific gateway af gateways detail # You'll be prompted to select the gateway ``` ```typescript // Get gateway by ID const gateway = await af.privateGateway().get({ id: 'gateway-id' }); console.log('Name:', gateway.name); console.log('Slug:', gateway.slug); console.log('Created:', gateway.createdAt); // Get gateway by slug const gatewayBySlug = await af.privateGateway().getBySlug({ slug: 'my-gateway' }); ``` ## Updating a Gateway [#updating-a-gateway] ```bash # Update gateway configuration af gateways update # You'll be prompted to: # 1. Select the gateway # 2. Enter new name ``` ```typescript // Update gateway await af.privateGateway().update({ id: 'gateway-id', name: 'Updated Gateway Name' }); ``` ## Deleting a Gateway [#deleting-a-gateway] ```bash # Delete a gateway af gateways delete # You'll be prompted to select which gateway to delete ``` ```typescript // Delete a gateway await af.privateGateway().delete({ id: 'gateway-id' }); ``` ## Setting Up Custom Domain [#setting-up-custom-domain] After creating a gateway, configure a custom domain: ### 1. Add DNS Records [#1-add-dns-records] Add a CNAME record pointing to your gateway: ``` Type: CNAME Name: gateway (or @) Value: .af-gateway.app TTL: 3600 ``` ### 2. Create Domain in Alternate Futures [#2-create-domain-in-alternate-futures] ```bash af domains create \ --hostname gateway.yourdomain.com \ --gateway-id ``` ### 3. Verify Domain [#3-verify-domain] ```bash af domains verify --domain-id ``` ## Accessing Content Through Gateway [#accessing-content-through-gateway] Once configured, access your IPFS content via: ### By CID [#by-cid] ``` https://gateway.yourdomain.com/ipfs/ ``` ### By IPNS [#by-ipns] ``` https://gateway.yourdomain.com/ipns/ ``` ### With Path [#with-path] ``` https://gateway.yourdomain.com/ipfs//path/to/file.html ``` ## Gateway Configuration [#gateway-configuration] ### Caching Strategy [#caching-strategy] Private gateways automatically cache content with: * **Edge Caching** - Content cached at CDN edge nodes globally * **Smart Invalidation** - Automatic cache updates for new versions * **Custom TTL** - Configure cache duration per content type ### Custom Headers [#custom-headers] Configure custom headers for your gateway: ```javascript // Example: Configure CORS headers { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Methods': 'GET, HEAD', 'Cache-Control': 'public, max-age=31536000', 'X-Content-Type-Options': 'nosniff' } ``` ### Access Control [#access-control] Restrict access to your gateway: * **IP Allowlist** - Only allow specific IP addresses * **Token Authentication** - Require authentication tokens * **Geo-Blocking** - Restrict by geographic location * **Rate Limiting** - Custom rate limits per user/IP ## Use Cases [#use-cases] ### E-Commerce Site [#e-commerce-site] ``` - Gateway: shop.mystore.com - Content: IPFS-hosted product images and assets - Benefit: Fast, reliable asset delivery worldwide ``` ### NFT Marketplace [#nft-marketplace] ``` - Gateway: assets.nftmarket.io - Content: NFT images, metadata, and media - Benefit: Decentralized, censorship-resistant hosting ``` ### Video Platform [#video-platform] ``` - Gateway: cdn.myvideos.com - Content: Video files and thumbnails on IPFS - Benefit: Distributed streaming, reduced bandwidth costs ``` ### Documentation Site [#documentation-site] ``` - Gateway: docs.myapp.com - Content: Documentation deployed to IPFS - Benefit: Immutable versions, always available ``` ## Performance Optimization [#performance-optimization] ### 1. Enable Compression [#1-enable-compression] Private gateways automatically compress content: * Gzip compression for text files * Brotli compression for modern browsers * Smart compression based on content type ### 2. Image Optimization [#2-image-optimization] Optimize images served through your gateway: * WebP conversion for supported browsers * Automatic resizing based on request * Lazy loading support ### 3. Preloading [#3-preloading] Preload frequently accessed content: ```bash # Pin content to your gateway af storage pin --gateway-id ``` ### 4. CDN Distribution [#4-cdn-distribution] Content is automatically distributed to edge nodes: * 200+ global edge locations * Automatic routing to nearest node * DDoS protection included ## Monitoring [#monitoring] ### Gateway Analytics [#gateway-analytics] Track gateway performance: * Request volume * Bandwidth usage * Cache hit rates * Geographic distribution * Top content (by requests) ### Performance Metrics [#performance-metrics] Monitor key metrics: * Average response time * P95/P99 latency * Error rates * Availability (uptime) ## Security [#security] ### HTTPS/TLS [#httpstls] All private gateways include: * Automatic TLS certificates * Certificate auto-renewal * TLS 1.3 support * HSTS (HTTP Strict Transport Security) ### DDoS Protection [#ddos-protection] Built-in DDoS protection: * Rate limiting * Traffic analysis * Automatic blocking * Custom rules ### Content Integrity [#content-integrity] Ensure content integrity: * Cryptographic verification of CIDs * Immutability guarantees * Origin authentication ## Troubleshooting [#troubleshooting] ### Gateway Not Accessible [#gateway-not-accessible] **Problem:** Cannot access gateway URL **Solutions:** * Verify DNS records are configured correctly * Check domain verification status * Ensure gateway is in active state * Wait for DNS propagation (up to 48 hours) ### Slow Response Times [#slow-response-times] **Problem:** Gateway responds slowly **Solutions:** * Check if content is pinned to gateway * Verify CDN cache is populated * Monitor bandwidth usage * Consider pre-warming cache for popular content ### Custom Domain Not Working [#custom-domain-not-working] **Problem:** Custom domain shows error **Solutions:** * Verify CNAME record is correct * Check domain verification in dashboard * Ensure TLS certificate is issued * Try accessing via default gateway URL first ## Best Practices [#best-practices] * **Use custom domains** - Professional branding and user trust * **Enable caching** - Maximize cache hit rates for better performance * **Monitor usage** - Track bandwidth and request patterns * **Pin popular content** - Pre-load frequently accessed files * **Set up alerts** - Get notified of issues or unusual traffic * **Regular testing** - Verify gateway performance periodically ## Pricing [#pricing] Private gateways include: * Dedicated infrastructure * Unlimited bandwidth (fair use) * Custom domain support * CDN distribution * DDoS protection * 99.9% uptime SLA ## Next Steps [#next-steps] * [Custom Domains](./custom-domains.md) - Configure custom domains * [Storage](./storage.md) - Manage IPFS content * [Sites](./sites.md) - Deploy sites to IPFS * [Best Practices](./best-practices.md) - Optimization tips # Glossary (/guides/glossary) This page is a reference: short definitions of the terms used in these docs, in alphabetical order. Terms from the retired `af` CLI (IPFS sites, IPNS, ENS, Filecoin, Arweave, functions) are covered in [Retired af CLI guides](/legacy). ### Access token [#access-token] A personal access token (PAT) that authenticates as you without a browser. Used by CI, scripts, agents, and the SDK. Created with `acc pat create`, passed as `AF_TOKEN`. See [Create and use access tokens](/guides/api-keys). ### Active project [#active-project] The project the CLI acts on. Shown by `acc whoami`, changed with `acc projects switch`, overridden by `AF_PROJECT_ID`. ### Admin [#admin] An organization role that can deploy and manage members but not billing. See [Roles](/guides/account-model#roles). ### Attestation [#attestation] Cryptographic proof, produced by the hardware, of exactly what code a confidential service is running. Fetch and verify it with `acc attest`. ### Auto stop [#auto-stop] A spend control that stops a service after a fixed runtime (`--stop-hours`, `--stop-days`). The projected cost is reserved from your balance up front. ### Bid [#bid] A provider's offer to run your deployment at a price. A new deployment waits for bids, then the platform selects one. ### Budget cap [#budget-cap] A spend control that stops a service when its total (`--budget-total`) or monthly (`--budget-monthly`) spend reaches the cap. ### Confidential compute [#confidential-compute] Running a service inside a trusted execution environment (TEE) so that nobody, including the provider, can read its memory. Enabled with `--confidential`. ### Credits [#credits] Prepaid US dollars in an organization's wallet, spent as services run. Topped up by card or stablecoin. See [How billing works](/guides/how-billing-works). ### Custom domain [#custom-domain] Your own domain name pointed at a service instead of the default `-app.alternatefutures.ai` URL. In early access; see [Custom domains](/guides/custom-domains). ### Decentralized registry [#decentralized-registry] A self-hosted, OCI-compatible container registry that stores image layers on IPFS and runs on decentralized compute you operate. See [Decentralized container registry](/guides/decentralized-registry). ### Deployment [#deployment] One release of a service. Redeploying creates a new deployment; the previous one is closed. Listed with `acc deployments`. ### Docker image [#docker-image] A packaged application that a service runs, named like `nginx:1.27`. Use a versioned tag; providers cache images by tag. ### Environment variable [#environment-variable] A configuration value passed to a running service, such as an API key. Set with `--env KEY=VALUE` or `acc services env set`. ### GPU [#gpu] A graphics processor attached to a service for inference or training, chosen by model and count (`--gpu-model h100 --gpu-count 1`). Billed by the hour. ### IPFS [#ipfs] The InterPlanetary File System, a content-addressed storage network. Used by the decentralized registry to store image layers. ### Member [#member] An organization role that can deploy and view. A member can be limited to selected projects. ### OCI [#oci] The Open Container Initiative, the standard for container images and registries. Standard Docker tools work with anything OCI-compatible. ### Organization [#organization] The owner of billing, credits, and members. Every account has a personal organization; teams are additional organizations. See [Accounts, organizations, and projects](/guides/account-model). ### Owner [#owner] The organization role with full control, including billing and deleting the organization. ### Pay as you go [#pay-as-you-go] The default spend control: no cap, pay for what you use. ### Project [#project] A workspace that groups related services inside an organization. See [Manage projects](/guides/projects). ### Provider [#provider] An independent operator that runs your workloads. The platform picks one for each deployment based on region, resources, and price. ### Region [#region] Where a service runs: `us-east`, `us-west`, `eu`, `asia`, or Any (cheapest available). `acc regions` shows availability and pricing. ### Seat [#seat] The unit a subscription is priced in, one per person in the organization. ### Service [#service] One deployed thing: a container from a Docker image, a template instance, or an empty server. Holds region, resources, environment variables, spend controls, and a URL. Managed with `acc services`. ### Service link [#service-link] A connection between two services in the same project that exposes the target's address to the source as environment variables. Created with `acc services link`. ### Slug [#slug] The short name in a service's URL, `https://-app.alternatefutures.ai`. ### Spend control [#spend-control] A per-service limit, enforced by the platform: pay as you go, budget cap, or auto stop. ### Subscription [#subscription] The monthly or yearly plan an organization pays per seat. It sets the markup applied to usage. See [How billing works](/guides/how-billing-works). ### Suspended [#suspended] A service paused because the organization's credits ran low. It resumes automatically after a topup. ### TEE [#tee] Trusted execution environment: a hardware-isolated part of a processor whose memory the host cannot read. The basis of confidential compute. ### Template [#template] A ready-made service definition (an AI agent, a database, an inference server) that you deploy with a few settings. Browse with `acc templates list`. ### Trial [#trial] The first 14 days of a new account, with deploys allowed and no card required. ### Wallet [#wallet] Two meanings: the organization's **credit wallet** that pays for usage, and an **Ethereum wallet** you can sign in with instead of an email. # How billing works (/guides/how-billing-works) This page explains the billing model. For the steps (top up, change plan, set a budget), see [Manage billing and credits](/guides/billing). ## Two parts: a plan and a wallet [#two-parts-a-plan-and-a-wallet] Billing is per organization and has two parts. * **Subscription.** A monthly or yearly plan, priced per seat. It is the base fee for the platform and sets the markup applied to your usage. * **Credit wallet.** Prepaid credits in US dollars. Everything you run is metered and paid from this wallet while it runs. The split keeps the fixed part predictable and the variable part prepaid: you can never be surprised by a bill larger than what you put in the wallet. ## Trial and signup credit [#trial-and-signup-credit] * Every new account starts a **14-day trial**. No card is needed, and you can deploy during the trial. * When the trial ends you have a short grace period of three days to choose a plan. After that you cannot deploy until you subscribe. * Signing up with a verified email adds a **one-time signup credit** to your wallet. If you signed up with a wallet address, you receive it when you add and verify an email in **Account settings**. ## What usage costs [#what-usage-costs] Usage is billed at what the provider charges plus your plan's markup. Yearly plans carry a lower markup than monthly plans, and each line on your usage page shows both the raw cost and what you were charged. * Compute is metered per hour of running time for each service. GPU and confidential (TEE) services are priced by the provider the same way. * Prices differ by region and by GPU model. `acc regions` shows current availability and pricing before you deploy. * Closing a service stops its charges. A service that is failed or closed does not bill. ## Paying [#paying] * **Subscriptions** are paid by card, or funded from your credit wallet if you prefer not to use a card. * **Credits** are topped up by card in the web app, or with a stablecoin transfer (USDC, USDT, or DAI on Base, Ethereum, Arbitrum, Optimism, or Polygon) from the web app or the CLI. ## When the wallet runs low [#when-the-wallet-runs-low] Two server-side safeguards protect the shared wallet: 1. **Before a deploy**, the platform checks that your balance covers at least one hour of everything you would then be running (and at least one dollar). If not, the deploy is refused and you are asked to top up. 2. **While services run**, if the balance falls below roughly one hour of total spend, services are **suspended** one at a time until the rest are covered. Suspended services are not deleted. They **resume automatically** after a topup. ## Spend controls per service [#spend-controls-per-service] Each service can carry its own limit, set when you create or deploy it and enforced by the platform rather than by your local machine: | Mode | What it does | Flags | | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | | **Pay as you go** | No limit. The default. | `--spend payg` | | **Budget cap** | Stops the service when its total or monthly spend reaches the cap. A monthly cap that the projected cost already exceeds is refused before launch. | `--budget-total `, `--budget-monthly ` | | **Auto stop** | Stops the service after a fixed runtime. The full projected cost is reserved from your balance up front. | `--stop-hours `, `--stop-days ` | When a service stops, the reason is recorded: budget exceeded, runtime expired, balance low, or manual stop. ## Who can see billing [#who-can-see-billing] Owners and admins of an organization see the **Billing** page in the web app: usage, payments, invoices, plans, and the credits wallet. Members can deploy but do not see billing. ## Next steps [#next-steps] * [Manage billing and credits](/guides/billing) * [Accounts, organizations, and projects](/guides/account-model) * [Command reference: billing](/cli/commands#billing) # What is Alternate Clouds? (/guides) Alternate Clouds runs your software on **decentralized infrastructure**. Instead of renting servers from one company, your workloads run on a network of independent providers, matched to what each service needs (general compute, confidential computing, GPUs), through one account, one bill, and one set of tools. You do not need to know anything about crypto or blockchains to use it. Sign in with an email address, pay by card, and deploy. ## What you can run [#what-you-can-run] * **Containers.** Any Docker image, with a public URL, environment variables, logs, and shell access. * **Apps and AI agents from templates.** One-click templates for agents, databases, inference servers, and more. * **GPU workloads.** GPUs billed by the hour for inference and training. * **Confidential services.** Add `--confidential` to run inside a trusted execution environment (TEE) with remote attestation, so nobody, including the provider, can read your data. ## Three ways to use it [#three-ways-to-use-it] | | Best for | | ------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ | | **Web app** at [clouds.alternatefutures.ai](https://clouds.alternatefutures.ai) | Deploying from templates, watching services, managing billing and team members. See the [Web app overview](/guides/dashboard). | | **CLI** (`acc`) | Day-to-day work from a terminal, scripts, and CI. See [Install the CLI](/cli/installation). | | **SDK** | Building the platform into your own product. See the [SDK overview](/sdk). | AI agents can drive all three. See [Docs for AI agents](/ai-agents). ## How billing works [#how-billing-works] Every account starts with a 14-day free trial, no card required. After that you pay a monthly or yearly subscription plus prepaid credits that are spent as your services run. Set a budget to cap spend. The model is explained in [How billing works](/guides/how-billing-works); the tasks are in [Manage billing and credits](/guides/billing). ## Key terms [#key-terms] * **Project.** A workspace for related services and the people who manage them. * **Service.** One deployed thing: a container, a template, a GPU job. * **Deployment.** A single release of a service. Redeploying creates a new one. * **Region.** Where a service runs: `us-east`, `us-west`, `eu`, `asia`, or Any. How these fit together is in [Accounts, organizations, and projects](/guides/account-model); more terms are in the [glossary](/guides/glossary). ## Next steps [#next-steps] Deploy your first service in about five minutes. Email or wallet sign-in, and tokens for the CLI and SDK. Organize services and invite your team. Every acc command and flag. # IPNS (InterPlanetary Name System) (/guides/ipns) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. Use IPNS to create mutable pointers to your IPFS content, enabling dynamic updates without changing URLs. ## What is IPNS? [#what-is-ipns] IPNS (InterPlanetary Name System) is a system for creating mutable pointers to IPFS content. While IPFS content is immutable (CID changes with each update), IPNS provides: * **Stable URLs** - Same IPNS name for all versions of your content * **Dynamic Updates** - Update content without changing the link * **Human-Readable Names** - Can be linked with ENS domains * **Decentralized** - No central authority required ## How IPNS Works [#how-ipns-works] ```mermaid graph LR A[IPNS Name] --> B[Latest CID] B --> C[IPFS Content v3] D[Old CID v2] -.-> A E[Old CID v1] -.-> A ``` * IPNS name stays constant: `/ipns/k51qzi5uqu5di...` * Points to current CID: `Qm...` or `bafy...` * Update by publishing new CID to same IPNS name * Old versions still accessible via their CIDs ## Creating an IPNS Record [#creating-an-ipns-record] ```bash # Create IPNS record for a site af ipns create --site-id # The IPNS record will automatically point to # the site's latest deployment ``` ```typescript import { AlternateFuturesSdk } from '@alternatefutures/sdk/node'; const af = new AlternateFuturesSdk({ personalAccessToken: process.env.AF_TOKEN }); // Create IPNS record for a site const ipnsRecord = await af.ipns().createRecordForSite({ siteId: 'site-id' }); console.log('IPNS Name:', ipnsRecord.name); console.log('Current Hash:', ipnsRecord.hash); ``` ## Listing IPNS Records [#listing-ipns-records] ```bash # List all IPNS records af ipns list ``` ```typescript // List all IPNS records const records = await af.ipns().listRecords(); records.forEach(record => { console.log(`Name: ${record.name}`); console.log(`Hash: ${record.hash}`); console.log(`ID: ${record.id}`); }); ``` ## Publishing Updates [#publishing-updates] When you deploy a new version of your site, the IPNS record automatically updates to point to the new content. You can also manually publish a new hash: ```bash # Publish new content to IPNS record af ipns publish \ --ipns-id \ --hash ``` ```typescript // Publish new content to IPNS await af.ipns().publishRecord({ id: 'ipns-record-id', hash: 'QmNewContentHash...' }); ``` ## Resolving IPNS Names [#resolving-ipns-names] Check what content an IPNS name currently points to: ```bash # Resolve IPNS name to current CID af ipns resolve --name ``` ```typescript // Resolve IPNS name const resolved = await af.ipns().resolveName({ name: '/ipns/k51qzi5uqu5di...' }); console.log('Current CID:', resolved); ``` ## Deleting an IPNS Record [#deleting-an-ipns-record] ```bash # Delete an IPNS record af ipns delete --ipns-id ``` ```typescript // Delete IPNS record await af.ipns().deleteRecord({ id: 'ipns-record-id' }); ``` ## Accessing Content via IPNS [#accessing-content-via-ipns] Access your content through IPNS: ### Public IPFS Gateways [#public-ipfs-gateways] ``` https://ipfs.io/ipns/ https://dweb.link/ipns/ https://cloudflare-ipfs.com/ipns/ ``` ### Alternate Futures Gateway [#alternate-futures-gateway] ``` https://ipfs.alternatefutures.ai/ipns/ ``` ### Private Gateway [#private-gateway] If you have a private gateway: ``` https://your-gateway.com/ipns/ ``` ### ENS Integration [#ens-integration] Link your IPNS to ENS: ``` https://yoursite.eth https://yoursite.eth.link https://yoursite.eth.limo ``` ## Automatic Updates [#automatic-updates] IPNS records automatically update when you deploy: ```bash # Deploy new version of site af sites deploy ./dist --site-id # IPNS record automatically updates to new CID # Users accessing /ipns/ see new version ``` The flow: 1. Deploy creates new IPFS CID 2. Deployment completes successfully 3. Site's IPNS record updated to new CID 4. Propagation across IPFS network (1-2 minutes) 5. Users see updated content ## Use Cases [#use-cases] ### Website Hosting [#website-hosting] ``` - Deploy: yoursite.com → IPNS → IPFS - Update: New deployment updates IPNS automatically - Benefit: Consistent URL, dynamic content ``` ### NFT Metadata [#nft-metadata] ``` - Mint NFT with IPNS URI - Update metadata without changing token - Benefit: Evolving NFTs, dynamic attributes ``` ### Documentation [#documentation] ``` - Docs at /ipns/ - Update docs frequently - Benefit: Latest version always at same URL ``` ### App Updates [#app-updates] ``` - dApp hosted on IPNS - Push updates by deploying new version - Benefit: Users always get latest version ``` ## IPNS vs Direct IPFS [#ipns-vs-direct-ipfs] | Feature | IPFS (CID) | IPNS (Name) | | --------------- | ------------------------- | ---------------------- | | **Mutability** | Immutable | Mutable pointer | | **URL Changes** | Yes (new CID each update) | No (same name) | | **Speed** | Instant | 1-2 min propagation | | **Caching** | Aggressive | Limited | | **Best For** | Archives, versioning | Dynamic content, sites | ## IPNS + ENS [#ipns--ens] Combine IPNS with ENS for best of both worlds: ``` yoursite.eth → IPNS Name → Latest IPFS CID ``` Benefits: * Human-readable domain (yoursite.eth) * Automatic updates (IPNS) * Decentralized hosting (IPFS) * One-time ENS setup Setup: 1. Create IPNS record for site 2. Create ENS record pointing to IPNS 3. Set ENS content hash (one time) 4. All future updates via IPNS automatically ## Performance Considerations [#performance-considerations] ### Propagation Time [#propagation-time] IPNS updates take time to propagate: * **Initial publish**: 1-2 minutes * **Subsequent updates**: 30-60 seconds * **Global propagation**: 2-5 minutes ### Caching [#caching] IPNS caching is limited compared to IPFS: * IPFS CIDs: Cached indefinitely * IPNS names: Short TTL (minutes) * Impact: More network lookups for IPNS ### Optimization [#optimization] Improve IPNS performance: 1. **Use private gateway** - Faster resolution 2. **Pre-warm caches** - Access content after publishing 3. **Monitor propagation** - Check resolution before announcing 4. **Combine with CDN** - Cache at application level ## Troubleshooting [#troubleshooting] ### IPNS Resolution Fails [#ipns-resolution-fails] **Problem:** Cannot resolve IPNS name **Solutions:** * Wait 2-3 minutes for propagation * Try different gateway * Verify IPNS record exists: `af ipns list` * Check network connectivity to IPFS ### Old Content Still Showing [#old-content-still-showing] **Problem:** IPNS shows old version **Solutions:** * Clear browser cache * Wait for propagation (2-5 minutes) * Verify publish succeeded: `af ipns resolve` * Try different IPFS gateway ### Slow Resolution [#slow-resolution] **Problem:** IPNS resolution takes long **Solutions:** * Use private gateway instead of public * Pre-fetch content after publishing * Consider caching layer in application * Check IPFS daemon health ## Advanced: Custom IPNS Keys [#advanced-custom-ipns-keys] For advanced users who want to manage their own IPNS keys: ```bash # Generate IPNS key locally ipfs key gen my-site # Publish with custom key ipfs name publish --key=my-site # Import key to Alternate Futures (contact support) ``` ## Best Practices [#best-practices] * **Use IPNS for sites** - Dynamic content that updates regularly * **Use direct CIDs for archives** - Immutable content that never changes * **Combine with ENS** - Get human-readable domains * **Monitor propagation** - Check updates went through * **Cache at app level** - Don't rely solely on IPFS caching * **Set up monitoring** - Track IPNS resolution times ## IPNS Name Format [#ipns-name-format] IPNS names are cryptographic hashes: ``` CIDv0 (older): QmYwAPJzv5CZsnA625s3Xf2nemtYgPpHdWEz79ojWnPbdG CIDv1 (newer): k51qzi5uqu5dgy83yw82... ``` Names are derived from: * Public key (for self-certifying names) * Or from peer ID * Verifiable cryptographically ## Comparison with Traditional DNS [#comparison-with-traditional-dns] | Feature | DNS | IPNS | | -------------- | ---------------------- | ----------------------------- | | **Control** | Centralized registrars | Decentralized, self-sovereign | | **Censorship** | Possible | Resistant | | **Cost** | Annual fees | Network costs only | | **Speed** | Fast (\<100ms) | Slower (seconds) | | **Setup** | Domain purchase | Key generation | ## Next Steps [#next-steps] * [ENS Integration](./ens.md) - Link IPNS with ENS domains * [Sites](./sites.md) - Deploy sites with IPNS * [Private Gateways](./gateways.md) - Faster IPNS resolution * [Storage](./storage.md) - Manage IPFS content # Migrate from Fleek (/guides/migrate-from-fleek) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. Fleek has pivoted away from Web3 hosting to focus on AI inference. If you have sites, storage, or deployments on Fleek, this guide walks you through migrating everything to Alternate Futures. **Time to complete:** 15-30 minutes per site ## What Changes [#what-changes] | Feature | Fleek | Alternate Futures | | -------------------- | ------------------ | ---------------------------- | | **CLI command** | `fleek` | `af` | | **Package name** | `@fleekxyz/cli` | `@alternatefutures/cli` | | **SDK package** | `@fleekxyz/sdk` | `@alternatefutures/sdk` | | **Config file** | `fleek.json` | `af.config.json` | | **Token env var** | `FLEEK_TOKEN` | `AF_TOKEN` | | **Project env var** | `FLEEK_PROJECT_ID` | `AF_PROJECT_ID` | | **IPFS support** | Yes | Yes | | **Arweave support** | Limited | Full | | **Filecoin support** | No | Yes | | **AI agents** | No | Yes (Eliza, ComfyUI, custom) | | **Observability** | No | Yes (OpenTelemetry) | ## Before You Start [#before-you-start] 1. **Export your Fleek data** before Fleek's service fully shuts down: * Download your deployed site files * Note your IPFS CIDs for any pinned content * Export your domain configuration * Save any environment variables 2. **Create an Alternate Futures account** at [clouds.alternatefutures.ai](https://clouds.alternatefutures.ai) 3. **Install the Alternate Futures CLI:** ```bash npm install -g @alternatefutures/cli af login ``` ## Step 1: Migrate Your Site [#step-1-migrate-your-site] ### From Fleek CLI to AF CLI [#from-fleek-cli-to-af-cli] If you were deploying with the Fleek CLI, the process is very similar with Alternate Futures. **Old (Fleek):** ```bash fleek sites init fleek sites deploy ``` **New (Alternate Futures):** ```bash af sites init af sites deploy ``` The `af sites init` command creates an `af.config.json` file. If you had a `fleek.json`, here is how the configuration maps: **Fleek config (`fleek.json`):** ```json { "id": "site-id", "name": "my-site", "distDir": "./dist", "buildCommand": "npm run build" } ``` **Alternate Futures config (`af.config.json`):** ```json { "sites": [ { "slug": "my-site", "distDir": "./dist", "buildCommand": "npm run build" } ] } ``` ### From Fleek SDK to AF SDK [#from-fleek-sdk-to-af-sdk] **Old (Fleek):** ```typescript import { FleekSdk, PersonalAccessTokenService } from '@fleekxyz/sdk/node'; const fleek = new FleekSdk({ accessTokenService: new PersonalAccessTokenService({ personalAccessToken: process.env.FLEEK_TOKEN, projectId: process.env.FLEEK_PROJECT_ID, }), }); const result = await fleek.ipfs().add('./dist'); ``` **New (Alternate Futures):** ```typescript import { AlternateFuturesSdk, PersonalAccessTokenService } from '@alternatefutures/sdk/node'; const af = new AlternateFuturesSdk({ accessTokenService: new PersonalAccessTokenService({ personalAccessToken: process.env.AF_TOKEN, projectId: process.env.AF_PROJECT_ID, }), }); const result = await af.ipfs().add('./dist'); ``` The SDK API is largely compatible. The main changes are the import path and environment variable names. ## Step 2: Migrate IPFS Content [#step-2-migrate-ipfs-content] If you have content pinned on Fleek's IPFS infrastructure, you should re-pin it on Alternate Futures before Fleek's pinning service goes offline. ```bash # If you have the original files, re-upload them af storage add ./my-files # Or upload from a directory af ipfs add ./my-content ``` Your CIDs will remain the same since IPFS content-addressing is deterministic -- the same files always produce the same CID. ## Step 3: Migrate Custom Domains [#step-3-migrate-custom-domains] ### Export Your DNS Configuration [#export-your-dns-configuration] Before making changes, note your current DNS records: ```bash # Check current DNS records dig yourdomain.com A dig yourdomain.com CNAME dig yourdomain.com TXT ``` ### Configure Domains on Alternate Futures [#configure-domains-on-alternate-futures] ```bash # Add your domain to your AF site af domains create --siteSlug my-site --hostname yourdomain.com # Verify DNS configuration af domains verify --hostname yourdomain.com ``` ### Update DNS Records [#update-dns-records] Update your DNS records at your registrar to point to Alternate Futures: **For subdomains (e.g., [www.example.com](http://www.example.com)):** ``` Type: CNAME Name: www Value: cname.alternatefutures.ai TTL: 3600 ``` **For root domains (e.g., example.com):** ``` Type: A Name: @ Value: [Platform IP from af domains detail] TTL: 3600 ``` See the [Custom Domains guide](./custom-domains.md) for full details. ## Step 4: Migrate CI/CD [#step-4-migrate-cicd] ### GitHub Actions [#github-actions] **Old (Fleek):** ```yaml - name: Deploy to Fleek run: npx @fleekxyz/cli sites deploy env: FLEEK_TOKEN: ${{ secrets.FLEEK_TOKEN }} ``` **New (Alternate Futures):** ```yaml - name: Deploy to Alternate Futures run: npx @alternatefutures/cli sites deploy env: AF_TOKEN: ${{ secrets.AF_TOKEN }} AF_PROJECT_ID: ${{ secrets.AF_PROJECT_ID }} ``` ### Update Repository Secrets [#update-repository-secrets] 1. Go to your repository **Settings** > **Secrets and variables** > **Actions** 2. Remove `FLEEK_TOKEN` and `FLEEK_PROJECT_ID` 3. Add `AF_TOKEN` with your Alternate Futures personal access token 4. Add `AF_PROJECT_ID` with your project ID ## Step 5: Migrate ENS Domains [#step-5-migrate-ens-domains] If you had ENS domains linked through Fleek: ```bash # Link your ENS domain to your AF site af ens create --domain mysite.eth --siteSlug my-site # Verify the configuration af ens verify --domain mysite.eth ``` ## Step 6: Clean Up [#step-6-clean-up] 1. Remove the Fleek CLI: `npm uninstall -g @fleekxyz/cli` 2. Delete `fleek.json` from your projects 3. Update any documentation referencing Fleek 4. Remove Fleek environment variables from your CI/CD ## What Alternate Futures Adds [#what-alternate-futures-adds] Beyond replacing Fleek's functionality, Alternate Futures provides additional features: * **Filecoin storage** -- Cheaper long-term archival (\~$0.03/GB/month) * **AI agent deployment** -- Deploy Eliza chatbots, ComfyUI image generators * **Observability** -- OpenTelemetry-based APM with distributed tracing * **Cloud functions** -- Serverless edge functions with optional SGX encryption * **Decentralized container registry** -- Self-hosted Docker registry on Akash * **Multi-method auth** -- Email, social OAuth, Web3 wallets (SIWE) ## Troubleshooting [#troubleshooting] ### "Package not found" when installing CLI [#package-not-found-when-installing-cli] Make sure you are installing the correct package: ```bash npm install -g @alternatefutures/cli ``` ### CIDs differ after re-uploading [#cids-differ-after-re-uploading] If your CIDs differ after re-uploading the same content, check that: * You are uploading the exact same files (byte-for-byte) * Directory structure matches exactly * No hidden files (like `.DS_Store`) were added or removed ### DNS not resolving after migration [#dns-not-resolving-after-migration] DNS propagation can take up to 48 hours. Check propagation status: ```bash dig yourdomain.com +trace ``` If using Cloudflare, set the record to "DNS Only" (grey cloud) during migration, then switch to "Proxied" after verification. ## Need Help? [#need-help] * **[Quick Start Guide](./quickstart.md)** -- Get started with Alternate Futures * **[CLI Commands](../cli/commands.md)** -- Full CLI reference * **[SDK Documentation](../sdk/)** -- Programmatic access * **[GitHub Issues](https://github.com/alternatefutures)** -- Report issues * **[Discord](https://discord.gg/alternatefutures)** -- Community support # Migrate from Netlify (/guides/migrate-from-netlify) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. Move your static sites from Netlify to Alternate Futures for decentralized hosting with IPFS, Filecoin, and Arweave storage options. **Time to complete:** 15-30 minutes per site ## Why Migrate? [#why-migrate] | Feature | Netlify | Alternate Futures | | ------------------------- | ------------------------------- | ------------------------------------- | | **Hosting model** | Centralized (AWS) | Decentralized (IPFS/Arweave/Filecoin) | | **Censorship resistance** | No | Yes | | **Permanent storage** | No | Yes (Arweave) | | **Pricing model** | Credit-based (usage metering) | Transparent per-network pricing | | **Vendor lock-in** | Yes (Netlify-specific features) | No (standard IPFS/web protocols) | | **Crypto payments** | No | Yes (ETH, AR, FIL, SOL) | | **AI agents** | No | Yes | | **Web3 integration** | No | ENS, IPNS, wallets | Migrating from Netlify works best for **static sites** and **JAMstack apps** (Next.js static export, Gatsby, Hugo, Astro, etc.). Server-side rendering and Netlify Functions can be replaced with [Cloud Functions](./functions.md). ## Prerequisites [#prerequisites] 1. **An Alternate Futures account** -- [Sign up at clouds.alternatefutures.ai](https://clouds.alternatefutures.ai) 2. **Node.js 18+** installed 3. **Your project source code** (not just the Netlify deployment) ## Step 1: Install and Authenticate [#step-1-install-and-authenticate] ```bash # Install the Alternate Futures CLI npm install -g @alternatefutures/cli # Authenticate af login ``` ## Step 2: Update Your Configuration [#step-2-update-your-configuration] ### Remove Netlify Config [#remove-netlify-config] Netlify uses `netlify.toml` for configuration. You will replace this with `af.config.json`. **Old (`netlify.toml`):** ```toml [build] command = "npm run build" publish = "dist" [[redirects]] from = "/*" to = "/index.html" status = 200 ``` **New (`af.config.json` -- created by `af sites init`):** ```json { "sites": [ { "slug": "my-site", "distDir": "./dist", "buildCommand": "npm run build" } ] } ``` Netlify's `_redirects` file and redirect rules in `netlify.toml` are specific to Netlify. For single-page apps on IPFS, ensure your build produces a `200.html` or `index.html` fallback. Most SPA frameworks handle this automatically. ### Configure Your Build [#configure-your-build] Build and deploy your site: ```bash npm run build af sites init # Select your output directory af sites deploy ``` ### Framework Output Directories [#framework-output-directories] | Framework | Output Directory | Notes | | ------------------ | ------------------ | ----------------------------------------------- | | Next.js (export) | `./out` | Requires `output: 'export'` in `next.config.js` | | Gatsby | `./public` | Works as-is | | React (Vite) | `./dist` | Works as-is | | React (CRA) | `./build` | Works as-is | | Vue (Vite) | `./dist` | Works as-is | | Astro | `./dist` | Works as-is | | Hugo | `./public` | Works as-is | | SvelteKit (static) | `./build` | Requires `@sveltejs/adapter-static` | | Nuxt (static) | `./.output/public` | Requires `nuxi generate` | | Eleventy | `./_site` | Works as-is | ## Step 3: Migrate Netlify Functions [#step-3-migrate-netlify-functions] If you use Netlify Functions, replace them with Alternate Futures [Cloud Functions](./functions.md). **Old (Netlify Function in `netlify/functions/hello.js`):** ```javascript export const handler = async (event, context) => { return { statusCode: 200, body: JSON.stringify({ message: 'Hello from Netlify' }), }; }; ``` **New (AF Cloud Function):** ```javascript export const main = (params) => { return { statusCode: 200, body: JSON.stringify({ message: 'Hello from Alternate Futures' }), }; }; ``` Deploy the function: ```bash af functions create --name hello --path ./functions/hello.js af functions deploy --name hello ``` See the [Cloud Functions guide](./functions.md) for full details on function deployment, environment variables, and SGX encryption. ## Step 4: Migrate Custom Domains [#step-4-migrate-custom-domains] ### Remove Domain from Netlify [#remove-domain-from-netlify] 1. Go to your Netlify site settings 2. Navigate to **Domain management** 3. Remove the custom domain (do not delete DNS records yet) ### Add Domain to Alternate Futures [#add-domain-to-alternate-futures] ```bash # Add the domain to your site af domains create --siteSlug my-site --hostname example.com # Get the required DNS records af domains detail --hostname example.com ``` ### Update DNS Records [#update-dns-records] Update your DNS at your registrar: **For subdomains:** ``` Type: CNAME Name: www Value: cname.alternatefutures.ai ``` **For root domains:** ``` Type: A Name: @ Value: [IP from af domains detail] ``` ```bash # Verify DNS configuration af domains verify --hostname example.com ``` If you used Netlify DNS as your nameserver, you will need to either migrate your nameservers to another provider (Cloudflare, Google DNS, etc.) or update records at Netlify DNS to point to Alternate Futures. We recommend migrating to a dedicated DNS provider for more control. ## Step 5: Migrate CI/CD [#step-5-migrate-cicd] ### Replace Netlify Build Integration [#replace-netlify-build-integration] Remove the Netlify GitHub integration and add an Alternate Futures deploy workflow. Create `.github/workflows/deploy.yml`: ```yaml name: Deploy to Alternate Futures on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: npm ci - name: Build run: npm run build - name: Deploy run: npx @alternatefutures/cli sites deploy env: AF_TOKEN: ${{ secrets.AF_TOKEN }} AF_PROJECT_ID: ${{ secrets.AF_PROJECT_ID }} ``` ### Add Secrets [#add-secrets] 1. Go to your GitHub repository **Settings** > **Secrets and variables** > **Actions** 2. Add `AF_TOKEN` -- your personal access token (create one with `af pat create --name "CI/CD"`) 3. Add `AF_PROJECT_ID` -- your project ID (find it with `af projects list`) ## Step 6: Migrate Environment Variables [#step-6-migrate-environment-variables] If your Netlify project uses environment variables: 1. Export your variables from **Netlify** > **Site settings** > **Environment variables** 2. For build-time variables, add them to your CI/CD workflow: ```yaml - name: Build run: npm run build env: NEXT_PUBLIC_API_URL: ${{ vars.NEXT_PUBLIC_API_URL }} GATSBY_API_KEY: ${{ secrets.GATSBY_API_KEY }} ``` 3. For runtime variables (functions), configure them in your [Cloud Functions](./functions.md) ## Step 7: Remove Netlify [#step-7-remove-netlify] 1. Remove the Netlify GitHub integration from your repository 2. Delete `netlify.toml` from your project 3. Delete the `netlify/` functions directory (if migrated to AF Cloud Functions) 4. Remove `_redirects` and `_headers` files (if present) 5. Optionally uninstall the Netlify CLI: `npm uninstall -g netlify-cli` 6. Delete the site from your Netlify dashboard ## Netlify Features vs Alternate Futures [#netlify-features-vs-alternate-futures] | Netlify Feature | Alternate Futures Equivalent | | ------------------------- | --------------------------------------------------------------- | | Deploy previews | Every deployment gets a unique CID URL | | Netlify Functions | [Cloud Functions](./functions.md) with SGX encryption | | Edge Functions | Cloud Functions (edge deployment) | | Netlify Analytics | [Observability & APM](./observability.md) | | Forms | Cloud Functions with form handling | | Identity | [Authentication](./authentication.md) with multi-method support | | Large Media | [Storage Management](./storage.md) on IPFS/Filecoin | | Split testing | Multiple deployments with unique CID URLs | | `_redirects` / `_headers` | Build-time configuration (framework-level) | ## Troubleshooting [#troubleshooting] ### SPA routing returns 404 [#spa-routing-returns-404] On IPFS, there is no server to handle redirects. Ensure your SPA framework generates a `200.html` or that your `index.html` handles client-side routing. Most modern frameworks (React Router, Vue Router) handle this correctly in production builds. ### Build fails during deployment [#build-fails-during-deployment] Verify that: 1. Your `buildCommand` in `af.config.json` matches what Netlify used 2. Your `distDir` points to the correct output directory 3. All required environment variables are set in your CI/CD workflow 4. You are not relying on Netlify-specific build plugins ### DNS not resolving after migration [#dns-not-resolving-after-migration] DNS propagation can take up to 48 hours. Check propagation status: ```bash dig yourdomain.com +trace ``` If using Cloudflare, set the record to "DNS Only" (grey cloud) during migration, then switch to "Proxied" after verification. ## Next Steps [#next-steps] * **[Deploying Sites](./sites.md)** -- Learn about storage networks and deployment options * **[Cloud Functions](./functions.md)** -- Replace Netlify Functions * **[CI/CD Integration](./cicd.md)** -- Advanced CI/CD patterns * **[Custom Domains](./custom-domains.md)** -- Full domain configuration guide * **[Best Practices](./best-practices.md)** -- Optimize your deployments # Migrate from Spheron (/guides/migrate-from-spheron) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. Spheron has pivoted away from Web3 hosting to focus on GPU compute and AI inference. If you have sites, storage, or deployments on Spheron, this guide walks you through migrating everything to Alternate Futures. **Time to complete:** 15-30 minutes per site ## What Changes [#what-changes] | Feature | Spheron | Alternate Futures | | -------------------- | ------------------ | ---------------------------- | | **CLI command** | `spheron` | `af` | | **Package name** | `@spheron/cli` | `@alternatefutures/cli` | | **SDK package** | `@spheron/storage` | `@alternatefutures/sdk` | | **Config file** | `spheron.json` | `af.config.json` | | **Token env var** | `SPHERON_TOKEN` | `AF_TOKEN` | | **IPFS support** | Yes | Yes | | **Arweave support** | Yes | Yes (full) | | **Filecoin support** | Yes | Yes | | **AI agents** | No | Yes (Eliza, ComfyUI, custom) | | **Observability** | No | Yes (OpenTelemetry) | | **Cloud functions** | No | Yes (SGX encryption) | | **ENS integration** | Limited | Full | If you used Spheron primarily for GPU compute, that functionality is separate from web hosting. This guide covers migrating your **web hosting, static sites, and storage**. For compute workloads, see [Cloud Functions](./functions.md) and [Managing Agents](./agents.md). ## Before You Start [#before-you-start] 1. **Export your Spheron data** before Spheron's hosting services are fully discontinued: * Download your deployed site source files * Note your IPFS CIDs for any pinned content * Export your domain configuration and DNS records * Save any environment variables from your Spheron dashboard 2. **Create an Alternate Futures account** at [clouds.alternatefutures.ai](https://clouds.alternatefutures.ai) 3. **Install the Alternate Futures CLI:** ```bash npm install -g @alternatefutures/cli af login ``` ## Step 1: Migrate Your Site [#step-1-migrate-your-site] ### From Spheron Dashboard to AF CLI [#from-spheron-dashboard-to-af-cli] Spheron used a dashboard-first workflow with Git integration. Alternate Futures provides both CLI and SDK workflows, with a web dashboard coming soon. **Deploy with the AF CLI:** ```bash # Navigate to your project directory cd my-project # Build your project (if not already built) npm run build # Initialize AF configuration af sites init # Deploy to IPFS (default), Filecoin, or Arweave af sites deploy ``` The `af sites init` command creates an `af.config.json` file. Here is how Spheron's configuration maps: **Spheron config (via dashboard):** * Framework: Auto-detected * Build command: `npm run build` * Output directory: `./dist` * Protocol: IPFS / Arweave / Filecoin **Alternate Futures config (`af.config.json`):** ```json { "sites": [ { "slug": "my-site", "distDir": "./dist", "buildCommand": "npm run build" } ] } ``` ### From Spheron SDK to AF SDK [#from-spheron-sdk-to-af-sdk] **Old (Spheron):** ```typescript import { SpheronClient, ProtocolEnum } from '@spheron/storage'; const client = new SpheronClient({ token: process.env.SPHERON_TOKEN, }); const { uploadId, bucketId, protocolLink, dynamicLinks } = await client.upload('./dist', { protocol: ProtocolEnum.IPFS, name: 'my-site', }); ``` **New (Alternate Futures):** ```typescript import { AlternateFuturesSdk, PersonalAccessTokenService } from '@alternatefutures/sdk/node'; const af = new AlternateFuturesSdk({ accessTokenService: new PersonalAccessTokenService({ personalAccessToken: process.env.AF_TOKEN, projectId: process.env.AF_PROJECT_ID, }), }); // Upload to IPFS const result = await af.ipfs().add('./dist'); console.log('CID:', result.pin.cid); console.log('URL:', `https://ipfs.io/ipfs/${result.pin.cid}`); ``` ### Storage Protocol Mapping [#storage-protocol-mapping] If you were using specific storage protocols on Spheron, here is how they map: | Spheron Protocol | AF Equivalent | CLI Flag | | ----------------------- | -------------- | ---------------------------- | | `ProtocolEnum.IPFS` | IPFS (default) | `af sites deploy` | | `ProtocolEnum.FILECOIN` | Filecoin | `af sites deploy --filecoin` | | `ProtocolEnum.ARWEAVE` | Arweave | `af sites deploy --arweave` | ## Step 2: Migrate IPFS Content [#step-2-migrate-ipfs-content] If you have content pinned on Spheron's IPFS infrastructure, re-pin it on Alternate Futures before Spheron's pinning service goes offline. ```bash # If you have the original files, re-upload them af storage add ./my-files # Upload a directory to IPFS af ipfs add ./my-content ``` Your CIDs will remain the same since IPFS content-addressing is deterministic -- the same files always produce the same CID. ### Migrate Arweave Content [#migrate-arweave-content] Arweave content is permanently stored on-chain, so it does not need to be re-uploaded. However, you should update any URLs or gateways you use to access it: ```bash # Your existing Arweave transaction IDs still work # Access via any Arweave gateway: # https://arweave.net/{TX_ID} # Deploy new content to Arweave via AF af sites deploy --arweave ``` ## Step 3: Migrate Custom Domains [#step-3-migrate-custom-domains] ### Export Your DNS Configuration [#export-your-dns-configuration] Before making changes, note your current DNS records: ```bash # Check current DNS records dig yourdomain.com A dig yourdomain.com CNAME dig yourdomain.com TXT ``` ### Remove Domain from Spheron [#remove-domain-from-spheron] 1. Go to your Spheron project dashboard 2. Navigate to **Domains** 3. Remove the domain (do not delete DNS records yet) ### Configure Domains on Alternate Futures [#configure-domains-on-alternate-futures] ```bash # Add your domain to your AF site af domains create --siteSlug my-site --hostname yourdomain.com # Get the required DNS records af domains detail --hostname yourdomain.com ``` ### Update DNS Records [#update-dns-records] Update your DNS records at your registrar to point to Alternate Futures: **For subdomains (e.g., [www.example.com](http://www.example.com)):** ``` Type: CNAME Name: www Value: cname.alternatefutures.ai TTL: 3600 ``` **For root domains (e.g., example.com):** ``` Type: A Name: @ Value: [Platform IP from af domains detail] TTL: 3600 ``` ```bash # Verify DNS configuration af domains verify --hostname yourdomain.com ``` See the [Custom Domains guide](./custom-domains.md) for full details. ## Step 4: Migrate CI/CD [#step-4-migrate-cicd] ### Replace Spheron GitHub Integration [#replace-spheron-github-integration] Spheron used a built-in GitHub integration. Replace it with an Alternate Futures deploy workflow. Remove the Spheron GitHub integration from your repository settings, then create `.github/workflows/deploy.yml`: ```yaml name: Deploy to Alternate Futures on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: npm ci - name: Build run: npm run build - name: Deploy run: npx @alternatefutures/cli sites deploy env: AF_TOKEN: ${{ secrets.AF_TOKEN }} AF_PROJECT_ID: ${{ secrets.AF_PROJECT_ID }} ``` ### Add Secrets [#add-secrets] 1. Go to your GitHub repository **Settings** > **Secrets and variables** > **Actions** 2. Add `AF_TOKEN` -- your personal access token (create one with `af pat create --name "CI/CD"`) 3. Add `AF_PROJECT_ID` -- your project ID (find it with `af projects list`) ## Step 5: Migrate Environment Variables [#step-5-migrate-environment-variables] If your Spheron project used environment variables: 1. Note your variables from the Spheron project dashboard 2. For build-time variables, add them to your CI/CD workflow: ```yaml - name: Build run: npm run build env: NEXT_PUBLIC_API_URL: ${{ vars.NEXT_PUBLIC_API_URL }} ``` 3. For runtime variables, configure them in your [Cloud Functions](./functions.md) ## Step 6: Clean Up [#step-6-clean-up] 1. Remove the Spheron CLI: `npm uninstall -g @spheron/cli` 2. Remove Spheron SDK packages: `npm uninstall @spheron/storage` 3. Delete any Spheron configuration files from your project 4. Remove Spheron environment variables from your CI/CD 5. Disconnect the Spheron GitHub integration from your repository 6. Delete the project from your Spheron dashboard ## What Alternate Futures Adds [#what-alternate-futures-adds] Beyond replacing Spheron's hosting functionality, Alternate Futures provides additional features: * **AI agent deployment** -- Deploy Eliza chatbots, ComfyUI image generators, and custom agents * **Cloud functions** -- Serverless edge functions with optional SGX encryption * **Observability** -- OpenTelemetry-based APM with distributed tracing, metrics, and logging * **ENS integration** -- Full ENS domain support with `.eth` names * **IPNS records** -- Mutable pointers for stable URLs to changing content * **Private gateways** -- Dedicated IPFS gateways with custom domains * **Decentralized container registry** -- Self-hosted Docker registry on Akash * **Multi-method auth** -- Email, social OAuth, Web3 wallets (SIWE) ## Spheron Features vs Alternate Futures [#spheron-features-vs-alternate-futures] | Spheron Feature | Alternate Futures Equivalent | | --------------------- | -------------------------------------------------- | | Dashboard deployments | CLI + SDK (web dashboard coming soon) | | GitHub auto-deploy | [CI/CD Integration](./cicd.md) with GitHub Actions | | IPFS pinning | Built-in IPFS pinning with `af storage add` | | Arweave uploads | `af sites deploy --arweave` | | Filecoin storage | `af sites deploy --filecoin` | | Custom domains | [Custom Domains](./custom-domains.md) with SSL | | Preview deployments | Every deployment gets a unique CID URL | | Team collaboration | [Projects](./projects.md) with team management | ## Troubleshooting [#troubleshooting] ### "Package not found" when installing CLI [#package-not-found-when-installing-cli] Make sure you are installing the correct package: ```bash npm install -g @alternatefutures/cli ``` ### CIDs differ after re-uploading [#cids-differ-after-re-uploading] If your CIDs differ after re-uploading the same content, check that: * You are uploading the exact same files (byte-for-byte) * Directory structure matches exactly * No hidden files (like `.DS_Store`) were added or removed ### Build fails during deployment [#build-fails-during-deployment] If your build fails, verify: 1. Your `buildCommand` in `af.config.json` matches what you used on Spheron 2. Your `distDir` points to the correct output directory 3. All required environment variables are set ### DNS not resolving after migration [#dns-not-resolving-after-migration] DNS propagation can take up to 48 hours. Check propagation status: ```bash dig yourdomain.com +trace ``` If using Cloudflare, set the record to "DNS Only" (grey cloud) during migration, then switch to "Proxied" after verification. ## Next Steps [#next-steps] * **[Quick Start Guide](./quickstart.md)** -- Get started with Alternate Futures * **[Deploying Sites](./sites.md)** -- Learn about storage networks and deployment options * **[CLI Commands](../cli/commands.md)** -- Full CLI reference * **[SDK Documentation](../sdk/)** -- Programmatic access * **[GitHub Issues](https://github.com/alternatefutures)** -- Report issues * **[Discord](https://discord.gg/alternatefutures)** -- Community support # Migrate from Vercel (/guides/migrate-from-vercel) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. Move your static sites from Vercel to Alternate Futures for decentralized hosting with IPFS, Filecoin, and Arweave storage options. **Time to complete:** 15-30 minutes per site ## Why Migrate? [#why-migrate] | Feature | Vercel | Alternate Futures | | ------------------------- | ------------------------------ | ------------------------------------- | | **Hosting model** | Centralized (AWS) | Decentralized (IPFS/Arweave/Filecoin) | | **Censorship resistance** | No | Yes | | **Permanent storage** | No | Yes (Arweave) | | **Free tier** | Limited (Hobby) | Generous free tier | | **Vendor lock-in** | Yes (Vercel-specific features) | No (standard IPFS/web protocols) | | **Crypto payments** | No | Yes (ETH, AR, FIL, SOL) | | **AI agents** | No | Yes | | **Web3 integration** | No | ENS, IPNS, wallets | Migrating from Vercel works best for **static sites** and **static exports** (Next.js with `output: 'export'`, React SPAs, Vue, Astro, etc.). Server-side rendering (SSR) features are handled by [Cloud Functions](./functions.md). ## Prerequisites [#prerequisites] 1. **An Alternate Futures account** -- [Sign up at clouds.alternatefutures.ai](https://clouds.alternatefutures.ai) 2. **Node.js 18+** installed 3. **Your project source code** (not just the Vercel deployment) ## Step 1: Install and Authenticate [#step-1-install-and-authenticate] ```bash # Install the Alternate Futures CLI npm install -g @alternatefutures/cli # Authenticate af login ``` ## Step 2: Configure Your Build [#step-2-configure-your-build] ### Next.js (Static Export) [#nextjs-static-export] Add static export to your `next.config.js`: ```javascript // next.config.js const nextConfig = { output: 'export', // Required for static hosting images: { unoptimized: true, // Required for static export }, trailingSlash: true, // Recommended for IPFS compatibility }; module.exports = nextConfig; ``` Build and deploy: ```bash npm run build af sites init # Set output directory to ./out af sites deploy ``` ### React (Vite or Create React App) [#react-vite-or-create-react-app] ```bash npm run build af sites init # Set output directory to ./dist (Vite) or ./build (CRA) af sites deploy ``` ### Other Frameworks [#other-frameworks] Any framework that produces static output works. Set the correct output directory: | Framework | Output Directory | | ------------------ | ------------------ | | Next.js (export) | `./out` | | React (Vite) | `./dist` | | React (CRA) | `./build` | | Vue (Vite) | `./dist` | | Astro | `./dist` | | SvelteKit (static) | `./build` | | Nuxt (static) | `./.output/public` | ## Step 3: Migrate Custom Domains [#step-3-migrate-custom-domains] ### Remove Domain from Vercel [#remove-domain-from-vercel] 1. Go to your Vercel project settings 2. Navigate to **Domains** 3. Remove the domain (do not delete DNS records yet) ### Add Domain to Alternate Futures [#add-domain-to-alternate-futures] ```bash # Add the domain to your site af domains create --siteSlug my-site --hostname example.com # Get the required DNS records af domains detail --hostname example.com ``` ### Update DNS Records [#update-dns-records] Update your DNS at your registrar: **For subdomains:** ``` Type: CNAME Name: www Value: cname.alternatefutures.ai ``` **For root domains:** ``` Type: A Name: @ Value: [IP from af domains detail] ``` ```bash # Verify DNS configuration af domains verify --hostname example.com ``` ## Step 4: Migrate CI/CD [#step-4-migrate-cicd] ### Replace Vercel GitHub Integration [#replace-vercel-github-integration] Remove the Vercel GitHub integration and add an Alternate Futures deploy workflow: Create `.github/workflows/deploy.yml`: ```yaml name: Deploy to Alternate Futures on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '20' - name: Install dependencies run: npm ci - name: Build run: npm run build - name: Deploy run: npx @alternatefutures/cli sites deploy env: AF_TOKEN: ${{ secrets.AF_TOKEN }} AF_PROJECT_ID: ${{ secrets.AF_PROJECT_ID }} ``` ### Add Secrets [#add-secrets] 1. Go to your GitHub repository **Settings** > **Secrets and variables** > **Actions** 2. Add `AF_TOKEN` -- your personal access token (create one with `af pat create --name "CI/CD"`) 3. Add `AF_PROJECT_ID` -- your project ID (find it with `af projects list`) ## Step 5: Migrate Environment Variables [#step-5-migrate-environment-variables] If your Vercel project uses environment variables: 1. Note your variables from Vercel project settings 2. For build-time variables, add them to your CI/CD workflow 3. For runtime variables (API routes), configure them in your [Cloud Functions](./functions.md) ## Step 6: Remove Vercel [#step-6-remove-vercel] 1. Remove the Vercel GitHub integration from your repository 2. Delete `vercel.json` from your project 3. Optionally uninstall the Vercel CLI: `npm uninstall -g vercel` 4. Delete the project from your Vercel dashboard ## Vercel Features vs Alternate Futures [#vercel-features-vs-alternate-futures] | Vercel Feature | Alternate Futures Equivalent | | -------------------- | ----------------------------------------------------- | | Preview deployments | Every deployment gets a unique CID URL | | Serverless functions | [Cloud Functions](./functions.md) with SGX encryption | | Edge functions | Cloud Functions (edge deployment) | | Analytics | [Observability & APM](./observability.md) | | Image optimization | Build-time optimization (recommended) | | ISR/SSR | Static export + Cloud Functions for dynamic routes | | Cron jobs | Cloud Functions with external scheduling | ## Next Steps [#next-steps] * **[Deploying Sites](./sites.md)** -- Learn about storage networks and deployment options * **[Cloud Functions](./functions.md)** -- Replace Vercel serverless functions * **[CI/CD Integration](./cicd.md)** -- Advanced CI/CD patterns * **[Custom Domains](./custom-domains.md)** -- Full domain configuration guide # Observability and APM (/guides/observability) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. Monitor your applications with distributed tracing, metrics, and logging. The Alternate Futures Observability platform provides full APM (Application Performance Monitoring) capabilities for your deployed services. ## Overview [#overview] The observability platform enables you to: * **Traces** - Track requests as they flow through your distributed systems * **Metrics** - Collect and query performance metrics * **Logs** - Centralized logging with search capabilities * **Service Maps** - Visualize dependencies between services * **Usage Analytics** - Monitor ingestion and costs ## Architecture [#architecture] ``` ┌─────────────────────────────────────────────────────────────────┐ │ Your Applications │ │ (AF Functions, Node.js, Python, Go, etc.) │ └─────────────────────────┬───────────────────────────────────────┘ │ OTLP (OpenTelemetry Protocol) │ + X-AF-Project-ID header ▼ ┌─────────────────────────────────────────────────────────────────┐ │ OTEL Collector │ │ - Multi-tenant routing │ │ - Sampling & filtering │ │ - Data transformation │ └──────────┬──────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ ClickHouse Storage │ │ - Traces, Metrics, Logs │ │ - Per-project partitioning │ │ - Configurable retention │ └──────────┬──────────────────────────────────────────────────────┘ │ ▼ ┌─────────────────────────────────────────────────────────────────┐ │ Query via SDK, CLI, or GraphQL API │ └─────────────────────────────────────────────────────────────────┘ ``` ## Quick Start [#quick-start] ### 1. Install the SDK with OpenTelemetry [#1-install-the-sdk-with-opentelemetry] ```bash npm install @alternatefutures/sdk \ @opentelemetry/api \ @opentelemetry/sdk-node \ @opentelemetry/auto-instrumentations-node \ @opentelemetry/exporter-trace-otlp-http \ @opentelemetry/exporter-metrics-otlp-http \ @opentelemetry/exporter-logs-otlp-http ``` ### 2. Initialize Instrumentation [#2-initialize-instrumentation] Create an `instrumentation.ts` file that runs before your application: ```typescript // instrumentation.ts import { initInstrumentation } from '@alternatefutures/sdk/instrumentation'; const sdk = await initInstrumentation({ projectId: 'your-project-id', projectSlug: 'your-project-slug', serviceName: 'my-api-service', }); // Graceful shutdown process.on('SIGTERM', async () => { await sdk.shutdown(); process.exit(0); }); ``` ### 3. Run Your Application [#3-run-your-application] ```bash # Node.js 18+ node --import ./instrumentation.ts ./app.ts # Or with ts-node node -r ts-node/register --import ./instrumentation.ts ./app.ts ``` That's it! Your application is now sending traces, metrics, and logs to the Alternate Futures platform. *** ## Instrumentation Setup [#instrumentation-setup] ### Node.js Auto-Instrumentation [#nodejs-auto-instrumentation] The SDK provides automatic instrumentation for common Node.js libraries: ```typescript import { initInstrumentation } from '@alternatefutures/sdk/instrumentation'; const sdk = await initInstrumentation({ // Required projectId: process.env.AF_PROJECT_ID!, projectSlug: process.env.AF_PROJECT_SLUG!, serviceName: 'api-gateway', // Optional serviceVersion: '1.0.0', environment: 'production', // OTEL endpoint (defaults to Alternate Futures collector) otlpEndpoint: 'https://otel.alternatefutures.ai', // Custom resource attributes resourceAttributes: { 'deployment.region': 'us-east-1', 'team.name': 'platform', }, // Configure auto-instrumentations instrumentationConfig: { '@opentelemetry/instrumentation-http': { ignoreIncomingPaths: ['/health', '/ready'], }, }, }); ``` **Automatically instrumented libraries:** * HTTP/HTTPS requests (incoming and outgoing) * Express, Fastify, Koa, Hapi * PostgreSQL, MySQL, MongoDB, Redis * gRPC * AWS SDK * GraphQL * And many more... ### Custom Spans [#custom-spans] Add custom spans to trace specific operations: ```typescript import { withSpan } from '@alternatefutures/sdk/instrumentation'; // Wrap a function with automatic span creation const processOrder = withSpan( async (orderId: string) => { // Your business logic here const order = await fetchOrder(orderId); await validateOrder(order); await chargePayment(order); return order; }, 'processOrder', { 'order.type': 'standard' } ); // Use it normally const result = await processOrder('order-123'); ``` ### Manual Spans [#manual-spans] For more control, create spans manually: ```typescript import { trace, SpanStatusCode } from '@opentelemetry/api'; const tracer = trace.getTracer('my-service'); async function complexOperation() { return tracer.startActiveSpan('complexOperation', async (span) => { try { // Add attributes span.setAttribute('user.id', userId); span.setAttribute('operation.type', 'batch'); // Add events span.addEvent('Starting batch processing', { 'batch.size': items.length, }); const result = await processBatch(items); span.addEvent('Batch complete', { 'processed.count': result.count, }); span.setStatus({ code: SpanStatusCode.OK }); return result; } catch (error) { span.setStatus({ code: SpanStatusCode.ERROR, message: error.message, }); span.recordException(error); throw error; } finally { span.end(); } }); } ``` ### Logging Integration [#logging-integration] Send structured logs to the observability platform: ```typescript import { logs, SeverityNumber } from '@opentelemetry/api-logs'; const logger = logs.getLogger('my-service'); // Log with severity levels logger.emit({ severityNumber: SeverityNumber.INFO, severityText: 'INFO', body: 'User logged in successfully', attributes: { 'user.id': '12345', 'user.email': 'user@example.com', 'login.method': 'oauth', }, }); // Error logging with exception logger.emit({ severityNumber: SeverityNumber.ERROR, severityText: 'ERROR', body: 'Failed to process payment', attributes: { 'error.type': 'PaymentError', 'error.message': 'Card declined', 'order.id': 'order-456', }, }); ``` *** ## Querying Data [#querying-data] ### Using the SDK [#using-the-sdk] ```typescript import { AlternateFuturesSdk } from '@alternatefutures/sdk/node'; const af = new AlternateFuturesSdk({ personalAccessToken: process.env.AF_TOKEN, }); // Query traces from the last hour const traces = await af.observability().queryTraces({ projectId: 'prj_abc123', startTime: new Date(Date.now() - 60 * 60 * 1000), endTime: new Date(), serviceName: 'api-gateway', // optional filter minDurationMs: 100, // optional: only slow traces limit: 50, }); // Display results traces.forEach(trace => { console.log(`Trace: ${trace.traceId}`); console.log(` Service: ${trace.serviceName}`); console.log(` Duration: ${trace.durationMs}ms`); console.log(` Spans: ${trace.spanCount}`); console.log(` Error: ${trace.hasError ? 'Yes' : 'No'}`); }); ``` ```typescript // Get full trace with all spans const trace = await af.observability().getTrace( 'prj_abc123', 'abc123def456...' ); console.log(`Trace ID: ${trace.traceId}`); console.log(`Total Duration: ${trace.durationMs}ms`); console.log(`Span Count: ${trace.spans.length}`); // Analyze spans trace.spans.forEach(span => { const indent = ' '.repeat(getSpanDepth(span)); console.log(`${indent}${span.spanName} (${span.durationMs}ms)`); console.log(`${indent} Kind: ${span.spanKind}`); console.log(`${indent} Status: ${span.statusCode}`); // Show events span.events?.forEach(event => { console.log(`${indent} Event: ${event.name}`); }); }); ``` ```typescript // Query logs with filters const logs = await af.observability().queryLogs({ projectId: 'prj_abc123', startTime: new Date(Date.now() - 24 * 60 * 60 * 1000), endTime: new Date(), severityText: 'ERROR', // Filter by severity bodyContains: 'payment', // Search in log body serviceName: 'checkout-service', limit: 100, }); logs.forEach(log => { console.log(`[${log.timestamp}] [${log.severityText}] ${log.body}`); if (log.traceId) { console.log(` Trace: ${log.traceId}`); } }); ``` ```typescript // Query metrics with aggregation const metrics = await af.observability().queryMetrics({ projectId: 'prj_abc123', startTime: new Date(Date.now() - 60 * 60 * 1000), endTime: new Date(), metricName: 'http.server.duration', aggregation: 'avg', groupBy: ['http.route', 'http.status_code'], }); metrics.forEach(series => { console.log(`Metric: ${series.name}`); console.log(`Labels: ${JSON.stringify(series.labels)}`); series.dataPoints.forEach(point => { console.log(` ${point.timestamp}: ${point.value}`); }); }); ``` ```typescript // Get service-level statistics const services = await af.observability().getServices( 'prj_abc123', new Date(Date.now() - 24 * 60 * 60 * 1000), new Date() ); console.log('Service Performance Summary:'); console.log('─'.repeat(80)); services.forEach(service => { const errorRate = (service.errorCount / service.spanCount * 100).toFixed(2); console.log(`\n${service.serviceName}`); console.log(` Traces: ${service.traceCount.toLocaleString()}`); console.log(` Spans: ${service.spanCount.toLocaleString()}`); console.log(` Errors: ${service.errorCount.toLocaleString()} (${errorRate}%)`); console.log(` Latency:`); console.log(` Avg: ${service.avgDurationMs.toFixed(2)}ms`); console.log(` P50: ${service.p50DurationMs.toFixed(2)}ms`); console.log(` P95: ${service.p95DurationMs.toFixed(2)}ms`); console.log(` P99: ${service.p99DurationMs.toFixed(2)}ms`); }); ``` ### Using the CLI [#using-the-cli] ```bash # List recent traces af observability traces # Filter by service af observability traces --service api-gateway # Filter by status (errors only) af observability traces --status ERROR # Filter by duration (slow requests) af observability traces --min-duration 500 # Look back further in time af observability traces --hours 24 --limit 100 ``` ```bash # View specific trace af observability trace abc123def456... # Output shows: # Trace Details: # Trace ID: abc123def456... # Service: api-gateway # Duration: 234.56ms # Span Count: 12 # Has Error: No # Start Time: 12/29/2025, 10:30:15 AM # # Spans: # ┌────────────────────────────┬────────┬────────────┬────────┬──────────────┐ # │ Span Name │ Kind │ Duration │ Status │ Service │ # ├────────────────────────────┼────────┼────────────┼────────┼──────────────┤ # │ HTTP GET /api/users │ SERVER │ 234.56ms │ OK │ api-gateway │ # │ PostgreSQL SELECT │ CLIENT │ 45.23ms │ OK │ api-gateway │ # │ Redis GET │ CLIENT │ 2.34ms │ OK │ api-gateway │ # └────────────────────────────┴────────┴────────────┴────────┴──────────────┘ ``` ```bash # Recent logs af observability logs # Filter by severity af observability logs --severity ERROR af observability logs --severity WARN # Search in log body af observability logs --search "connection failed" # Filter by service af observability logs --service database-worker # Combine filters af observability logs \ --service checkout-service \ --severity ERROR \ --hours 4 ``` ```bash # Get service performance overview af observability services # Look at last 7 days af observability services --hours 168 # Output shows: # Found 5 service(s) with telemetry data: # # ┌────────────────────┬─────────┬──────────┬────────┬────────────┬──────────┬──────────┬──────────┬──────────┐ # │ Service │ Traces │ Spans │ Errors │ Error Rate │ Avg (ms) │ P50 (ms) │ P95 (ms) │ P99 (ms) │ # ├────────────────────┼─────────┼──────────┼────────┼────────────┼──────────┼──────────┼──────────┼──────────┤ # │ api-gateway │ 15,234 │ 45,702 │ 123 │ 0.3% │ 45.23 │ 32.10 │ 156.78 │ 423.45 │ # │ user-service │ 8,456 │ 16,912 │ 45 │ 0.3% │ 23.45 │ 18.90 │ 67.89 │ 145.67 │ # │ checkout-service │ 3,234 │ 12,936 │ 234 │ 1.8% │ 156.78 │ 123.45 │ 456.78 │ 890.12 │ # │ notification-svc │ 12,345 │ 24,690 │ 12 │ 0.0% │ 12.34 │ 10.00 │ 34.56 │ 67.89 │ # │ analytics-worker │ 1,234 │ 3,702 │ 0 │ 0.0% │ 234.56 │ 200.00 │ 567.89 │ 890.12 │ # └────────────────────┴─────────┴──────────┴────────┴────────────┴──────────┴──────────┴──────────┴──────────┘ ``` ```bash # View telemetry usage for billing period af observability usage # Look at specific period af observability usage --days 7 # Output shows: # Telemetry Usage Summary: # # Period: 12/1/2025 - 12/29/2025 # Project ID: prj_abc123 # # ┌───────────────────────┬───────────────────┐ # │ Metric │ Value │ # ├───────────────────────┼───────────────────┤ # │ Spans Ingested │ 1,234,567 │ # │ Metrics Ingested │ 456,789 │ # │ Logs Ingested │ 789,012 │ # │ Total Data Ingested │ 2.34 GB │ # │ Estimated Cost │ $0.82 │ # └───────────────────────┴───────────────────┘ # # Pricing: $0.35 per GB ingested ``` ```bash # View current settings af observability settings # Enable/disable telemetry types af observability settings:update --traces true --metrics false # Adjust sampling rate (0.0 to 1.0) af observability settings:update --sample-rate 0.5 # Change retention periods af observability settings:update --trace-retention 14 --log-retention 30 ``` *** ## Observability Settings [#observability-settings] Configure per-project observability settings: ```typescript // Get current settings const settings = await af.observability().getSettings('prj_abc123'); console.log('Observability Settings:'); console.log(` Traces: ${settings.tracesEnabled ? 'Enabled' : 'Disabled'}`); console.log(` Metrics: ${settings.metricsEnabled ? 'Enabled' : 'Disabled'}`); console.log(` Logs: ${settings.logsEnabled ? 'Enabled' : 'Disabled'}`); console.log(` Sample Rate: ${settings.sampleRate * 100}%`); console.log(` Trace Retention: ${settings.traceRetention} days`); console.log(` Metric Retention: ${settings.metricRetention} days`); console.log(` Log Retention: ${settings.logRetention} days`); // Update settings await af.observability().updateSettings('prj_abc123', { tracesEnabled: true, metricsEnabled: true, logsEnabled: true, sampleRate: 0.5, // Sample 50% of traces traceRetention: 14, // Keep traces for 14 days logRetention: 30, // Keep logs for 30 days }); ``` ```bash # View settings af observability settings # Update individual settings af observability settings:update --sample-rate 0.5 af observability settings:update --trace-retention 14 af observability settings:update --logs false ``` ### Settings Reference [#settings-reference] | Setting | Description | Default | | ----------------- | ------------------------- | ------------------ | | `tracesEnabled` | Enable trace collection | `true` | | `metricsEnabled` | Enable metrics collection | `true` | | `logsEnabled` | Enable log collection | `true` | | `sampleRate` | Sampling rate (0.0-1.0) | `1.0` (100%) | | `traceRetention` | Trace retention in days | `7` | | `metricRetention` | Metric retention in days | `30` | | `logRetention` | Log retention in days | `7` | | `maxBytesPerHour` | Rate limit (bytes/hour) | `null` (unlimited) | *** ## AF Functions Integration [#af-functions-integration] When using Alternate Futures Functions, observability is automatically configured. Your functions receive telemetry context from incoming requests. ```javascript // functions/api.js - Traces are automatically created export default async function handler(request) { const url = new URL(request.url); // This request is automatically traced const userData = await fetch('https://api.example.com/users/123'); // Log events are captured console.log('Fetched user data'); return new Response(JSON.stringify(userData), { headers: { 'Content-Type': 'application/json' } }); } ``` To add custom spans within your function: ```javascript import { trace } from '@opentelemetry/api'; export default async function handler(request) { const tracer = trace.getTracer('my-function'); return tracer.startActiveSpan('processRequest', async (span) => { try { span.setAttribute('request.path', new URL(request.url).pathname); const result = await processData(); span.setStatus({ code: 1 }); // OK return new Response(JSON.stringify(result)); } catch (error) { span.setStatus({ code: 2, message: error.message }); // ERROR span.recordException(error); throw error; } finally { span.end(); } }); } ``` *** ## Pricing [#pricing] Observability is billed based on data ingested: | Metric | Price | | -------------- | ---------------- | | Data Ingestion | **$0.35 per GB** | Includes: * Traces, metrics, and logs * Unlimited queries * API access * CLI tools ### Estimating Costs [#estimating-costs] Use the CLI to check current usage: ```bash af observability usage --days 30 ``` **Typical data sizes:** * Span: \~500 bytes average * Metric point: \~100 bytes * Log entry: \~1KB average **Example calculation:** * 1 million spans/day = \~500MB/day = ~~15GB/month = \*\*~~$5.25/month\*\* ### Reducing Costs [#reducing-costs] 1. **Adjust sampling rate** - Sample 50% or 10% of traces for high-volume services 2. **Disable unused telemetry** - Turn off metrics or logs if not needed 3. **Shorter retention** - Reduce retention periods 4. **Filter at source** - Don't instrument health checks or internal endpoints ```typescript // Configure sampling await initInstrumentation({ projectId: 'prj_abc123', projectSlug: 'my-project', serviceName: 'high-volume-service', instrumentationConfig: { '@opentelemetry/instrumentation-http': { // Don't trace health checks ignoreIncomingPaths: ['/health', '/ready', '/metrics'], }, }, }); // Or set sampling via settings await af.observability().updateSettings('prj_abc123', { sampleRate: 0.1, // Only sample 10% }); ``` *** ## Best Practices [#best-practices] ### Span Naming [#span-naming] Use consistent, descriptive span names: ```typescript // Good - descriptive and consistent 'HTTP GET /api/users/:id' 'PostgreSQL SELECT users' 'Redis GET session:*' 'processPayment' 'sendNotification' // Bad - too generic or inconsistent 'request' 'database' 'do_thing' ``` ### Attributes [#attributes] Add meaningful attributes for filtering and analysis: ```typescript span.setAttribute('user.id', userId); span.setAttribute('order.id', orderId); span.setAttribute('order.total', orderTotal); span.setAttribute('payment.method', 'credit_card'); span.setAttribute('feature.flag', 'new-checkout-flow'); ``` ### Error Handling [#error-handling] Always record exceptions and set error status: ```typescript try { await riskyOperation(); } catch (error) { span.setStatus({ code: SpanStatusCode.ERROR, message: error.message, }); span.recordException(error); // Log the error too logger.emit({ severityNumber: SeverityNumber.ERROR, body: `Operation failed: ${error.message}`, attributes: { 'error.type': error.name, 'error.stack': error.stack, }, }); throw error; } ``` ### Context Propagation [#context-propagation] Ensure trace context is propagated across service boundaries: ```typescript import { context, propagation } from '@opentelemetry/api'; // When making outbound requests const headers = {}; propagation.inject(context.active(), headers); const response = await fetch('https://other-service/api', { headers: { ...headers, 'Content-Type': 'application/json', }, }); ``` *** ## Troubleshooting [#troubleshooting] ### No Data Appearing [#no-data-appearing] 1. **Check project ID** - Ensure `X-AF-Project-ID` header is set correctly 2. **Verify endpoint** - Confirm OTLP endpoint is reachable 3. **Check sampling** - Sampling rate might be set too low 4. **Review settings** - Telemetry type might be disabled ```bash # Check settings af observability settings # Verify connectivity curl -X POST https://otel.alternatefutures.ai/v1/traces \ -H "Content-Type: application/json" \ -H "X-AF-Project-ID: your-project-id" \ -d '{}' ``` ### Missing Spans [#missing-spans] 1. **Ensure spans are ended** - Always call `span.end()` 2. **Check async context** - Use `startActiveSpan` for automatic propagation 3. **Verify flush** - SDK might not have flushed before process exit ```typescript // Ensure graceful shutdown process.on('SIGTERM', async () => { await sdk.shutdown(); // Flushes pending telemetry process.exit(0); }); ``` ### High Cardinality Warning [#high-cardinality-warning] Avoid high-cardinality attributes that create too many unique combinations: ```typescript // Bad - creates millions of unique series span.setAttribute('request.id', requestId); // Unique per request! span.setAttribute('timestamp', Date.now()); // Always different! // Good - limited cardinality span.setAttribute('http.method', 'GET'); span.setAttribute('http.status_code', 200); span.setAttribute('user.tier', 'premium'); ``` *** ## Next Steps [#next-steps] * [Cloud Functions](./functions.md) - Deploy serverless functions with built-in observability * [Best Practices](./best-practices.md) - General platform best practices * [Billing](./billing.md) - Understand billing and manage costs * [CLI Commands](/cli/commands.md) - Full CLI reference # Manage projects (/guides/projects) This page shows how to work with projects. For what projects are and how they relate to organizations and services, read [Accounts, organizations, and projects](/guides/account-model). Every service lives in one project, and the CLI always acts on your active project. ## Create a project [#create-a-project] ```bash acc projects create --name my-app acc projects list ``` In the web app, open **Projects** and create one from there. The new project belongs to the organization you currently have selected. ## See and switch the active project [#see-and-switch-the-active-project] ```bash acc whoami # shows who you are and the active project acc projects switch # pick from a list acc projects switch # or name the project directly ``` To act on another project for one command, pass it explicitly: ```bash acc services list -p acc deployments --project ``` ## Point CI or an agent at a project [#point-ci-or-an-agent-at-a-project] Set two environment variables. Every command then runs against that project without prompts; add `-y` to commands that ask for confirmation. ```bash export AF_TOKEN="..." # a personal access token, see Create and use access tokens export AF_PROJECT_ID="..." # from acc projects list acc whoami --json acc services deploy -y ``` Use one project per environment (for example `my-app-staging` and `my-app-production`) and give each pipeline its own `AF_PROJECT_ID`. ## Rename a project [#rename-a-project] ```bash acc projects update ``` ## Invite people [#invite-people] People are invited at the organization level, and access to projects is set per person. In the web app, open **Members** (owners and admins only) and send an invitation. Choose a role, and for a member, choose whether they can see all projects or only selected ones. Inviting requires an active paid subscription. Roles are explained in [Accounts, organizations, and projects](/guides/account-model#roles). ## Delete a project [#delete-a-project] Deleting a project deletes every service in it and closes their deployments. ```bash acc projects delete ``` Before deleting, run `acc services list -p ` and make sure nothing there is still needed. ## Next steps [#next-steps] * [Accounts, organizations, and projects](/guides/account-model) * [Create and use access tokens](/guides/api-keys) * [Manage billing and credits](/guides/billing) # Quick start (/guides/quickstart) Get started with Alternate Clouds in minutes. This guide walks you through installing the CLI, authenticating, and deploying your first service to decentralized compute. ## What You'll Learn [#what-youll-learn] By the end of this guide, you'll have: * Installed the `acc` CLI * Authenticated with the platform * Deployed your first service (a container) to decentralized infrastructure * Checked its logs and URL **Time to complete:** 5-10 minutes ## Prerequisites [#prerequisites] Before you begin, make sure you have: * **An Alternate Clouds account** - [Sign up here](https://clouds.alternatefutures.ai) * Sign in with email or an Ethereum wallet; your account is created on first successful verification. * New accounts start a 14-day trial - free, no credit card required. * **Node.js 18.18.2 or later** - [Download here](https://nodejs.org/en/download) if you don't have it * Check your version with `node --version` ## Step 1: Install the CLI [#step-1-install-the-cli] ```bash npm install -g @alternatefutures/acc acc --version ``` ## Step 2: Log in [#step-2-log-in] ```bash acc login ``` This opens the browser so you can approve the CLI session. On a headless machine use `acc login --email` instead. Verify: ```bash acc whoami ``` ## Step 3: Create a project [#step-3-create-a-project] Services live inside projects. ```bash acc projects create --name hello-clouds acc projects list ``` ## Step 4: Deploy your first service [#step-4-deploy-your-first-service] The fastest first deploy is a plain container: ```bash acc services create --kind docker --image nginx:latest --port 80 --name hello-web -y ``` Or start from the template catalog (AI agents, databases, and more): ```bash acc templates list acc services create --kind template --template -y ``` Want verifiable confidential compute? Add `--confidential` to deploy on a TEE. ## Step 5: Watch it come up [#step-5-watch-it-come-up] ```bash acc services list # status and URL acc services info # full details for a service acc services logs --tail 100 ``` Once the service is running, `acc services list` shows its public URL (`https://-app.alternatefutures.ai`). ## Step 6: Manage it [#step-6-manage-it] ```bash acc services deploy # redeploy after changes acc services env set KEY VALUE acc ssh # shell into the running container acc services close # stop billing for it ``` ## Where to go next [#where-to-go-next] * [CLI command reference](/cli/commands) - every command and flag * [Projects](/guides/projects) - organize services and teams * [Billing](/guides/billing) - credits, topups, and budgets * [Authentication](/guides/authentication) - all sign-in methods Automating this? Use `acc pat create` for a token, export `AF_TOKEN` and `AF_PROJECT_ID`, and every command above works non-interactively (add `-y`). Machine-readable docs: [/llms.txt](/llms.txt). # Registry architecture (/guides/registry-architecture) Deep dive into the technical architecture of the decentralized container registry. ## System Overview [#system-overview] The Alternate Futures registry is a **fully decentralized** container registry built on open-source components running on Akash Network with IPFS storage. ``` ┌────────────────────────────────────────────────────────────┐ │ Decentralized Registry Stack │ ├────────────────────────────────────────────────────────────┤ │ │ │ ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ │ │ │ │ │ │ │ │ │ │ │ PostgreSQL │◄───┤ OpenRegistry │────► IPFS (Kubo) │ │ │ │ │ │ │ │ │ │ │ │ Metadata │ │ OCI API │ │ Storage │ │ │ │ │ │ │ │ │ │ │ └─────────────┘ └──────────────┘ └──────────────┘ │ │ │ │ │ │ │ │ │ │ │ │ └───────────────────┴─────────────────────┘ │ │ │ │ │ Akash Network │ │ (Decentralized Compute) │ │ │ └────────────────────────────────────────────────────────────┘ ↕ DNS (Namecheap) ↕ ┌──────────────────────┐ │ Docker Client / CLI │ └──────────────────────┘ ``` ## Component Details [#component-details] ### 1. PostgreSQL [#1-postgresql] **Purpose**: Stores registry metadata and relationships. **Schema**: ```sql -- Image repositories CREATE TABLE repositories ( id SERIAL PRIMARY KEY, name VARCHAR(255) UNIQUE NOT NULL, created_at TIMESTAMP DEFAULT NOW() ); -- Image tags CREATE TABLE tags ( id SERIAL PRIMARY KEY, repository_id INT REFERENCES repositories(id), name VARCHAR(255) NOT NULL, manifest_digest VARCHAR(255) NOT NULL, created_at TIMESTAMP DEFAULT NOW(), UNIQUE(repository_id, name) ); -- Image manifests CREATE TABLE manifests ( digest VARCHAR(255) PRIMARY KEY, content_type VARCHAR(255) NOT NULL, data JSONB NOT NULL, created_at TIMESTAMP DEFAULT NOW() ); -- Blob storage (references to IPFS CIDs) CREATE TABLE blobs ( digest VARCHAR(255) PRIMARY KEY, ipfs_cid VARCHAR(255) NOT NULL, size BIGINT NOT NULL, created_at TIMESTAMP DEFAULT NOW() ); -- Blob/Manifest relationships CREATE TABLE manifest_blobs ( manifest_digest VARCHAR(255) REFERENCES manifests(digest), blob_digest VARCHAR(255) REFERENCES blobs(digest), PRIMARY KEY (manifest_digest, blob_digest) ); ``` **Configuration**: * **Resources**: 1 CPU, 2GB RAM, 20GB storage * **Network**: Internal only (not exposed publicly) * **Backup**: Automated via Akash persistent storage ### 2. OpenRegistry [#2-openregistry] **Purpose**: OCI-compliant API server handling Docker client requests. **Technology**: Go-based HTTP server implementing [OCI Distribution Spec](https://github.com/opencontainers/distribution-spec). **Key Endpoints**: **Catalog API:** ```http GET /v2/_catalog → Lists all repositories ``` **Tags API:** ```http GET /v2//tags/list → Lists tags for a repository ``` **Manifest API:** ```http GET /v2//manifests/ → Returns image manifest PUT /v2//manifests/ → Uploads image manifest ``` **Blob API:** ```http GET /v2//blobs/ → Downloads blob from IPFS POST /v2//blobs/uploads/ → Initiates blob upload PUT /v2//blobs/uploads/ → Completes blob upload to IPFS ``` **Authentication Flow**: ``` Client → GET /v2/ → 401 Unauthorized ← WWW-Authenticate: Bearer realm="..." Client → POST /token (with credentials) ← {token: "..."} Client → GET /v2//manifests/ Headers: Authorization: Bearer ← 200 OK + Manifest ``` **Configuration**: * **Resources**: 2 CPU, 4GB RAM, 10GB storage * **Network**: Public HTTPS on port 5000 * **Environment**: * `OPEN_REGISTRY_DB_HOST=postgres` * `OPEN_REGISTRY_DFS_IPFS_API_URL=http://ipfs:5001` ### 3. IPFS Node (Kubo) [#3-ipfs-node-kubo] **Purpose**: Decentralized storage for container image layers (blobs). **Technology**: [Kubo](https://github.com/ipfs/kubo) - Official IPFS implementation in Go. **APIs Exposed**: **Add API** (used by OpenRegistry): ```bash curl -X POST "http://ipfs:5001/api/v0/add" \ -F file=@layer.tar.gz → Returns: {"Hash": "QmXxx...", "Size": "12345"} ``` **Cat API** (retrieve content): ```bash curl "http://ipfs:5001/api/v0/cat?arg=QmXxx..." → Returns: raw file content ``` **Pin API** (ensure persistence): ```bash curl -X POST "http://ipfs:5001/api/v0/pin/add?arg=QmXxx..." → Pins content to prevent garbage collection ``` **Gateway** (public HTTP access): ```bash curl "https://ipfs.alternatefutures.ai/ipfs/QmXxx..." → Returns: content via HTTP gateway ``` **Configuration**: * **Resources**: 2 CPU, 4GB RAM, 100GB storage * **Network**: * API (5001): Internal only * Gateway (8080): Public HTTPS * Swarm (4001): Public TCP (P2P) * **Profile**: `server` (optimized for production) **Storage Structure**: ``` /data/ipfs/ ├── blocks/ # IPFS blocks (actual content) │ ├── QmXxx.../ │ └── QmYyy.../ ├── datastore/ # Metadata └── config # Node configuration ``` ### 4. Akash Network [#4-akash-network] **Purpose**: Decentralized compute platform hosting all services. **Provider Selection**: * Providers bid on deployments * You choose based on price, location, reputation * Multi-provider redundancy possible **Resource Allocation**: ```yaml profiles: compute: postgres: # 1 CPU, 2GB RAM, 20GB storage ipfs: # 2 CPU, 4GB RAM, 100GB storage registry: # 2 CPU, 4GB RAM, 10GB storage Total: 5 CPUs, 10GB RAM, 130GB storage Estimated cost: ~$40-70/month ``` **Persistent Storage**: * Data persists across deployments * Backed by provider's infrastructure * Redundant storage recommended ## Data Flow [#data-flow] ### Push Image Flow [#push-image-flow] ``` ┌──────────┐ │ Docker │ │ Client │ └────┬─────┘ │ 1. docker push registry.alternatefutures.ai/app:v1 ▼ ┌──────────────┐ │ OpenRegistry │ └──────┬───────┘ │ 2. Split into layers (blobs) │ │ For each layer: ├─► 3. POST to IPFS /api/v0/add │ ▼ │ ┌──────────┐ │ │ IPFS │ │ │ (Kubo) │ │ └────┬─────┘ │ │ 4. Returns CID: QmXxx... │ │ 5. Pin CID ◄────────┘ │ │ 6. Store mapping in PostgreSQL: ▼ ┌──────────────┐ │ PostgreSQL │ │ │ │ blobs: │ │ - digest │ │ - ipfs_cid │ │ - size │ └──────────────┘ ``` **Example**: ```bash # Client pushes image docker push registry.alternatefutures.ai/app:v1 # OpenRegistry receives: # - Config blob (JSON with metadata) # - Layer 1: base OS # - Layer 2: dependencies # - Layer 3: application code # - Manifest (references all blobs) # For Layer 1 (100MB): # → Upload to IPFS: POST /api/v0/add # ← Response: QmAbc123... # → Pin: POST /api/v0/pin/add?arg=QmAbc123... # → Save to DB: INSERT INTO blobs VALUES ( # 'sha256:abc...', 'QmAbc123...', 104857600 # ) # Repeat for all layers # Store manifest referencing all layer digests ``` ### Pull Image Flow [#pull-image-flow] ``` ┌──────────┐ │ Docker │ │ Client │ └────┬─────┘ │ 1. docker pull registry.alternatefutures.ai/app:v1 ▼ ┌──────────────┐ │ OpenRegistry │ └──────┬───────┘ │ 2. Query PostgreSQL for manifest ▼ ┌──────────────┐ │ PostgreSQL │ └──────┬───────┘ │ 3. Returns: manifest with layer digests ▼ ┌──────────────┐ │ OpenRegistry │ └──────┬───────┘ │ 4. For each layer digest: │ Query PostgreSQL for IPFS CID ▼ ┌──────────────┐ │ PostgreSQL │ └──────┬───────┘ │ 5. Returns: blob.ipfs_cid = QmXxx... ▼ ┌──────────────┐ │ OpenRegistry │ └──────┬───────┘ │ 6. GET from IPFS /api/v0/cat?arg=QmXxx... ▼ ┌──────────┐ │ IPFS │ │ (Kubo) │ └────┬─────┘ │ 7. Returns: raw layer content ▼ ┌──────────────┐ │ OpenRegistry │ └──────┬───────┘ │ 8. Stream to Docker client ▼ ┌──────────┐ │ Docker │ │ Client │ └──────────┘ ``` ## Security Architecture [#security-architecture] ### Authentication [#authentication] **Token-based auth** using JWT: ``` ┌─────────┐ ┌──────────────┐ │ Client │──1. GET /v2/──────────────►│ OpenRegistry │ │ │◄──401 + WWW-Authenticate──┤ │ │ │ └──────────────┘ │ │ │ │──2. POST /token───────────►┌──────────────┐ │ │ (username, password) │ Auth Service │ │ │◄──{token: "eyJhb..."}──────┤ │ │ │ └──────────────┘ │ │ │ │──3. GET /v2//...────►┌──────────────┐ │ │ Header: Authorization │ OpenRegistry │ │ │ Bearer eyJhb... │ │ │ │◄──200 OK + Data───────────┤ │ └─────────┘ └──────────────┘ ``` **JWT Structure**: ```json { "header": { "alg": "RS256", "typ": "JWT" }, "payload": { "sub": "username", "iss": "registry.alternatefutures.ai", "aud": "registry.alternatefutures.ai", "exp": 1709251200, "iat": 1709247600, "access": [ { "type": "repository", "name": "myapp", "actions": ["pull", "push"] } ] } } ``` ### Network Security [#network-security] **Internal Network** (service-to-service): ``` registry ──► postgres:5432 (SQL queries) registry ──► ipfs:5001 (IPFS API) ``` Not exposed publicly. **External Network** (public endpoints): ``` Internet ──► registry.alternatefutures.ai:443 (HTTPS) Internet ──► ipfs.alternatefutures.ai:443 (HTTPS Gateway) Internet ──► ipfs.alternatefutures.ai:4001 (IPFS Swarm) ``` **TLS**: Automatic via Akash provider Let's Encrypt integration. ### Data Integrity [#data-integrity] **Content Addressing** ensures integrity: 1. Client uploads layer 2. OpenRegistry computes SHA256: `sha256:abc123...` 3. IPFS stores and returns CID: `QmXxx...` (also a hash) 4. Both hashes stored in database 5. On pull, verify SHA256 matches **Tampering detection**: Any modification changes the hash, invalidating the image. ## Performance Optimization [#performance-optimization] ### Caching Strategy [#caching-strategy] **Layer Deduplication**: * Identical layers share the same IPFS CID * Only stored once, referenced multiple times * Saves storage and bandwidth Example: ``` Image A: ubuntu:22.04 (200MB) + app1 (50MB) Image B: ubuntu:22.04 (200MB) + app2 (60MB) Storage: - ubuntu:22.04 → QmUbuntu... (200MB) [shared] - app1 → QmApp1... (50MB) - app2 → QmApp2... (60MB) Total: 310MB (not 510MB!) ``` ### IPFS Optimization [#ipfs-optimization] **Pinning Strategy**: * All blobs pinned immediately on upload * Prevents garbage collection * Ensures availability **Blockstore settings**: ```json { "Datastore": { "StorageMax": "100GB", "StorageGCWatermark": 90, // GC at 90% full "GCPeriod": "1h" } } ``` ### Database Indexing [#database-indexing] ```sql -- Fast lookups by repository name CREATE INDEX idx_repos_name ON repositories(name); -- Fast tag lookups CREATE INDEX idx_tags_repo_name ON tags(repository_id, name); -- Fast manifest lookups CREATE INDEX idx_manifests_digest ON manifests(digest); -- Fast blob lookups by IPFS CID CREATE INDEX idx_blobs_ipfs_cid ON blobs(ipfs_cid); ``` ## Monitoring & Observability [#monitoring--observability] ### Metrics to Track [#metrics-to-track] **Registry Metrics**: * Requests per second * Push/pull latency * Error rates * Active connections **IPFS Metrics**: * Repository size * Pin count * Bandwidth usage * Peer connections **Database Metrics**: * Query latency * Connection pool usage * Storage usage ### Health Checks [#health-checks] ```bash # Registry health curl https://registry.alternatefutures.ai/v2/ # IPFS health curl http://ipfs:5001/api/v0/id # Database health psql -c "SELECT 1" ``` ### Logging [#logging] **Structured logs** in JSON format: ```json { "timestamp": "2025-01-15T10:30:45Z", "level": "info", "service": "registry", "event": "blob_upload", "repository": "myapp", "digest": "sha256:abc...", "ipfs_cid": "QmXxx...", "size": 104857600, "duration_ms": 1234 } ``` ## Scalability [#scalability] ### Horizontal Scaling [#horizontal-scaling] **Multiple Registry Instances**: ```yaml deployment: registry: count: 3 # 3 registry instances ``` All instances share: * Same PostgreSQL database * Same IPFS node * Load balanced via Akash ### Storage Scaling [#storage-scaling] **Increase IPFS storage**: ```yaml ipfs: resources: storage: size: 500Gi # Scale from 100Gi to 500Gi ``` ### Geographic Distribution [#geographic-distribution] Deploy multiple stacks in different regions: * US: `registry-us.alternatefutures.ai` * EU: `registry-eu.alternatefutures.ai` * Asia: `registry-asia.alternatefutures.ai` Use GeoDNS to route clients to nearest instance. ## Comparison with Centralized Registries [#comparison-with-centralized-registries] | Feature | Docker Hub | Alternate Futures Registry | | ----------------- | ----------------------- | -------------------------- | | **Storage** | Centralized S3 | Decentralized IPFS | | **Compute** | AWS/GCP | Akash Network | | **Control** | Docker, Inc. | You | | **Censorship** | Possible | Resistant | | **Cost** | $7/user/month | \~$40-70/month total | | **Downtime Risk** | Single point of failure | Multi-provider redundancy | | **Privacy** | Controlled by Docker | You control all data | | **Open Source** | Proprietary | 100% FOSS | ## Future Enhancements [#future-enhancements] ### Planned Features [#planned-features] 1. **IPFS Cluster**: Multi-node IPFS for redundancy 2. **Image Signing**: Cosign integration for verification 3. **Vulnerability Scanning**: Trivy integration 4. **Replication**: Cross-region sync 5. **Analytics**: Usage dashboards 6. **Webhook**: Notifications on push/pull events ## Technical References [#technical-references] * **OCI Distribution Spec**: [https://github.com/opencontainers/distribution-spec](https://github.com/opencontainers/distribution-spec) * **OpenRegistry**: [https://github.com/containerish/OpenRegistry](https://github.com/containerish/OpenRegistry) * **IPFS Kubo**: [https://github.com/ipfs/kubo](https://github.com/ipfs/kubo) * **Akash Network**: [https://akash.network](https://akash.network) * **Docker Registry HTTP API V2**: [https://docs.docker.com/registry/spec/api/](https://docs.docker.com/registry/spec/api/) ## Next Steps [#next-steps] * [Deploy Your Registry](/guides/registry-deployment) * [Use the Registry](/guides/decentralized-registry) * [Troubleshooting](/troubleshooting) # Deploy the registry (/guides/registry-deployment) This guide walks you through deploying your own OpenRegistry + IPFS stack on Akash Network. ## Prerequisites [#prerequisites] Before you begin, ensure you have: * **Akash CLI** installed (`brew install akash-provider-services`) * **Akash wallet** with at least 5 AKT tokens * **Domain** with DNS management access (Namecheap, Cloudflare, etc.) * **Docker** installed locally ## Architecture Overview [#architecture-overview] You'll be deploying three services on Akash: ``` ┌──────────── Akash Deployment ────────────┐ │ │ │ PostgreSQL (metadata) │ │ ├─ Port: 5432 (internal) │ │ └─ Storage: 20GB │ │ │ │ IPFS Node (storage) │ │ ├─ API: 5001 (internal) │ │ ├─ Gateway: 8080 (public) │ │ ├─ Swarm: 4001 (P2P) │ │ └─ Storage: 100GB │ │ │ │ OpenRegistry (OCI API) │ │ ├─ Port: 5000 (public) │ │ └─ Storage: 10GB │ │ │ └───────────────────────────────────────────┘ ``` ## Step 1: Setup Akash CLI [#step-1-setup-akash-cli] ### Install Akash CLI [#install-akash-cli] **macOS:** ```bash brew tap akash-network/tap brew install akash-provider-services ``` **Linux:** ```bash curl -sSfL https://raw.githubusercontent.com/akash-network/node/master/install.sh | sh ``` ### Verify Installation [#verify-installation] ```bash akash version # Should output: v0.x.x ``` ### Configure Environment [#configure-environment] ```bash export AKASH_NODE=https://rpc.akash.network:443 export AKASH_CHAIN_ID=akashnet-2 export AKASH_GAS=auto export AKASH_GAS_ADJUSTMENT=1.5 export AKASH_GAS_PRICES=0.025uakt ``` Add these to your `~/.bashrc` or `~/.zshrc` to make them permanent. ## Step 2: Create Akash Wallet [#step-2-create-akash-wallet] ### Generate New Wallet [#generate-new-wallet] ```bash akash keys add registry-wallet # Save the mnemonic phrase securely! ``` ### Or Import Existing Wallet [#or-import-existing-wallet] ```bash akash keys add registry-wallet --recover # Enter your mnemonic phrase ``` ### Get Your Address [#get-your-address] ```bash export AKASH_ACCOUNT_ADDRESS=$(akash keys show registry-wallet -a) echo $AKASH_ACCOUNT_ADDRESS ``` ### Fund Your Wallet [#fund-your-wallet] You need at least 5 AKT tokens: * **Buy AKT**: [Exchanges](https://akash.network/token) * **Testnet Faucet**: [https://faucet.akash.network](https://faucet.akash.network) ### Check Balance [#check-balance] ```bash akash query bank balances $AKASH_ACCOUNT_ADDRESS --node $AKASH_NODE ``` ## Step 3: Configure Deployment [#step-3-configure-deployment] ### Download SDL File [#download-sdl-file] Download the deployment configuration: ```bash curl -O https://raw.githubusercontent.com/alternatefutures/backend/main/deploy-registry.yaml ``` ### Edit Configuration [#edit-configuration] Open `deploy-registry.yaml` and update these values: ```yaml services: postgres: env: # Change this password! - POSTGRES_PASSWORD=YOUR_SECURE_PASSWORD_HERE registry: env: # Change this JWT secret (min 32 characters) - OPEN_REGISTRY_SIGNING_SECRET=YOUR_JWT_SECRET_MIN_32_CHARS_HERE # Match PostgreSQL password - OPEN_REGISTRY_DB_PASSWORD=YOUR_SECURE_PASSWORD_HERE # Your registry domain - OPEN_REGISTRY_DOMAIN=registry.yourdomain.com expose: - port: 5000 as: 80 to: - global: true accept: # Change to your domain - registry.yourdomain.com ipfs: expose: - port: 8080 as: 8080 to: - global: true accept: # Change to your domain - ipfs.yourdomain.com ``` ### Generate Secure Passwords [#generate-secure-passwords] ```bash # Generate secure password openssl rand -base64 32 # Generate JWT secret openssl rand -base64 48 ``` ## Step 4: Deploy to Akash [#step-4-deploy-to-akash] ### Create Deployment [#create-deployment] ```bash akash tx deployment create deploy-registry.yaml \ --from registry-wallet \ --node $AKASH_NODE \ --chain-id $AKASH_CHAIN_ID \ --fees 5000uakt ``` ### Get Deployment ID [#get-deployment-id] Save the DSEQ (deployment sequence) from the output: ```bash export AKASH_DSEQ= ``` ### Wait for Bids [#wait-for-bids] Providers will send bids for your deployment (usually takes 30-60 seconds): ```bash akash query market bid list \ --owner $AKASH_ACCOUNT_ADDRESS \ --node $AKASH_NODE \ --dseq $AKASH_DSEQ ``` ### Accept a Bid [#accept-a-bid] Choose a provider and create a lease: ```bash export AKASH_PROVIDER= akash tx market lease create \ --dseq $AKASH_DSEQ \ --from registry-wallet \ --provider $AKASH_PROVIDER \ --node $AKASH_NODE \ --chain-id $AKASH_CHAIN_ID \ --fees 5000uakt ``` ### Send Manifest [#send-manifest] ```bash akash provider send-manifest deploy-registry.yaml \ --dseq $AKASH_DSEQ \ --from registry-wallet \ --provider $AKASH_PROVIDER \ --node $AKASH_NODE ``` ### Get Service Endpoints [#get-service-endpoints] ```bash akash provider lease-status \ --dseq $AKASH_DSEQ \ --from registry-wallet \ --provider $AKASH_PROVIDER \ --node $AKASH_NODE ``` Note the `forwarded_ports` - these are your public IPs and ports! ## Step 5: Configure DNS [#step-5-configure-dns] ### Get Provider IP [#get-provider-ip] From the lease status, note the provider's IP address. ### Add DNS Records [#add-dns-records] **Using Namecheap:** 1. Log into Namecheap 2. Go to Domain List → Manage → Advanced DNS 3. Add A Records: ``` Type: A Record Host: registry Value: TTL: Automatic Type: A Record Host: ipfs Value: TTL: Automatic ``` **Using Cloudflare:** ```bash # Add DNS records via CLI curl -X POST "https://api.cloudflare.com/client/v4/zones//dns_records" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ --data '{ "type": "A", "name": "registry", "content": "", "ttl": 1, "proxied": false }' curl -X POST "https://api.cloudflare.com/client/v4/zones//dns_records" \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ --data '{ "type": "A", "name": "ipfs", "content": "", "ttl": 1, "proxied": false }' ``` ### Wait for DNS Propagation [#wait-for-dns-propagation] DNS changes can take 5-60 minutes to propagate. Check status: ```bash dig registry.yourdomain.com dig ipfs.yourdomain.com ``` ## Step 6: Test Your Registry [#step-6-test-your-registry] ### Test OCI API [#test-oci-api] ```bash curl https://registry.yourdomain.com/v2/ # Should return: {} ``` ### Test IPFS Gateway [#test-ipfs-gateway] ```bash curl https://ipfs.yourdomain.com/ipfs/QmUNLLsPACCz1vLxQVkXqqLX5R1X345qqfHbsf67hvA3Nn # Should return: hello worlds ``` ### Push First Image [#push-first-image] ```bash # Build a simple image echo "FROM alpine:latest" > Dockerfile echo "CMD echo 'Hello from decentralized registry!'" >> Dockerfile docker build -t test-image . # Tag for your registry docker tag test-image registry.yourdomain.com/test-image:latest # Push docker push registry.yourdomain.com/test-image:latest ``` ### Pull Image [#pull-image] ```bash docker pull registry.yourdomain.com/test-image:latest docker run registry.yourdomain.com/test-image:latest # Should output: Hello from decentralized registry! ``` ## Step 7: Monitor Your Deployment [#step-7-monitor-your-deployment] ### View Logs [#view-logs] **Registry logs:** ```bash akash provider lease-logs \ --dseq $AKASH_DSEQ \ --from registry-wallet \ --provider $AKASH_PROVIDER \ --node $AKASH_NODE \ --service registry \ --follow ``` **IPFS logs:** ```bash akash provider lease-logs \ --dseq $AKASH_DSEQ \ --from registry-wallet \ --provider $AKASH_PROVIDER \ --node $AKASH_NODE \ --service ipfs \ --follow ``` ### Check Service Status [#check-service-status] ```bash akash provider service-status \ --dseq $AKASH_DSEQ \ --from registry-wallet \ --provider $AKASH_PROVIDER \ --node $AKASH_NODE ``` ### IPFS Stats [#ipfs-stats] Check IPFS node storage: ```bash curl http://ipfs.yourdomain.com:5001/api/v0/repo/stat | jq ``` ## Costs and Billing [#costs-and-billing] ### Estimated Monthly Cost [#estimated-monthly-cost] * **Compute**: \~$30-50/month * **Storage (130GB total)**: Included in compute cost * **Bandwidth**: Pay-as-you-go **Total**: \~$40-70/month for production-ready registry ### Monitoring Spending [#monitoring-spending] Check your deployment cost: ```bash akash query market lease list \ --owner $AKASH_ACCOUNT_ADDRESS \ --node $AKASH_NODE \ --dseq $AKASH_DSEQ ``` ### Funding Your Deployment [#funding-your-deployment] Deposits are deducted every block. Ensure your wallet has sufficient balance. Top up if needed: ```bash akash tx deployment deposit 5000000uakt \ --dseq $AKASH_DSEQ \ --from registry-wallet \ --node $AKASH_NODE ``` ## Updating Your Deployment [#updating-your-deployment] ### Update Configuration [#update-configuration] 1. Edit `deploy-registry.yaml` 2. Update the deployment: ```bash akash tx deployment update deploy-registry.yaml \ --dseq $AKASH_DSEQ \ --from registry-wallet \ --node $AKASH_NODE ``` 3. Send updated manifest: ```bash akash provider send-manifest deploy-registry.yaml \ --dseq $AKASH_DSEQ \ --from registry-wallet \ --provider $AKASH_PROVIDER \ --node $AKASH_NODE ``` ## Troubleshooting [#troubleshooting] ### Deployment Fails [#deployment-fails] **Check SDL validation:** ```bash akash deployment validate deploy-registry.yaml ``` **Common issues:** * Insufficient balance * Invalid SDL syntax * Port conflicts ### No Bids Received [#no-bids-received] **Possible causes:** * Price too low * Resource requirements too high * No providers available **Solution**: Increase bid price in SDL: ```yaml pricing: registry: amount: 2000 # Increase from 1000 ``` ### Services Not Starting [#services-not-starting] **Check logs:** ```bash akash provider lease-logs \ --dseq $AKASH_DSEQ \ --from registry-wallet \ --provider $AKASH_PROVIDER \ --node $AKASH_NODE \ --follow ``` **Common issues:** * Environment variables not set * Database connection failures * IPFS initialization errors ### DNS Not Resolving [#dns-not-resolving] **Check DNS propagation:** ```bash dig registry.yourdomain.com +trace ``` **Verify A record:** ```bash nslookup registry.yourdomain.com ``` **Clear DNS cache:** ```bash # macOS sudo dscacheutil -flushcache # Linux sudo systemctl restart systemd-resolved ``` ## Security Best Practices [#security-best-practices] ### 1. Use Strong Passwords [#1-use-strong-passwords] Generate cryptographically secure passwords: ```bash openssl rand -base64 32 ``` ### 2. Enable TLS [#2-enable-tls] Akash providers typically include Let's Encrypt automatically. Verify: ```bash curl -I https://registry.yourdomain.com # Look for: SSL certificate from Let's Encrypt ``` ### 3. Regular Backups [#3-regular-backups] Backup PostgreSQL database: ```bash # Enter the postgres container akash provider lease-shell \ --dseq $AKASH_DSEQ \ --from registry-wallet \ --provider $AKASH_PROVIDER \ --service postgres # Inside container pg_dump -U postgres open_registry > backup.sql ``` ### 4. Monitor Access [#4-monitor-access] Review registry access logs regularly: ```bash akash provider lease-logs \ --dseq $AKASH_DSEQ \ --service registry | grep "POST\|GET" ``` ## Next Steps [#next-steps] * [Use Your Registry](/guides/decentralized-registry) - Push and pull images * [CLI Integration](/cli/commands) - Add registry commands to CLI * [Troubleshooting](/troubleshooting) - Common issues and fixes ## Support [#support] Need help deploying? * [Discord Community](https://discord.gg/alternatefutures) * [Akash Discord](https://discord.gg/akash) * [GitHub Issues](https://github.com/alternatefutures/backend/issues) # Deploying sites (/guides/sites) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. Deploy static sites to decentralized storage networks (IPFS, Filecoin, Arweave). ## Deployment Methods [#deployment-methods] The web application interface (GitHub Integration and Upload Folder methods) is currently in development. In the meantime, use the CLI or SDK methods below to deploy your sites. ### GitHub Integration [#github-integration] This feature will be available once the web app launches. Deploy directly from a GitHub repository: 1. Go to **Sites** → **Deploy Site** 2. Choose **GitHub** 3. Connect your GitHub account 4. Select repository and branch 5. Configure build settings 6. Choose storage network 7. Click **Deploy** Auto-deploys on every push to the selected branch. ### Upload Folder [#upload-folder] This feature will be available once the web app launches. Deploy a local build folder: 1. Go to **Sites** → **Deploy Site** 2. Choose **Upload Folder** 3. Drag and drop your build folder (or browse) 4. Choose storage network 5. Click **Deploy** ### CLI Deployment (Available Now) [#cli-deployment-available-now] Deploy via command line: ```bash # Deploy to IPFS af sites deploy ./dist --network ipfs # Deploy to Arweave af sites deploy ./dist --network arweave # Deploy to Filecoin af sites deploy ./dist --network filecoin ``` ## Storage Networks [#storage-networks] Alternate Futures supports three decentralized storage networks. Each has different strengths, costs, and use cases. ### Choosing the Right Network [#choosing-the-right-network] Not sure which network to use? Use this decision guide: #### Quick Decision Tree [#quick-decision-tree] ``` Are you building an NFT project or need permanent, immutable storage? → YES: Use Arweave → NO: Continue... Is this a production website that updates regularly? → YES: Use IPFS (with optional Arweave backup) → NO: Continue... Do you have large files (100GB+) and need low cost? → YES: Use Filecoin → NO: Use IPFS (easiest to start) ``` #### By Use Case [#by-use-case] **Personal Portfolio (Developer/Designer)** * **Primary:** IPFS (~~$0.01/month for 100MB) or Arweave (~~$0.60 one-time) * **Why:** Show off your work with a unique, decentralized URL * **Like:** GitHub Pages but with custom domains and decentralized * **Bonus:** Content can't be taken down, great conversation starter **React/Vue/Svelte App (SPA)** * **Primary:** IPFS (\~$0.15/month for 1GB) * **Why:** Fast global CDN, frequent updates, easy deployments * **Like:** Vercel or Netlify but decentralized * **Perfect for:** SaaS frontends, admin dashboards, web apps **Static Blog (Astro/Hugo/Jekyll)** * **Primary:** IPFS with Arweave backup * **Why:** Fast loading (IPFS) + permanent archive (Arweave) * **Cost:** \~$0.05/month + \~$1.50 one-time for 250MB * **Like:** Medium or Ghost but you own everything forever **Landing Page (Marketing Site)** * **Primary:** IPFS (\~$0.02/month for 50MB) * **Why:** Frequent A/B testing, fast worldwide delivery * **Like:** Netlify but potentially cheaper for static content * **Perfect for:** Product launches, email capture, announcements **Documentation Site (Vitepress/Docusaurus/MkDocs)** * **Primary:** IPFS (\~$0.08/month for 500MB) * **Why:** Regular updates, versioning, fast search * **Like:** Read the Docs but decentralized with version history * **Bonus:** Every deployment gets a permanent CID for version linking **E-commerce Storefront (Headless Commerce)** * **Primary:** IPFS (\~$0.20/month for 2GB) * **Why:** Fast product pages, frequent inventory updates * **Like:** Shopify frontend on Vercel, but decentralized * **Perfect for:** Headless Shopify, product catalogs, storefronts **Company Website (Corporate Site)** * **Primary:** IPFS with custom domain (\~$0.10/month for 1GB) * **Why:** Professional presence, SSL included, global CDN * **Like:** Any traditional web host but censorship-resistant * **Perfect for:** About pages, team bios, contact forms **NFT Collection Website** * **Primary:** Arweave (\~$0.60 one-time for 100MB) * **Why:** Must be permanent, immutable, and verifiable * **Cost:** \~$0.60 one-time for 100MB of metadata/images * **Industry standard** for NFT projects (OpenSea expects Arweave) **Conference/Event Site (Temporary)** * **Primary:** IPFS (\~$0.05/month for 500MB) * **Why:** Short-term hosting, then can unpin to stop costs * **Like:** Quick landing page for events, cheaper than keeping domain alive * **Bonus:** Keep it pinned forever as a historical record for \~$0 more **Large Media Archive (500GB Videos/Photos)** * **Primary:** Filecoin (\~$15/month) * **Why:** Most cost-effective for large datasets * **Cost:** $15/month vs \~$75/month on IPFS or $3,000 on Arweave * **Perfect for:** Video galleries, photo archives, backups **Open Source Project Demos** * **Primary:** IPFS (\~$0.05/month for 200MB) * **Why:** Each PR can have its own CID for preview deploys * **Like:** Vercel preview deployments but with permanent CIDs * **Perfect for:** Interactive demos that need to stay accessible **Whistleblower/Leak Platform** * **Primary:** Arweave (\~$3 one-time for 500MB) * **Why:** Permanent, immutable, no server logs, no centralized control * **Like:** WikiLeaks-style platforms but truly uncensorable * **Perfect for:** Document dumps, investigative journalism, transparency initiatives * **Bonus:** Content-addressing means identical documents have same CID (deduplication) **Activist/Political Campaign Site** * **Primary:** IPFS (\~$0.05/month for 300MB) * **Why:** Can't be seized, no single hosting company to pressure * **Like:** Traditional website but immune to takedown requests * **Perfect for:** Protest organizing, political dissidents, human rights advocacy * **Bonus:** Mirror across multiple gateways for resilience **Privacy-Focused Blog (Anonymous Author)** * **Primary:** IPFS (~~$0.03/month for 150MB) or Arweave (~~$1 one-time) * **Why:** No server logs tracking visitors, no centralized owner * **Like:** Medium but without corporate surveillance * **Perfect for:** Journalists in dangerous regions, anonymous researchers * **Security tip:** Use Tor + IPFS gateway for true anonymity **Encrypted Document Archive** * **Primary:** Filecoin (\~$3/month for 100GB) + client-side encryption * **Why:** Cheap long-term storage, data encrypted before upload * **Like:** Encrypted cloud backup but decentralized * **Perfect for:** Legal documents, medical records, sensitive research * **Security:** Encrypt files locally before uploading (server never sees plaintext) **Alternative Social Network/Forum** * **Primary:** IPFS (\~$0.20/month for 2GB) * **Why:** No central authority can ban users or censor content * **Like:** Reddit/Mastodon but without moderators or corporate control * **Perfect for:** Free speech platforms, controversial discussions * **Note:** Frontend is decentralized, but consider decentralized backend too **Government/Corporate Watchdog Site** * **Primary:** Arweave (\~$6 one-time for 1GB) * **Why:** Permanent record that can't be altered or deleted * **Like:** Archive.org but immutable and censorship-proof * **Perfect for:** Tracking policy changes, preserving deleted tweets/posts * **Bonus:** Every version has verifiable timestamp on blockchain ### Network Comparison [#network-comparison] | Feature | IPFS | Filecoin | Arweave | | -------------------- | ---------------- | ---------------- | ------------ | | **Cost Structure** | Monthly | Monthly | One-time | | **Price** | \~$0.15/GB/month | \~$0.03/GB/month | \~$6/GB once | | **Update Frequency** | ✅ High | ⚠️ Moderate | ❌ Immutable | | **Speed** | ✅ Fast | ⚠️ Moderate | ✅ Fast | | **Permanence** | While pinned | Contract-based | ♾️ Forever | | **Best File Size** | Any | Large (100GB+) | Any | | **Mutability** | ✅ Via IPNS | ✅ New deals | ❌ Immutable | | **NFT-Ready** | ⚠️ Needs pinning | ⚠️ Needs pinning | ✅ Perfect | ### Understanding the Networks [#understanding-the-networks] #### IPFS (InterPlanetary File System) [#ipfs-interplanetary-file-system] **What it is:** A peer-to-peer network where files are identified by their content, not location. **How it works:** 1. Your files get a unique ID (CID) based on their content 2. Files are "pinned" to ensure they stay available 3. Content is retrieved from the nearest available node 4. Like BitTorrent, but for websites **Pros:** * ✅ Fast global distribution via CDN gateways * ✅ Easy to update (IPNS support) * ✅ Most similar to traditional hosting * ✅ Great ecosystem and tooling **Cons:** * ❌ Requires active pinning (monthly cost) * ❌ Content disappears if unpinned * ❌ Not truly permanent **Best for:** Frequently updated sites, fast propagation **Pricing:** \~$0.15/GB/month **Real Example:** A 500MB React app costs \~$0.08/month. If you update it weekly, IPFS makes sense because updates are easy. #### Filecoin [#filecoin] **What it is:** A blockchain-based storage marketplace where you make "deals" with storage providers. **How it works:** 1. You create a storage deal with a miner 2. The miner stores your data and provides cryptographic proofs 3. You pay for the storage duration 4. Compatible with IPFS for retrieval **Pros:** * ✅ 5x cheaper than IPFS for large files * ✅ Cryptographic proof your data is stored * ✅ Decentralized marketplace * ✅ IPFS-compatible **Cons:** * ❌ Slower than IPFS for small files * ❌ More complex setup * ❌ Deal negotiation required **Best for:** Long-term archival, data preservation, large datasets **Pricing:** \~$0.03/GB/month **Real Example:** A 200GB video archive costs \~$6/month on Filecoin vs \~$30/month on IPFS. #### Arweave [#arweave] **What it is:** A blockchain that offers permanent, pay-once storage that lasts forever. **How it works:** 1. You pay a one-time fee upfront 2. Your data is stored permanently on the "blockweave" 3. Economic incentives ensure miners store it forever 4. Cannot be updated or deleted **Pros:** * ✅ Truly permanent (200+ year guarantee) * ✅ One-time payment (no recurring costs) * ✅ Built-in CDN * ✅ Perfect for NFTs and archives * ✅ Censorship-resistant **Cons:** * ❌ Higher upfront cost * ❌ Cannot update or delete content * ❌ Not suitable for frequently changing sites **Best for:** Permanent storage, immutable content, NFTs **Pricing:** One-time fee (\~$6/GB) **Real Example:** NFT metadata (1MB) costs \~$0.006 once and is stored forever. If a traditional CDN costs $0.01/month, Arweave pays for itself in 7 months and then it's free forever. ### Cost Comparison Examples [#cost-comparison-examples] Here's what different project sizes cost across networks: #### Small Blog (100MB) [#small-blog-100mb] * **IPFS:** $0.015/month → $0.18/year * **Filecoin:** $0.003/month → $0.036/year * **Arweave:** $0.60 once (free after that) * **Winner:** IPFS for frequent updates, Arweave for long-term #### Medium Website (1GB) [#medium-website-1gb] * **IPFS:** $0.15/month → $1.80/year * **Filecoin:** $0.03/month → $0.36/year * **Arweave:** $6 once * **Winner:** Filecoin after year 1, Arweave after \~3 years #### Large Archive (100GB) [#large-archive-100gb] * **IPFS:** $15/month → $180/year * **Filecoin:** $3/month → $36/year * **Arweave:** $600 once * **Winner:** Filecoin for almost all cases #### NFT Collection (500MB metadata) [#nft-collection-500mb-metadata] * **IPFS:** $0.075/month → Needs permanent pinning * **Filecoin:** $0.015/month → Needs permanent deals * **Arweave:** $3 once → Permanent, immutable, verifiable * **Winner:** Arweave (industry standard for NFTs) ## Build Configuration [#build-configuration] ### Framework Detection [#framework-detection] Automatic detection for: * **React/Vite** - `dist/` * **Next.js** - `.next/` * **SvelteKit** - `.svelte-kit/output/client/` * **Nuxt** - `.output/public/` * **Astro** - `dist/` * **Hugo** - `public/` ### Custom Build [#custom-build] Specify custom build settings: ```yaml build: command: npm run build output: dist environment: NODE_ENV: production ``` ## Custom Domains [#custom-domains] Custom domain management via the web interface is in development. For now, see [Custom Domains](./custom-domains.md) for manual DNS configuration. Point your domain to your deployment: 1. Go to site settings 2. Click **Add Custom Domain** 3. Enter your domain (e.g., `example.com`) 4. Configure DNS: * **A Record**: Point to gateway IP * **CNAME**: Point to deployment URL * **DNSLink**: Point to IPFS CID 5. Wait for propagation (\~24 hours) See [Custom Domains](./custom-domains.md) for detailed instructions. ## Deployment History [#deployment-history] Deployment history viewing via the web interface is in development. Use the CLI to view deployment history: `af sites list --history` View all deployments for a site: * **CID/Transaction ID** - Unique identifier * **Timestamp** - When deployed * **Status** - Success, failed, pending * **Size** - Total deployment size * **Cost** - Deployment cost Roll back to any previous deployment with one click. ## Next Steps [#next-steps] * [Storage Management](./storage.md) - Manage storage across networks * [Custom Domains](./custom-domains.md) - Configure DNS * [CI/CD Integration](./cicd.md) - Automate deployments # Storage management (/guides/storage) This page was written for the retired `af` CLI and the sites/storage workflow. The current CLI is `acc` (compute services), which does not include these commands yet. Commands on this page will not work with `acc`. Kept for reference while this functionality is rebuilt. The web interface for storage management is currently in development. Use the [CLI](../cli/) or [SDK](../sdk/) to manage your decentralized storage. Manage decentralized storage across IPFS, Filecoin, and Arweave. ## Storage Dashboard [#storage-dashboard] The Storage Dashboard will be available once the web app launches. View all your stored content in one place: * **Storage Items** - Files, sites, and agent data * **Network Distribution** - Storage by network (IPFS, Filecoin, Arweave) * **Total Size** - Aggregate storage usage * **Monthly Cost** - Current storage costs ## Storage Networks [#storage-networks] ### IPFS [#ipfs] **Content-addressed storage with pinning:** * Files identified by CID (Content Identifier) * Pinned via Pinata, Web3.Storage, or Lighthouse * Fast retrieval via global gateways * Mutable pointers via IPNS **Use cases:** * Website hosting * Dynamic content * Frequently updated files ### Filecoin [#filecoin] **Decentralized storage marketplace:** * Storage deals with miners * Cryptographic proof of storage * IPFS-compatible CIDs * Cost-effective for large datasets **Use cases:** * Data archival * Backup storage * Large file storage ### Arweave [#arweave] **Permanent, immutable storage:** * Pay once, store forever * Blockweave data structure * Built-in content delivery * Immutable by design **Use cases:** * NFT metadata * Legal documents * Historical records * Permanent websites ## Managing Storage Items [#managing-storage-items] Web interface for managing storage items is in development. Use CLI/SDK for now. ### View Details [#view-details] Click on any storage item to see: * **CID/Transaction ID** - Unique identifier * **Size** - File size * **Network** - Storage network * **Created** - Upload date * **Last Accessed** - Last retrieval time * **URL** - Public access link * **Pinned** - Pin status (IPFS only) ### Actions [#actions] * **Pin/Unpin** (IPFS) - Control pinning status * **Copy CID** - Copy content identifier * **Open in Gateway** - View in browser * **Download** - Download file * **Delete** - Remove from storage ### Filtering [#filtering] Filter storage items by: * **Network** - IPFS, Filecoin, Arweave * **Type** - Site, Agent, File * **Size** - Size ranges * **Date** - Upload date ### Search [#search] Search storage by: * File name * CID or transaction ID * Type or network ## Pinning Management (IPFS) [#pinning-management-ipfs] ### What is Pinning? [#what-is-pinning] Pinning keeps content available on IPFS by ensuring at least one node stores and serves it. ### Pin Providers [#pin-providers] We integrate with multiple pinning services: * **Pinata** - Fast, reliable pinning * **Web3.Storage** - Free tier available * **Lighthouse** - Filecoin-backed pinning ### Pin Status [#pin-status] * **Pinned** - Content is actively pinned * **Unpinned** - Content may become unavailable * **Pinning** - Pin operation in progress * **Failed** - Pin operation failed ## Storage Analytics [#storage-analytics] ### Usage Over Time [#usage-over-time] Track storage growth: * Daily/weekly/monthly charts * Network breakdown * Cost trends ### Cost Analysis [#cost-analysis] Understand storage costs: * Cost by network * Cost by project * Cost projections ## Next Steps [#next-steps] * [Deploying Sites](./sites.md) - Deploy sites to storage networks * [Billing](./billing.md) - Understand storage costs * [Best Practices](./best-practices.md) - Optimize storage usage # Retired af CLI guides (/legacy) The guides in this section were written for the retired `af` command line tool and its sites, storage, functions, and IPFS workflow. The current CLI is `acc`. It deploys compute services (containers, templates, GPU and confidential workloads) and does not include the `af sites`, `af storage`, `af functions`, `af ipns`, `af ens`, or `af gateways` commands. Commands on these pages will not work with `acc`. ## What to use instead [#what-to-use-instead] | You want to | Use | | -------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | Deploy a container or an app from a template | [Quick start](/guides/quickstart) and `acc services create` | | Point a domain at a service | [Custom domains](/guides/custom-domains) | | Automate deploys from CI or an agent | [Docs for AI agents](/ai-agents) and [Access tokens](/guides/api-keys) | | Host a static site | Not available in `acc` yet. Deploy the site inside a container (for example an `nginx` image that serves your build output). | | Store files on IPFS or Arweave | Not available in `acc`. The self-hosted [decentralized container registry](/guides/decentralized-registry) covers image storage on IPFS. | ## Why these pages are still here [#why-these-pages-are-still-here] They document product surface that is planned to return, and people still land on them from older tutorials. Each page carries a banner. Nothing in this section is used by the search index for "how do I" answers about `acc`. # SDK API reference (/sdk/api) {/* AUTO-GENERATED by scripts/generate-sdk-docs.mjs from @alternatefutures/sdk@0.2.3 - do not edit by hand. */} **@alternatefutures/sdk** • **Docs** *** # @alternatefutures/sdk [#alternatefuturessdk] ## Modules [#modules] * [clients/applications](clients/applications/README.md) * [clients/billing](clients/billing/README.md) * [clients/domains](clients/domains/README.md) * [clients/ens](clients/ens/README.md) * [clients/functions](clients/functions/README.md) * [clients/ipfs](clients/ipfs/README.md) * [clients/ipns](clients/ipns/README.md) * [clients/privateGateway](clients/privateGateway/README.md) * [clients/projects](clients/projects/README.md) * [clients/sites](clients/sites/README.md) * [clients/storage](clients/storage/README.md) * [clients/uploadProxy](clients/uploadProxy/README.md) * [clients/user](clients/user/README.md) * [index](index/README.md) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / clients/applications # clients/applications [#clientsapplications] ## Index [#index] ### Classes [#classes] * [ApplicationsClient](classes/ApplicationsClient.md) ### Type Aliases [#type-aliases] * [Application](type-aliases/Application.md) * [CreateApplicationArgs](type-aliases/CreateApplicationArgs.md) * [DeleteApplicationArgs](type-aliases/DeleteApplicationArgs.md) * [GetApplicationArgs](type-aliases/GetApplicationArgs.md) * [UpdateApplicationArgs](type-aliases/UpdateApplicationArgs.md) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/applications](../README.md) / ApplicationsClient # Class: ApplicationsClient [#class-applicationsclient] ## Constructors [#constructors] ### new ApplicationsClient() [#new-applicationsclient] > **new ApplicationsClient**(`options`): [`ApplicationsClient`](ApplicationsClient.md) #### Parameters [#parameters] • **options**: `ApplicationsClientOptions` #### Returns [#returns] [`ApplicationsClient`](ApplicationsClient.md) #### Defined in [#defined-in] [clients/applications.ts:53](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/applications.ts#L53) ## Methods [#methods] ### create() [#create] > **create**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-1] • **\_\_namedParameters**: [`CreateApplicationArgs`](../type-aliases/CreateApplicationArgs.md) #### Returns [#returns-1] `Promise`\<`any`> #### Defined in [#defined-in-1] [clients/applications.ts:84](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/applications.ts#L84) *** ### delete() [#delete] > **delete**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-2] • **\_\_namedParameters**: [`DeleteApplicationArgs`](../type-aliases/DeleteApplicationArgs.md) #### Returns [#returns-2] `Promise`\<`any`> #### Defined in [#defined-in-2] [clients/applications.ts:129](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/applications.ts#L129) *** ### get() [#get] > **get**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-3] • **\_\_namedParameters**: [`GetApplicationArgs`](../type-aliases/GetApplicationArgs.md) #### Returns [#returns-3] `Promise`\<`any`> #### Defined in [#defined-in-3] [clients/applications.ts:57](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/applications.ts#L57) *** ### list() [#list] > **list**(): `Promise`\<`any`> #### Returns [#returns-4] `Promise`\<`any`> #### Defined in [#defined-in-4] [clients/applications.ts:73](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/applications.ts#L73) *** ### update() [#update] > **update**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-4] • **\_\_namedParameters**: [`UpdateApplicationArgs`](../type-aliases/UpdateApplicationArgs.md) #### Returns [#returns-5] `Promise`\<`any`> #### Defined in [#defined-in-5] [clients/applications.ts:104](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/applications.ts#L104) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/applications](../README.md) / Application # Type Alias: Application [#type-alias-application] > **Application**: `Omit`\<[`createClient`](../../../index/variables/createClient.md), `"__typename"` | `"whitelistDomains"`> & `object` & `object` ## Type declaration [#type-declaration] ### whitelistDomains [#whitelistdomains] > **whitelistDomains**: `string`\[] ## Type declaration [#type-declaration-1] ### whiteLabelDomains [#whitelabeldomains] > **whiteLabelDomains**: `string`\[] ## Defined in [#defined-in-6] [clients/applications.ts:8](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/applications.ts#L8) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/applications](../README.md) / CreateApplicationArgs # Type Alias: CreateApplicationArgs [#type-alias-createapplicationargs] > **CreateApplicationArgs**: `Pick`\<[`Application`](Application.md), `"name"` | `"whitelistDomains"`> ## Defined in [#defined-in-7] [clients/applications.ts:24](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/applications.ts#L24) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/applications](../README.md) / DeleteApplicationArgs # Type Alias: DeleteApplicationArgs [#type-alias-deleteapplicationargs] > **DeleteApplicationArgs**: `Pick`\<[`Application`](Application.md), `"id"`> ## Defined in [#defined-in-8] [clients/applications.ts:33](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/applications.ts#L33) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/applications](../README.md) / GetApplicationArgs # Type Alias: GetApplicationArgs [#type-alias-getapplicationargs] > **GetApplicationArgs**: `Pick`\<[`Application`](Application.md), `"id"`> ## Defined in [#defined-in-9] [clients/applications.ts:21](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/applications.ts#L21) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/applications](../README.md) / UpdateApplicationArgs # Type Alias: UpdateApplicationArgs [#type-alias-updateapplicationargs] > **UpdateApplicationArgs**: `Pick`\<[`Application`](Application.md), `"id"`> & `Partial`\<`Pick`\<[`Application`](Application.md), `"name"` | `"whitelistDomains"`>> ## Defined in [#defined-in-10] [clients/applications.ts:30](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/applications.ts#L30) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / clients/billing # clients/billing [#clientsbilling] ## Index [#index-1] ### Classes [#classes-1] * [BillingClient](classes/BillingClient.md) ### Type Aliases [#type-aliases-1] * [CurrentUsage](type-aliases/CurrentUsage.md) * [Customer](type-aliases/Customer.md) * [Invoice](type-aliases/Invoice.md) * [InvoiceLineItem](type-aliases/InvoiceLineItem.md) * [Payment](type-aliases/Payment.md) * [PaymentMethod](type-aliases/PaymentMethod.md) * [Subscription](type-aliases/Subscription.md) * [UsageMetric](type-aliases/UsageMetric.md) * [UsageRecord](type-aliases/UsageRecord.md) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/billing](../README.md) / BillingClient # Class: BillingClient [#class-billingclient] ## Constructors [#constructors-1] ### new BillingClient() [#new-billingclient] > **new BillingClient**(`options`): [`BillingClient`](BillingClient.md) #### Parameters [#parameters-5] • **options**: `BillingClientOptions` #### Returns [#returns-6] [`BillingClient`](BillingClient.md) #### Defined in [#defined-in-11] [clients/billing.ts:101](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L101) ## Methods [#methods-1] ### addPaymentMethod() [#addpaymentmethod] > **addPaymentMethod**(`input`): `Promise`\<`any`> Add a payment method #### Parameters [#parameters-6] • **input** • **input.blockchain?**: `string` • **input.setAsDefault?**: `boolean` • **input.stripePaymentMethodId?**: `string` • **input.walletAddress?**: `string` #### Returns [#returns-7] `Promise`\<`any`> #### Defined in [#defined-in-12] [clients/billing.ts:150](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L150) *** ### cancelSubscription() [#cancelsubscription] > **cancelSubscription**(`__namedParameters`): `Promise`\<`any`> Cancel a subscription #### Parameters [#parameters-7] • **\_\_namedParameters** • **\_\_namedParameters.id**: `string` • **\_\_namedParameters.immediately?**: `boolean` = `false` #### Returns [#returns-8] `Promise`\<`any`> #### Defined in [#defined-in-13] [clients/billing.ts:288](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L288) *** ### createSubscription() [#createsubscription] > **createSubscription**(`input`): `Promise`\<`any`> Create a subscription #### Parameters [#parameters-8] • **input** • **input.plan**: `"FREE"` | `"STARTER"` | `"PRO"` | `"ENTERPRISE"` • **input.seats?**: `number` #### Returns [#returns-9] `Promise`\<`any`> #### Defined in [#defined-in-14] [clients/billing.ts:261](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L261) *** ### generateInvoice() [#generateinvoice] > **generateInvoice**(`__namedParameters`): `Promise`\<`any`> Generate invoice #### Parameters [#parameters-9] • **\_\_namedParameters** • **\_\_namedParameters.subscriptionId**: `string` #### Returns [#returns-10] `Promise`\<`any`> #### Defined in [#defined-in-15] [clients/billing.ts:504](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L504) *** ### getActiveSubscription() [#getactivesubscription] > **getActiveSubscription**(): `Promise`\<`any`> Get active subscription #### Returns [#returns-11] `Promise`\<`any`> #### Defined in [#defined-in-16] [clients/billing.ts:237](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L237) *** ### getCurrentUsage() [#getcurrentusage] > **getCurrentUsage**(): `Promise`\<`any`> Get current usage #### Returns [#returns-12] `Promise`\<`any`> #### Defined in [#defined-in-17] [clients/billing.ts:415](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L415) *** ### getCustomer() [#getcustomer] > **getCustomer**(): `Promise`\<`any`> Get customer information #### Returns [#returns-13] `Promise`\<`any`> #### Defined in [#defined-in-18] [clients/billing.ts:108](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L108) *** ### getInvoice() [#getinvoice] > **getInvoice**(`__namedParameters`): `Promise`\<`any`> Get invoice by ID #### Parameters [#parameters-10] • **\_\_namedParameters** • **\_\_namedParameters.id**: `string` #### Returns [#returns-14] `Promise`\<`any`> #### Defined in [#defined-in-19] [clients/billing.ts:377](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L377) *** ### listInvoices() [#listinvoices] > **listInvoices**(`__namedParameters`): `Promise`\<`any`> List invoices #### Parameters [#parameters-11] • **\_\_namedParameters** = `{}` • **\_\_namedParameters.limit?**: `number` = `50` • **\_\_namedParameters.status?**: `string` #### Returns [#returns-15] `Promise`\<`any`> #### Defined in [#defined-in-20] [clients/billing.ts:339](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L339) *** ### listPaymentMethods() [#listpaymentmethods] > **listPaymentMethods**(): `Promise`\<`any`> List payment methods #### Returns [#returns-16] `Promise`\<`any`> #### Defined in [#defined-in-21] [clients/billing.ts:127](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L127) *** ### listSubscriptions() [#listsubscriptions] > **listSubscriptions**(): `Promise`\<`any`> List subscriptions #### Returns [#returns-17] `Promise`\<`any`> #### Defined in [#defined-in-22] [clients/billing.ts:213](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L213) *** ### processPayment() [#processpayment] > **processPayment**(`__namedParameters`): `Promise`\<`any`> Process a payment #### Parameters [#parameters-12] • **\_\_namedParameters** • **\_\_namedParameters.amount**: `number` • **\_\_namedParameters.currency?**: `string` = `'usd'` • **\_\_namedParameters.invoiceId?**: `string` #### Returns [#returns-18] `Promise`\<`any`> #### Defined in [#defined-in-23] [clients/billing.ts:445](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L445) *** ### recordCryptoPayment() [#recordcryptopayment] > **recordCryptoPayment**(`input`): `Promise`\<`any`> Record a crypto payment #### Parameters [#parameters-13] • **input** • **input.amount**: `number` • **input.blockchain**: `string` • **input.invoiceId?**: `string` • **input.txHash**: `string` #### Returns [#returns-19] `Promise`\<`any`> #### Defined in [#defined-in-24] [clients/billing.ts:476](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L476) *** ### removePaymentMethod() [#removepaymentmethod] > **removePaymentMethod**(`__namedParameters`): `Promise`\<`any`> Remove a payment method #### Parameters [#parameters-14] • **\_\_namedParameters** • **\_\_namedParameters.id**: `string` #### Returns [#returns-20] `Promise`\<`any`> #### Defined in [#defined-in-25] [clients/billing.ts:178](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L178) *** ### setDefaultPaymentMethod() [#setdefaultpaymentmethod] > **setDefaultPaymentMethod**(`__namedParameters`): `Promise`\<`any`> Set default payment method #### Parameters [#parameters-15] • **\_\_namedParameters** • **\_\_namedParameters.id**: `string` #### Returns [#returns-21] `Promise`\<`any`> #### Defined in [#defined-in-26] [clients/billing.ts:195](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L195) *** ### updateSubscriptionSeats() [#updatesubscriptionseats] > **updateSubscriptionSeats**(`__namedParameters`): `Promise`\<`any`> Update subscription seats #### Parameters [#parameters-16] • **\_\_namedParameters** • **\_\_namedParameters.id**: `string` • **\_\_namedParameters.seats**: `number` #### Returns [#returns-22] `Promise`\<`any`> #### Defined in [#defined-in-27] [clients/billing.ts:314](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L314) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/billing](../README.md) / CurrentUsage # Type Alias: CurrentUsage [#type-alias-currentusage] > **CurrentUsage**: [`UsageRecord`](UsageRecord.md) & `object` ## Type declaration [#type-declaration-2] ### total [#total] > **total**: `number` ## Defined in [#defined-in-28] [clients/billing.ts:90](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L90) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/billing](../README.md) / Customer # Type Alias: Customer [#type-alias-customer] > **Customer**: `object` ## Type declaration [#type-declaration-3] ### createdAt [#createdat] > **createdAt**: `Date` ### email [#email] > **email**: `string` ### id [#id] > **id**: `string` ### name [#name] > **name**: `string` ### stripeCustomerId? [#stripecustomerid] > `optional` **stripeCustomerId**: `string` ### updatedAt [#updatedat] > **updatedAt**: `Date` ## Defined in [#defined-in-29] [clients/billing.ts:5](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L5) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/billing](../README.md) / Invoice # Type Alias: Invoice [#type-alias-invoice] > **Invoice**: `object` ## Type declaration [#type-declaration-4] ### amountDue [#amountdue] > **amountDue**: `number` ### amountPaid [#amountpaid] > **amountPaid**: `number` ### createdAt [#createdat-1] > **createdAt**: `Date` ### currency [#currency] > **currency**: `string` ### dueDate? [#duedate] > `optional` **dueDate**: `Date` ### id [#id-1] > **id**: `string` ### invoiceNumber [#invoicenumber] > **invoiceNumber**: `string` ### lineItems? [#lineitems] > `optional` **lineItems**: [`InvoiceLineItem`](InvoiceLineItem.md)\[] ### paidAt? [#paidat] > `optional` **paidAt**: `Date` ### pdfUrl? [#pdfurl] > `optional` **pdfUrl**: `string` ### periodEnd [#periodend] > **periodEnd**: `Date` ### periodStart [#periodstart] > **periodStart**: `Date` ### status [#status] > **status**: `"DRAFT"` | `"OPEN"` | `"PAID"` | `"VOID"` | `"UNCOLLECTIBLE"` ### subtotal [#subtotal] > **subtotal**: `number` ### tax [#tax] > **tax**: `number` ### total [#total-1] > **total**: `number` ## Defined in [#defined-in-30] [clients/billing.ts:49](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L49) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/billing](../README.md) / InvoiceLineItem # Type Alias: InvoiceLineItem [#type-alias-invoicelineitem] > **InvoiceLineItem**: `object` ## Type declaration [#type-declaration-5] ### amount [#amount] > **amount**: `number` ### description [#description] > **description**: `string` ### id [#id-2] > **id**: `string` ### quantity [#quantity] > **quantity**: `number` ### unitPrice [#unitprice] > **unitPrice**: `number` ## Defined in [#defined-in-31] [clients/billing.ts:41](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L41) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/billing](../README.md) / Payment # Type Alias: Payment [#type-alias-payment] > **Payment**: `object` ## Type declaration [#type-declaration-6] ### amount [#amount-1] > **amount**: `number` ### blockchain? [#blockchain] > `optional` **blockchain**: `string` ### createdAt [#createdat-2] > **createdAt**: `Date` ### currency [#currency-1] > **currency**: `string` ### id [#id-3] > **id**: `string` ### status [#status-1] > **status**: `"PENDING"` | `"SUCCEEDED"` | `"FAILED"` ### txHash? [#txhash] > `optional` **txHash**: `string` ## Defined in [#defined-in-32] [clients/billing.ts:68](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L68) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/billing](../README.md) / PaymentMethod # Type Alias: PaymentMethod [#type-alias-paymentmethod] > **PaymentMethod**: `object` ## Type declaration [#type-declaration-7] ### blockchain? [#blockchain-1] > `optional` **blockchain**: `string` ### cardBrand? [#cardbrand] > `optional` **cardBrand**: `string` ### cardExpMonth? [#cardexpmonth] > `optional` **cardExpMonth**: `number` ### cardExpYear? [#cardexpyear] > `optional` **cardExpYear**: `number` ### cardLast4? [#cardlast4] > `optional` **cardLast4**: `string` ### createdAt [#createdat-3] > **createdAt**: `Date` ### id [#id-4] > **id**: `string` ### isDefault [#isdefault] > **isDefault**: `boolean` ### type [#type] > **type**: `"CARD"` | `"CRYPTO"` ### walletAddress? [#walletaddress] > `optional` **walletAddress**: `string` ## Defined in [#defined-in-33] [clients/billing.ts:14](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L14) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/billing](../README.md) / Subscription # Type Alias: Subscription [#type-alias-subscription] > **Subscription**: `object` ## Type declaration [#type-declaration-8] ### basePricePerSeat [#basepriceperseat] > **basePricePerSeat**: `number` ### cancelAt? [#cancelat] > `optional` **cancelAt**: `Date` ### createdAt [#createdat-4] > **createdAt**: `Date` ### currentPeriodEnd [#currentperiodend] > **currentPeriodEnd**: `Date` ### currentPeriodStart [#currentperiodstart] > **currentPeriodStart**: `Date` ### id [#id-5] > **id**: `string` ### plan [#plan] > **plan**: `"FREE"` | `"STARTER"` | `"PRO"` | `"ENTERPRISE"` ### seats [#seats] > **seats**: `number` ### status [#status-2] > **status**: `"ACTIVE"` | `"CANCELED"` | `"PAST_DUE"` | `"UNPAID"` ### updatedAt [#updatedat-1] > **updatedAt**: `Date` ### usageMarkup [#usagemarkup] > **usageMarkup**: `number` ## Defined in [#defined-in-34] [clients/billing.ts:27](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L27) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/billing](../README.md) / UsageMetric # Type Alias: UsageMetric [#type-alias-usagemetric] > **UsageMetric**: `object` ## Type declaration [#type-declaration-9] ### amount [#amount-2] > **amount**: `number` ### quantity [#quantity-1] > **quantity**: `number` ## Defined in [#defined-in-35] [clients/billing.ts:78](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L78) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/billing](../README.md) / UsageRecord # Type Alias: UsageRecord [#type-alias-usagerecord] > **UsageRecord**: `object` ## Type declaration [#type-declaration-10] ### bandwidth [#bandwidth] > **bandwidth**: [`UsageMetric`](UsageMetric.md) ### compute [#compute] > **compute**: [`UsageMetric`](UsageMetric.md) ### requests [#requests] > **requests**: [`UsageMetric`](UsageMetric.md) ### storage [#storage] > **storage**: [`UsageMetric`](UsageMetric.md) ## Defined in [#defined-in-36] [clients/billing.ts:83](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/billing.ts#L83) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / clients/domains # clients/domains [#clientsdomains] ## Index [#index-2] ### Classes [#classes-2] * [DomainsClient](classes/DomainsClient.md) ### Type Aliases [#type-aliases-2] * [Domain](type-aliases/Domain.md) * [Zone](type-aliases/Zone.md) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/domains](../README.md) / DomainsClient # Class: DomainsClient [#class-domainsclient] ## Constructors [#constructors-2] ### new DomainsClient() [#new-domainsclient] > **new DomainsClient**(`options`): [`DomainsClient`](DomainsClient.md) #### Parameters [#parameters-17] • **options**: `DomainsClientOptions` #### Returns [#returns-23] [`DomainsClient`](DomainsClient.md) #### Defined in [#defined-in-37] [clients/domains.ts:110](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L110) ## Methods [#methods-2] ### createCustomDomain() [#createcustomdomain] > **createCustomDomain**(`options`): `Promise`\<`any`> Creates a custom domain for a site with DNS verification. Supports multiple domain types including traditional Web2 domains and Web3 domains (ARNS, ENS, IPNS). Choose your preferred DNS verification method. #### Parameters [#parameters-18] • **options** Domain creation options • **options.domainType?**: `"WEB2"` | `"ARNS"` | `"ENS"` | `"IPNS"` = `'WEB2'` Domain type: 'WEB2' (default), 'ARNS', 'ENS', or 'IPNS' • **options.hostname**: `string` The domain hostname (e.g., 'example.com', 'mysite.eth') • **options.siteId**: `string` The ID of the site to attach the domain to • **options.verificationMethod?**: `"TXT"` | `"CNAME"` | `"A"` = `'TXT'` DNS verification method: 'TXT' (default), 'CNAME', or 'A' #### Returns [#returns-24] `Promise`\<`any`> Promise\ Domain object with verification instructions #### Examples [#examples] ```typescript // Create a standard web domain with TXT verification const domain = await sdk.domains().createCustomDomain({ siteId: 'site-123', hostname: 'example.com', verificationMethod: 'TXT', domainType: 'WEB2' }); console.log(domain.txtVerificationToken); // 'af-verify-abc123' ``` ```typescript // Create an ENS domain const ensDomain = await sdk.domains().createCustomDomain({ siteId: 'site-123', hostname: 'mysite.eth', domainType: 'ENS' }); ``` ```typescript // Create domain with CNAME verification const domain = await sdk.domains().createCustomDomain({ siteId: 'site-123', hostname: 'www.example.com', verificationMethod: 'CNAME' }); ``` #### Defined in [#defined-in-38] [clients/domains.ts:384](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L384) *** ### createDomain() [#createdomain] > **createDomain**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-19] • **\_\_namedParameters** • **\_\_namedParameters.hostname**: `string` • **\_\_namedParameters.zoneId**: `string` #### Returns [#returns-25] `Promise`\<`any`> #### Defined in [#defined-in-39] [clients/domains.ts:206](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L206) *** ### createZoneForPrivateGateway() [#createzoneforprivategateway] > **createZoneForPrivateGateway**(): `Promise`\<[`Zone`](../type-aliases/Zone.md)> #### Returns [#returns-26] `Promise`\<[`Zone`](../type-aliases/Zone.md)> #### Defined in [#defined-in-40] [clients/domains.ts:309](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L309) *** ### createZoneForSite() [#createzoneforsite] > **createZoneForSite**(`__namedParameters`): `Promise`\<[`Zone`](../type-aliases/Zone.md)> #### Parameters [#parameters-20] • **\_\_namedParameters** • **\_\_namedParameters.siteId**: `string` #### Returns [#returns-27] `Promise`\<[`Zone`](../type-aliases/Zone.md)> #### Defined in [#defined-in-41] [clients/domains.ts:288](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L288) *** ### deleteDomain() [#deletedomain] > **deleteDomain**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-21] • **\_\_namedParameters** • **\_\_namedParameters.domainId**: `string` #### Returns [#returns-28] `Promise`\<`any`> #### Defined in [#defined-in-42] [clients/domains.ts:231](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L231) *** ### deleteZone() [#deletezone] > **deleteZone**(`__namedParameters`): `Promise`\<[`Zone`](../type-aliases/Zone.md)> #### Parameters [#parameters-22] • **\_\_namedParameters** • **\_\_namedParameters.id**: `string` #### Returns [#returns-29] `Promise`\<[`Zone`](../type-aliases/Zone.md)> #### Defined in [#defined-in-43] [clients/domains.ts:318](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L318) *** ### get() [#get-1] > **get**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-23] • **\_\_namedParameters** • **\_\_namedParameters.domainId**: `string` #### Returns [#returns-30] `Promise`\<`any`> #### Defined in [#defined-in-44] [clients/domains.ts:141](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L141) *** ### getByHostname() [#getbyhostname] > **getByHostname**(`__namedParameters`): `Promise`\<`DomainWithRelations`> #### Parameters [#parameters-24] • **\_\_namedParameters** • **\_\_namedParameters.hostname**: `string` #### Returns [#returns-31] `Promise`\<`DomainWithRelations`> #### Defined in [#defined-in-45] [clients/domains.ts:161](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L161) *** ### getVerificationInstructions() [#getverificationinstructions] > **getVerificationInstructions**(`options`): `Promise`\<`any`> Retrieves DNS verification instructions for a domain. Returns detailed instructions on which DNS records to add for domain verification. Instructions include record type (TXT, CNAME, or A), hostname, and value. #### Parameters [#parameters-25] • **options** Instruction retrieval options • **options.domainId**: `string` The ID of the domain #### Returns [#returns-32] `Promise`\<`any`> Promise\ Object containing DNS record instructions #### Example [#example] ```typescript // Get verification instructions const domain = await sdk.domains().createCustomDomain({ siteId: 'site-123', hostname: 'example.com' }); const instructions = await sdk.domains().getVerificationInstructions({ domainId: domain.id }); console.log(instructions.instructions); // Output: "Add a TXT record to your DNS..." console.log(instructions.recordType); // "TXT" console.log(instructions.value); // "af-verify-abc123" ``` #### Defined in [#defined-in-46] [clients/domains.ts:629](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L629) *** ### getZone() [#getzone] > **getZone**(`__namedParameters`): `Promise`\<[`Zone`](../type-aliases/Zone.md)> #### Parameters [#parameters-26] • **\_\_namedParameters** • **\_\_namedParameters.id**: `string` #### Returns [#returns-33] `Promise`\<[`Zone`](../type-aliases/Zone.md)> #### Defined in [#defined-in-47] [clients/domains.ts:272](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L272) *** ### list() [#list-1] > **list**(): `Promise`\<`any`> #### Returns [#returns-34] `Promise`\<`any`> #### Defined in [#defined-in-48] [clients/domains.ts:116](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L116) *** ### listByZoneId() [#listbyzoneid] > **listByZoneId**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-27] • **\_\_namedParameters** • **\_\_namedParameters.zoneId**: `string` #### Returns [#returns-35] `Promise`\<`any`> #### Defined in [#defined-in-49] [clients/domains.ts:183](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L183) *** ### listDomainsForSite() [#listdomainsforsite] > **listDomainsForSite**(`options`): `Promise`\<`any`> Lists all custom domains associated with a site. Returns all domains (verified and unverified) configured for the specified site. Includes domain status, SSL information, and verification details. #### Parameters [#parameters-28] • **options** List options • **options.siteId**: `string` The ID of the site #### Returns [#returns-36] `Promise`\<`any`> Promise\ Array of domain objects #### Examples [#examples-1] ```typescript // List all domains for a site const domains = await sdk.domains().listDomainsForSite({ siteId: 'site-123' }); domains.forEach(domain => { console.log(`${domain.hostname}: ${domain.verified ? 'Verified' : 'Pending'}`); console.log(`SSL: ${domain.sslStatus}`); }); ``` ```typescript // Filter domains by status const domains = await sdk.domains().listDomainsForSite({ siteId: 'site-123' }); const verified = domains.filter(d => d.verified); const withSsl = domains.filter(d => d.sslStatus === 'ACTIVE'); const web3 = domains.filter(d => ['ENS', 'ARNS', 'IPNS'].includes(d.domainType)); console.log(`Verified: ${verified.length}, SSL Active: ${withSsl.length}, Web3: ${web3.length}`); ``` #### Defined in [#defined-in-50] [clients/domains.ts:683](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L683) *** ### listZones() [#listzones] > **listZones**(): `Promise`\<[`Zone`](../type-aliases/Zone.md)\[]> #### Returns [#returns-37] `Promise`\<[`Zone`](../type-aliases/Zone.md)\[]> #### Defined in [#defined-in-51] [clients/domains.ts:263](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L263) *** ### provisionSsl() [#provisionssl] > **provisionSsl**(`options`): `Promise`\<`any`> Provisions an SSL certificate for a verified domain. Automatically provisions and configures an SSL certificate for your custom domain. The certificate is issued via Let's Encrypt and includes automatic renewal. Domain must be verified before SSL can be provisioned. #### Parameters [#parameters-29] • **options** SSL provisioning options • **options.domainId**: `string` The ID of the verified domain • **options.email**: `string` Contact email for SSL expiration notifications and renewal alerts #### Returns [#returns-38] `Promise`\<`any`> Promise\ Updated domain object with SSL status #### Example [#example-1] ```typescript // Provision SSL after domain verification const domainWithSsl = await sdk.domains().provisionSsl({ domainId: 'domain-123', email: 'admin@example.com' }); console.log(domainWithSsl.sslStatus); // 'PENDING' or 'ACTIVE' console.log(domainWithSsl.sslAutoRenew); // true ``` #### Defined in [#defined-in-52] [clients/domains.ts:481](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L481) *** ### removeCustomDomain() [#removecustomdomain] > **removeCustomDomain**(`options`): `Promise`\<`any`> Removes a custom domain from a site. Permanently deletes a custom domain. This action cannot be undone. The domain can be re-added later if needed. #### Parameters [#parameters-30] • **options** Deletion options • **options.domainId**: `string` The ID of the domain to remove #### Returns [#returns-39] `Promise`\<`any`> Promise\ True if deletion successful #### Examples [#examples-2] ```typescript // Remove a domain await sdk.domains().removeCustomDomain({ domainId: 'domain-123' }); ``` ```typescript // Remove all unverified domains const domains = await sdk.domains().listDomainsForSite({ siteId: 'site-123' }); const unverified = domains.filter(d => !d.verified); for (const domain of unverified) { await sdk.domains().removeCustomDomain({ domainId: domain.id }); } ``` #### Defined in [#defined-in-53] [clients/domains.ts:586](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L586) *** ### setPrimaryDomain() [#setprimarydomain] > **setPrimaryDomain**(`options`): `Promise`\<`any`> Sets a domain as the primary domain for a site. The primary domain is the main domain used to access your site. Only one domain can be set as primary per site. #### Parameters [#parameters-31] • **options** Primary domain options • **options.domainId**: `string` The ID of the domain to set as primary • **options.siteId**: `string` The ID of the site #### Returns [#returns-40] `Promise`\<`any`> Promise\ True if successful #### Examples [#examples-3] ```typescript // Set primary domain for a site await sdk.domains().setPrimaryDomain({ siteId: 'site-123', domainId: 'domain-456' }); ``` ```typescript // Switch primary domain const domains = await sdk.domains().listDomainsForSite({ siteId: 'site-123' }); const newPrimary = domains.find(d => d.hostname === 'www.example.com'); await sdk.domains().setPrimaryDomain({ siteId: 'site-123', domainId: newPrimary.id }); ``` #### Defined in [#defined-in-54] [clients/domains.ts:535](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L535) *** ### verifyCustomDomain() [#verifycustomdomain] > **verifyCustomDomain**(`options`): `Promise`\<`any`> Verifies domain ownership via DNS record check. This checks if the required DNS records (TXT, CNAME, or A) have been properly configured and are propagating correctly. DNS propagation can take up to 48 hours. #### Parameters [#parameters-32] • **options** Verification options • **options.domainId**: `string` The ID of the domain to verify #### Returns [#returns-41] `Promise`\<`any`> Promise\ True if verification successful, false otherwise #### Example [#example-2] ```typescript // Verify domain after adding DNS records const domain = await sdk.domains().createCustomDomain({ siteId: 'site-123', hostname: 'example.com' }); // Add DNS record as instructed, then verify const isVerified = await sdk.domains().verifyCustomDomain({ domainId: domain.id }); if (isVerified) { console.log('Domain verified successfully!'); } ``` #### Defined in [#defined-in-55] [clients/domains.ts:442](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L442) *** ### verifyDomain() [#verifydomain] > **verifyDomain**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-33] • **\_\_namedParameters** • **\_\_namedParameters.domainId**: `string` #### Returns [#returns-42] `Promise`\<`any`> #### Defined in [#defined-in-56] [clients/domains.ts:247](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L247) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/domains](../README.md) / Domain # Type Alias: Domain [#type-alias-domain] > **Domain**: `Pick`\<[`createClient`](../../../index/variables/createClient.md), `"id"` | `"zone"` | `"hostname"` | `"isVerified"` | `"updatedAt"` | `"createdAt"` | `"dnsConfigs"` | `"status"`> & `object` ## Type declaration [#type-declaration-11] ### arnsName? [#arnsname] > `optional` **arnsName**: `string` ### dnsCheckAttempts? [#dnscheckattempts] > `optional` **dnsCheckAttempts**: `number` ### dnsVerifiedAt? [#dnsverifiedat] > `optional` **dnsVerifiedAt**: `string` ### domainType? [#domaintype] > `optional` **domainType**: `"WEB2"` | `"ARNS"` | `"ENS"` | `"IPNS"` ### ensName? [#ensname] > `optional` **ensName**: `string` ### expectedARecord? [#expectedarecord] > `optional` **expectedARecord**: `string` ### expectedCname? [#expectedcname] > `optional` **expectedCname**: `string` ### ipnsHash? [#ipnshash] > `optional` **ipnsHash**: `string` ### lastDnsCheck? [#lastdnscheck] > `optional` **lastDnsCheck**: `string` ### sslAutoRenew? [#sslautorenew] > `optional` **sslAutoRenew**: `boolean` ### sslExpiresAt? [#sslexpiresat] > `optional` **sslExpiresAt**: `string` ### sslIssuedAt? [#sslissuedat] > `optional` **sslIssuedAt**: `string` ### sslStatus? [#sslstatus] > `optional` **sslStatus**: `"NONE"` | `"PENDING"` | `"ACTIVE"` | `"EXPIRED"` | `"FAILED"` ### txtVerificationStatus? [#txtverificationstatus] > `optional` **txtVerificationStatus**: `"PENDING"` | `"VERIFIED"` | `"FAILED"` ### txtVerificationToken? [#txtverificationtoken] > `optional` **txtVerificationToken**: `string` ### verified? [#verified] > `optional` **verified**: `boolean` ## Defined in [#defined-in-57] [clients/domains.ts:23](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L23) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/domains](../README.md) / Zone # Type Alias: Zone [#type-alias-zone] > **Zone**: `Pick`\<[`createClient`](../../../index/variables/createClient.md), `"id"` | `"originUrl"` | `"createdAt"` | `"updatedAt"` | `"type"` | `"status"`> ## Defined in [#defined-in-58] [clients/domains.ts:53](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/domains.ts#L53) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / clients/ens # clients/ens [#clientsens] ## Index [#index-3] ### Classes [#classes-3] * [EnsClient](classes/EnsClient.md) ### Type Aliases [#type-aliases-3] * [EnsRecord](type-aliases/EnsRecord.md) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/ens](../README.md) / EnsClient # Class: EnsClient [#class-ensclient] ## Constructors [#constructors-3] ### new EnsClient() [#new-ensclient] > **new EnsClient**(`options`): [`EnsClient`](EnsClient.md) #### Parameters [#parameters-34] • **options**: `EnsClientOptions` #### Returns [#returns-43] [`EnsClient`](EnsClient.md) #### Defined in [#defined-in-59] [clients/ens.ts:40](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ens.ts#L40) ## Methods [#methods-3] ### create() [#create-1] > **create**(`__namedParameters`): `Promise`\<[`EnsRecord`](../type-aliases/EnsRecord.md)> #### Parameters [#parameters-35] • **\_\_namedParameters** • **\_\_namedParameters.ipnsRecordId**: `string` • **\_\_namedParameters.name**: `string` • **\_\_namedParameters.siteId**: `string` #### Returns [#returns-44] `Promise`\<[`EnsRecord`](../type-aliases/EnsRecord.md)> #### Defined in [#defined-in-60] [clients/ens.ts:44](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ens.ts#L44) *** ### delete() [#delete-1] > **delete**(`__namedParameters`): `Promise`\<[`EnsRecord`](../type-aliases/EnsRecord.md)> #### Parameters [#parameters-36] • **\_\_namedParameters** • **\_\_namedParameters.id**: `string` #### Returns [#returns-45] `Promise`\<[`EnsRecord`](../type-aliases/EnsRecord.md)> #### Defined in [#defined-in-61] [clients/ens.ts:120](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ens.ts#L120) *** ### get() [#get-2] > **get**(`__namedParameters`): `Promise`\<[`EnsRecord`](../type-aliases/EnsRecord.md)> #### Parameters [#parameters-37] • **\_\_namedParameters** • **\_\_namedParameters.id**: `string` #### Returns [#returns-46] `Promise`\<[`EnsRecord`](../type-aliases/EnsRecord.md)> #### Defined in [#defined-in-62] [clients/ens.ts:72](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ens.ts#L72) *** ### getByName() [#getbyname] > **getByName**(`__namedParameters`): `Promise`\<[`EnsRecord`](../type-aliases/EnsRecord.md)> #### Parameters [#parameters-38] • **\_\_namedParameters** • **\_\_namedParameters.name**: `string` #### Returns [#returns-47] `Promise`\<[`EnsRecord`](../type-aliases/EnsRecord.md)> #### Defined in [#defined-in-63] [clients/ens.ts:88](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ens.ts#L88) *** ### list() [#list-2] > **list**(): `Promise`\<[`EnsRecord`](../type-aliases/EnsRecord.md)\[]> #### Returns [#returns-48] `Promise`\<[`EnsRecord`](../type-aliases/EnsRecord.md)\[]> #### Defined in [#defined-in-64] [clients/ens.ts:136](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ens.ts#L136) *** ### listByIpnsRecordId() [#listbyipnsrecordid] > **listByIpnsRecordId**(`__namedParameters`): `Promise`\<[`EnsRecord`](../type-aliases/EnsRecord.md)\[]> #### Parameters [#parameters-39] • **\_\_namedParameters** • **\_\_namedParameters.ipnsRecordId**: `string` #### Returns [#returns-49] `Promise`\<[`EnsRecord`](../type-aliases/EnsRecord.md)\[]> #### Defined in [#defined-in-65] [clients/ens.ts:149](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ens.ts#L149) *** ### verify() [#verify] > **verify**(`__namedParameters`): `Promise`\<[`EnsRecord`](../type-aliases/EnsRecord.md)> #### Parameters [#parameters-40] • **\_\_namedParameters** • **\_\_namedParameters.id**: `string` #### Returns [#returns-50] `Promise`\<[`EnsRecord`](../type-aliases/EnsRecord.md)> #### Defined in [#defined-in-66] [clients/ens.ts:104](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ens.ts#L104) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/ens](../README.md) / EnsRecord # Type Alias: EnsRecord [#type-alias-ensrecord] > **EnsRecord**: `Omit`\<[`createClient`](../../../index/variables/createClient.md), `"site"` | `"ipnsRecord"`> & `object` ## Type declaration [#type-declaration-12] ### ipnsRecord [#ipnsrecord] > **ipnsRecord**: `Pick`\<[`createClient`](../../../index/variables/createClient.md)\[`"ipnsRecord"`], `"id"` | `"name"` | `"hash"`> & `object` #### Type declaration [#type-declaration-13] ##### id [#id-6] > **id**: `string` ### site [#site] > **site**: `Pick`\<[`createClient`](../../../index/variables/createClient.md)\[`"site"`], `"id"`> ## Defined in [#defined-in-67] [clients/ens.ts:7](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ens.ts#L7) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / clients/functions # clients/functions [#clientsfunctions] ## Index [#index-4] ### Classes [#classes-4] * [FunctionsClient](classes/FunctionsClient.md) ### Type Aliases [#type-aliases-4] * [AFFunction](type-aliases/AFFunction.md) * [CreateAFFunctionArgs](type-aliases/CreateAFFunctionArgs.md) * [DeleteAFFunctionArgs](type-aliases/DeleteAFFunctionArgs.md) * [DeployAFFunctionArgs](type-aliases/DeployAFFunctionArgs.md) * [GetAFFunctionArgs](type-aliases/GetAFFunctionArgs.md) * [ListAFFunctionArgs](type-aliases/ListAFFunctionArgs.md) * [UpdateAFFunctionArgs](type-aliases/UpdateAFFunctionArgs.md) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/functions](../README.md) / FunctionsClient # Class: FunctionsClient [#class-functionsclient] ## Constructors [#constructors-4] ### new FunctionsClient() [#new-functionsclient] > **new FunctionsClient**(`options`): [`FunctionsClient`](FunctionsClient.md) #### Parameters [#parameters-41] • **options**: `FunctionsClientOptions` #### Returns [#returns-51] [`FunctionsClient`](FunctionsClient.md) #### Defined in [#defined-in-68] [clients/functions.ts:70](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/functions.ts#L70) ## Methods [#methods-4] ### create() [#create-2] > **create**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-42] • **\_\_namedParameters**: [`CreateAFFunctionArgs`](../type-aliases/CreateAFFunctionArgs.md) #### Returns [#returns-52] `Promise`\<`any`> #### Defined in [#defined-in-69] [clients/functions.ts:121](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/functions.ts#L121) *** ### delete() [#delete-2] > **delete**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-43] • **\_\_namedParameters**: [`DeleteAFFunctionArgs`](../type-aliases/DeleteAFFunctionArgs.md) #### Returns [#returns-53] `Promise`\<`any`> #### Defined in [#defined-in-70] [clients/functions.ts:156](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/functions.ts#L156) *** ### deploy() [#deploy] > **deploy**(`__namedParameters`): `Promise`\<`AFFunctionDeployment`> #### Parameters [#parameters-44] • **\_\_namedParameters**: [`DeployAFFunctionArgs`](../type-aliases/DeployAFFunctionArgs.md) #### Returns [#returns-54] `Promise`\<`AFFunctionDeployment`> #### Defined in [#defined-in-71] [clients/functions.ts:139](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/functions.ts#L139) *** ### get() [#get-3] > **get**(`__namedParameters`): `Promise`\<[`AFFunction`](../type-aliases/AFFunction.md)> #### Parameters [#parameters-45] • **\_\_namedParameters**: [`GetAFFunctionArgs`](../type-aliases/GetAFFunctionArgs.md) #### Returns [#returns-55] `Promise`\<[`AFFunction`](../type-aliases/AFFunction.md)> #### Defined in [#defined-in-72] [clients/functions.ts:74](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/functions.ts#L74) *** ### list() [#list-3] > **list**(): `Promise`\<[`AFFunction`](../type-aliases/AFFunction.md)\[]> #### Returns [#returns-56] `Promise`\<[`AFFunction`](../type-aliases/AFFunction.md)\[]> #### Defined in [#defined-in-73] [clients/functions.ts:90](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/functions.ts#L90) *** ### listDeployments() [#listdeployments] > **listDeployments**(`__namedParameters`): `Promise`\<`AFFunctionDeployment`\[]> #### Parameters [#parameters-46] • **\_\_namedParameters**: [`ListAFFunctionArgs`](../type-aliases/ListAFFunctionArgs.md) #### Returns [#returns-57] `Promise`\<`AFFunctionDeployment`\[]> #### Defined in [#defined-in-74] [clients/functions.ts:104](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/functions.ts#L104) *** ### update() [#update-1] > **update**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-47] • **\_\_namedParameters**: [`UpdateAFFunctionArgs`](../type-aliases/UpdateAFFunctionArgs.md) #### Returns [#returns-58] `Promise`\<`any`> #### Defined in [#defined-in-75] [clients/functions.ts:172](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/functions.ts#L172) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/functions](../README.md) / AFFunction # Type Alias: AFFunction [#type-alias-affunction] > **AFFunction**: `Omit`\<[`createClient`](../../../index/variables/createClient.md), `"projectId"` | `"site"`> ## Defined in [#defined-in-76] [clients/functions.ts:13](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/functions.ts#L13) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/functions](../README.md) / CreateAFFunctionArgs # Type Alias: CreateAFFunctionArgs [#type-alias-createaffunctionargs] > **CreateAFFunctionArgs**: `object` ## Type declaration [#type-declaration-14] ### name [#name-1] > **name**: `string` ### routes? [#routes] > `optional` **routes**: `Record`\<`string`, `string`> ### siteId? [#siteid] > `optional` **siteId**: `string` ## Defined in [#defined-in-77] [clients/functions.ts:18](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/functions.ts#L18) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/functions](../README.md) / DeleteAFFunctionArgs # Type Alias: DeleteAFFunctionArgs [#type-alias-deleteaffunctionargs] > **DeleteAFFunctionArgs**: `object` ## Type declaration [#type-declaration-15] ### id [#id-7] > **id**: `string` ## Defined in [#defined-in-78] [clients/functions.ts:23](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/functions.ts#L23) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/functions](../README.md) / DeployAFFunctionArgs # Type Alias: DeployAFFunctionArgs [#type-alias-deployaffunctionargs] > **DeployAFFunctionArgs**: `object` ## Type declaration [#type-declaration-16] ### assetsCid? [#assetscid] > `optional` **assetsCid**: `string` ### blake3Hash? [#blake3hash] > `optional` **blake3Hash**: `string` ### cid [#cid] > **cid**: `string` ### functionId [#functionid] > **functionId**: `string` ### sgx? [#sgx] > `optional` **sgx**: `boolean` ## Defined in [#defined-in-79] [clients/functions.ts:33](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/functions.ts#L33) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/functions](../README.md) / GetAFFunctionArgs # Type Alias: GetAFFunctionArgs [#type-alias-getaffunctionargs] > **GetAFFunctionArgs**: `object` ## Type declaration [#type-declaration-17] ### name [#name-2] > **name**: `string` ## Defined in [#defined-in-80] [clients/functions.ts:15](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/functions.ts#L15) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/functions](../README.md) / ListAFFunctionArgs # Type Alias: ListAFFunctionArgs [#type-alias-listaffunctionargs] > **ListAFFunctionArgs**: `object` ## Type declaration [#type-declaration-18] ### functionId [#functionid-1] > **functionId**: `string` ## Defined in [#defined-in-81] [clients/functions.ts:40](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/functions.ts#L40) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/functions](../README.md) / UpdateAFFunctionArgs # Type Alias: UpdateAFFunctionArgs [#type-alias-updateaffunctionargs] > **UpdateAFFunctionArgs**: `object` ## Type declaration [#type-declaration-19] ### id [#id-8] > **id**: `string` ### name? [#name-3] > `optional` **name**: `string` ### routes? [#routes-1] > `optional` **routes**: `Record`\<`string`, `string`> | `null` ### slug? [#slug] > `optional` **slug**: `string` ### status? [#status-3] > `optional` **status**: [`createClient`](../../../index/variables/createClient.md) ## Defined in [#defined-in-82] [clients/functions.ts:26](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/functions.ts#L26) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / clients/ipfs # clients/ipfs [#clientsipfs] ## Index [#index-5] ### Classes [#classes-5] * [IpfsClient](classes/IpfsClient.md) ### Type Aliases [#type-aliases-5] * [AddAllOptions](type-aliases/AddAllOptions.md) * [AddFromPathOptions](type-aliases/AddFromPathOptions.md) * [IpfsClientOptions](type-aliases/IpfsClientOptions.md) * [IpfsFile](type-aliases/IpfsFile.md) * [UploadResult](type-aliases/UploadResult.md) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/ipfs](../README.md) / IpfsClient # Class: IpfsClient [#class-ipfsclient] ## Constructors [#constructors-5] ### new IpfsClient() [#new-ipfsclient] > **new IpfsClient**(`options`): [`IpfsClient`](IpfsClient.md) #### Parameters [#parameters-48] • **options**: [`IpfsClientOptions`](../type-aliases/IpfsClientOptions.md) #### Returns [#returns-59] [`IpfsClient`](IpfsClient.md) #### Defined in [#defined-in-83] [clients/ipfs.ts:47](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipfs.ts#L47) ## Methods [#methods-5] ### add() [#add] > **add**(`file`): `Promise`\<[`UploadResult`](../type-aliases/UploadResult.md)> #### Parameters [#parameters-49] • **file**: [`IpfsFile`](../type-aliases/IpfsFile.md) #### Returns [#returns-60] `Promise`\<[`UploadResult`](../type-aliases/UploadResult.md)> #### Defined in [#defined-in-84] [clients/ipfs.ts:68](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipfs.ts#L68) *** ### addAll() [#addall] > **addAll**(`files`, `options`): `Promise`\<[`UploadResult`](../type-aliases/UploadResult.md)\[]> #### Parameters [#parameters-50] • **files**: `any` • **options**: [`AddAllOptions`](../type-aliases/AddAllOptions.md) = `{}` #### Returns [#returns-61] `Promise`\<[`UploadResult`](../type-aliases/UploadResult.md)\[]> #### Defined in [#defined-in-85] [clients/ipfs.ts:89](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipfs.ts#L89) *** ### addFromPath() [#addfrompath] > **addFromPath**(`path`, `options`): `Promise`\<`object`\[]> #### Parameters [#parameters-51] • **path**: `string` • **options**: [`AddFromPathOptions`](../type-aliases/AddFromPathOptions.md) = `{}` #### Returns [#returns-62] `Promise`\<`object`\[]> #### Defined in [#defined-in-86] [clients/ipfs.ts:161](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipfs.ts#L161) *** ### addSitesToIpfs() [#addsitestoipfs] > **addSitesToIpfs**(`path`, `options`): `Promise`\<`object`\[]> #### Parameters [#parameters-52] • **path**: `string` • **options**: [`AddFromPathOptions`](../type-aliases/AddFromPathOptions.md) = `{}` #### Returns [#returns-63] `Promise`\<`object`\[]> #### Defined in [#defined-in-87] [clients/ipfs.ts:197](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipfs.ts#L197) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/ipfs](../README.md) / AddAllOptions # Type Alias: AddAllOptions [#type-alias-addalloptions] > **AddAllOptions**: `object` ## Type declaration [#type-declaration-20] ### basename? [#basename] > `optional` **basename**: `string` ### searchParams? [#searchparams] > `optional` **searchParams**: `URLSearchParams` ### siteId? [#siteid-1] > `optional` **siteId**: `string` ### wrapWithDirectory? [#wrapwithdirectory] > `optional` **wrapWithDirectory**: `boolean` ## Defined in [#defined-in-88] [clients/ipfs.ts:26](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipfs.ts#L26) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/ipfs](../README.md) / AddFromPathOptions # Type Alias: AddFromPathOptions [#type-alias-addfrompathoptions] > **AddFromPathOptions**: `object` ## Type declaration [#type-declaration-21] ### searchParams? [#searchparams-1] > `optional` **searchParams**: `URLSearchParams` ### siteId? [#siteid-2] > `optional` **siteId**: `string` ### wrapWithDirectory? [#wrapwithdirectory-1] > `optional` **wrapWithDirectory**: `boolean` ## Defined in [#defined-in-89] [clients/ipfs.ts:33](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipfs.ts#L33) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/ipfs](../README.md) / IpfsClientOptions # Type Alias: IpfsClientOptions [#type-alias-ipfsclientoptions] > **IpfsClientOptions**: `object` ## Type declaration [#type-declaration-22] ### uploadProxyClient [#uploadproxyclient] > **uploadProxyClient**: [`UploadProxyClient`](../../uploadProxy/classes/UploadProxyClient.md) ## Defined in [#defined-in-90] [clients/ipfs.ts:22](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipfs.ts#L22) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/ipfs](../README.md) / IpfsFile # Type Alias: IpfsFile [#type-alias-ipfsfile] > **IpfsFile**: `object` ## Type declaration [#type-declaration-23] ### content [#content] > **content**: `ArrayBuffer` | `string` ### path? [#path] > `optional` **path**: `string` ## Defined in [#defined-in-91] [clients/ipfs.ts:17](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipfs.ts#L17) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/ipfs](../README.md) / UploadResult # Type Alias: UploadResult [#type-alias-uploadresult] > **UploadResult**: `object` ## Type declaration [#type-declaration-24] ### cid [#cid-1] > **cid**: [`createClient`](../../../index/variables/createClient.md) ### path [#path-1] > **path**: `string` ### size [#size] > **size**: `number` ## Defined in [#defined-in-92] [clients/ipfs.ts:39](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipfs.ts#L39) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / clients/ipns # clients/ipns [#clientsipns] ## Index [#index-6] ### Classes [#classes-6] * [IpnsClient](classes/IpnsClient.md) ### Type Aliases [#type-aliases-6] * [CreateRecordForSiteArgs](type-aliases/CreateRecordForSiteArgs.md) * [DeleteRecordArgs](type-aliases/DeleteRecordArgs.md) * [GetRecordArgs](type-aliases/GetRecordArgs.md) * [IpnsRecord](type-aliases/IpnsRecord.md) * [PublishRecordArgs](type-aliases/PublishRecordArgs.md) * [PublishSignedNameArgs](type-aliases/PublishSignedNameArgs.md) * [ResolveNameArgs](type-aliases/ResolveNameArgs.md) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/ipns](../README.md) / IpnsClient # Class: IpnsClient [#class-ipnsclient] ## Constructors [#constructors-6] ### new IpnsClient() [#new-ipnsclient] > **new IpnsClient**(`options`): [`IpnsClient`](IpnsClient.md) #### Parameters [#parameters-53] • **options**: `IpnsClientOptions` #### Returns [#returns-64] [`IpnsClient`](IpnsClient.md) #### Defined in [#defined-in-93] [clients/ipns.ts:54](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipns.ts#L54) ## Methods [#methods-6] ### createRecord() [#createrecord] > **createRecord**(): `Promise`\<[`IpnsRecord`](../type-aliases/IpnsRecord.md)> #### Returns [#returns-65] `Promise`\<[`IpnsRecord`](../type-aliases/IpnsRecord.md)> #### Defined in [#defined-in-94] [clients/ipns.ts:110](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipns.ts#L110) *** ### createRecordForSite() [#createrecordforsite] > **createRecordForSite**(`__namedParameters`): `Promise`\<[`IpnsRecord`](../type-aliases/IpnsRecord.md)> #### Parameters [#parameters-54] • **\_\_namedParameters**: [`CreateRecordForSiteArgs`](../type-aliases/CreateRecordForSiteArgs.md) #### Returns [#returns-66] `Promise`\<[`IpnsRecord`](../type-aliases/IpnsRecord.md)> #### Defined in [#defined-in-95] [clients/ipns.ts:119](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipns.ts#L119) *** ### deleteRecord() [#deleterecord] > **deleteRecord**(`__namedParameters`): `Promise`\<[`IpnsRecord`](../type-aliases/IpnsRecord.md)> #### Parameters [#parameters-55] • **\_\_namedParameters**: [`DeleteRecordArgs`](../type-aliases/DeleteRecordArgs.md) #### Returns [#returns-67] `Promise`\<[`IpnsRecord`](../type-aliases/IpnsRecord.md)> #### Defined in [#defined-in-96] [clients/ipns.ts:137](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipns.ts#L137) *** ### getRecord() [#getrecord] > **getRecord**(`__namedParameters`): `Promise`\<[`IpnsRecord`](../type-aliases/IpnsRecord.md)> #### Parameters [#parameters-56] • **\_\_namedParameters**: [`GetRecordArgs`](../type-aliases/GetRecordArgs.md) #### Returns [#returns-68] `Promise`\<[`IpnsRecord`](../type-aliases/IpnsRecord.md)> #### Defined in [#defined-in-97] [clients/ipns.ts:164](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipns.ts#L164) *** ### listRecords() [#listrecords] > **listRecords**(): `Promise`\<[`IpnsRecord`](../type-aliases/IpnsRecord.md)\[]> #### Returns [#returns-69] `Promise`\<[`IpnsRecord`](../type-aliases/IpnsRecord.md)\[]> #### Defined in [#defined-in-98] [clients/ipns.ts:155](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipns.ts#L155) *** ### publishRecord() [#publishrecord] > **publishRecord**(`__namedParameters`): `Promise`\<[`IpnsRecord`](../type-aliases/IpnsRecord.md)> #### Parameters [#parameters-57] • **\_\_namedParameters**: [`PublishRecordArgs`](../type-aliases/PublishRecordArgs.md) #### Returns [#returns-70] `Promise`\<[`IpnsRecord`](../type-aliases/IpnsRecord.md)> #### Defined in [#defined-in-99] [clients/ipns.ts:88](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipns.ts#L88) *** ### publishSignedName() [#publishsignedname] > **publishSignedName**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-58] • **\_\_namedParameters**: [`PublishSignedNameArgs`](../type-aliases/PublishSignedNameArgs.md) #### Returns [#returns-71] `Promise`\<`any`> #### Defined in [#defined-in-100] [clients/ipns.ts:58](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipns.ts#L58) *** ### resolveName() [#resolvename] > **resolveName**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-59] • **\_\_namedParameters**: [`ResolveNameArgs`](../type-aliases/ResolveNameArgs.md) #### Returns [#returns-72] `Promise`\<`any`> #### Defined in [#defined-in-101] [clients/ipns.ts:74](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipns.ts#L74) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/ipns](../README.md) / CreateRecordForSiteArgs # Type Alias: CreateRecordForSiteArgs [#type-alias-createrecordforsiteargs] > **CreateRecordForSiteArgs**: `object` ## Type declaration [#type-declaration-25] ### siteId [#siteid-3] > **siteId**: `string` ## Defined in [#defined-in-102] [clients/ipns.ts:20](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipns.ts#L20) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/ipns](../README.md) / DeleteRecordArgs # Type Alias: DeleteRecordArgs [#type-alias-deleterecordargs] > **DeleteRecordArgs**: `object` ## Type declaration [#type-declaration-26] ### id [#id-9] > **id**: `string` ## Defined in [#defined-in-103] [clients/ipns.ts:24](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipns.ts#L24) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/ipns](../README.md) / GetRecordArgs # Type Alias: GetRecordArgs [#type-alias-getrecordargs] > **GetRecordArgs**: `object` ## Type declaration [#type-declaration-27] ### name [#name-4] > **name**: `string` ## Defined in [#defined-in-104] [clients/ipns.ts:28](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipns.ts#L28) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/ipns](../README.md) / IpnsRecord # Type Alias: IpnsRecord [#type-alias-ipnsrecord] > **IpnsRecord**: `Pick`\<[`createClient`](../../../index/variables/createClient.md), `"id"` | `"name"` | `"hash"`> & `object` ## Type declaration [#type-declaration-28] ### ensRecords [#ensrecords] > **ensRecords**: `Pick`\<[`createClient`](../../../index/variables/createClient.md)\[`"ensRecords"`]\[`number`], `"id"`>\[] ## Defined in [#defined-in-105] [clients/ipns.ts:37](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipns.ts#L37) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/ipns](../README.md) / PublishRecordArgs # Type Alias: PublishRecordArgs [#type-alias-publishrecordargs] > **PublishRecordArgs**: `object` ## Type declaration [#type-declaration-29] ### hash [#hash] > **hash**: `string` ### id [#id-10] > **id**: `string` ## Defined in [#defined-in-106] [clients/ipns.ts:11](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipns.ts#L11) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/ipns](../README.md) / PublishSignedNameArgs # Type Alias: PublishSignedNameArgs [#type-alias-publishsignednameargs] > **PublishSignedNameArgs**: `object` ## Type declaration [#type-declaration-30] ### input [#input] > **input**: `string` ### key [#key] > **key**: `string` ## Defined in [#defined-in-107] [clients/ipns.ts:32](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipns.ts#L32) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/ipns](../README.md) / ResolveNameArgs # Type Alias: ResolveNameArgs [#type-alias-resolvenameargs] > **ResolveNameArgs**: `object` ## Type declaration [#type-declaration-31] ### name [#name-5] > **name**: `string` ## Defined in [#defined-in-108] [clients/ipns.ts:16](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/ipns.ts#L16) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / clients/privateGateway # clients/privateGateway [#clientsprivategateway] ## Index [#index-7] ### Classes [#classes-7] * [PrivateGatewayClient](classes/PrivateGatewayClient.md) ### Type Aliases [#type-aliases-7] * [CreatePrivateGatewayArgs](type-aliases/CreatePrivateGatewayArgs.md) * [DeletePrivateGatewayArgs](type-aliases/DeletePrivateGatewayArgs.md) * [GetPrivateGatewayArgs](type-aliases/GetPrivateGatewayArgs.md) * [GetPrivateGatewayBySlugArgs](type-aliases/GetPrivateGatewayBySlugArgs.md) * [PrivateGateway](type-aliases/PrivateGateway.md) * [UpdatePrivateGatewayArgs](type-aliases/UpdatePrivateGatewayArgs.md) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/privateGateway](../README.md) / PrivateGatewayClient # Class: PrivateGatewayClient [#class-privategatewayclient] ## Constructors [#constructors-7] ### new PrivateGatewayClient() [#new-privategatewayclient] > **new PrivateGatewayClient**(`options`): [`PrivateGatewayClient`](PrivateGatewayClient.md) #### Parameters [#parameters-60] • **options**: `PrivateGatewayClientOptions` #### Returns [#returns-73] [`PrivateGatewayClient`](PrivateGatewayClient.md) #### Defined in [#defined-in-109] [clients/privateGateway.ts:49](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/privateGateway.ts#L49) ## Methods [#methods-7] ### create() [#create-3] > **create**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-61] • **\_\_namedParameters**: [`CreatePrivateGatewayArgs`](../type-aliases/CreatePrivateGatewayArgs.md) #### Returns [#returns-74] `Promise`\<`any`> #### Defined in [#defined-in-110] [clients/privateGateway.ts:116](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/privateGateway.ts#L116) *** ### delete() [#delete-3] > **delete**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-62] • **\_\_namedParameters**: [`DeletePrivateGatewayArgs`](../type-aliases/DeletePrivateGatewayArgs.md) #### Returns [#returns-75] `Promise`\<`any`> #### Defined in [#defined-in-111] [clients/privateGateway.ts:135](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/privateGateway.ts#L135) *** ### get() [#get-4] > **get**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-63] • **\_\_namedParameters**: [`GetPrivateGatewayArgs`](../type-aliases/GetPrivateGatewayArgs.md) #### Returns [#returns-76] `Promise`\<`any`> #### Defined in [#defined-in-112] [clients/privateGateway.ts:53](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/privateGateway.ts#L53) *** ### getBySlug() [#getbyslug] > **getBySlug**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-64] • **\_\_namedParameters**: [`GetPrivateGatewayBySlugArgs`](../type-aliases/GetPrivateGatewayBySlugArgs.md) #### Returns [#returns-77] `Promise`\<`any`> #### Defined in [#defined-in-113] [clients/privateGateway.ts:78](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/privateGateway.ts#L78) *** ### list() [#list-4] > **list**(): `Promise`\<`any`> #### Returns [#returns-78] `Promise`\<`any`> #### Defined in [#defined-in-114] [clients/privateGateway.ts:98](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/privateGateway.ts#L98) *** ### update() [#update-2] > **update**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-65] • **\_\_namedParameters**: [`UpdatePrivateGatewayArgs`](../type-aliases/UpdatePrivateGatewayArgs.md) #### Returns [#returns-79] `Promise`\<`any`> #### Defined in [#defined-in-115] [clients/privateGateway.ts:151](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/privateGateway.ts#L151) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/privateGateway](../README.md) / CreatePrivateGatewayArgs # Type Alias: CreatePrivateGatewayArgs [#type-alias-createprivategatewayargs] > **CreatePrivateGatewayArgs**: `object` ## Type declaration [#type-declaration-32] ### name [#name-6] > **name**: `string` ### zoneId [#zoneid] > **zoneId**: `string` ## Defined in [#defined-in-116] [clients/privateGateway.ts:22](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/privateGateway.ts#L22) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/privateGateway](../README.md) / DeletePrivateGatewayArgs # Type Alias: DeletePrivateGatewayArgs [#type-alias-deleteprivategatewayargs] > **DeletePrivateGatewayArgs**: `object` ## Type declaration [#type-declaration-33] ### id [#id-11] > **id**: `string` ## Defined in [#defined-in-117] [clients/privateGateway.ts:23](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/privateGateway.ts#L23) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/privateGateway](../README.md) / GetPrivateGatewayArgs # Type Alias: GetPrivateGatewayArgs [#type-alias-getprivategatewayargs] > **GetPrivateGatewayArgs**: `object` ## Type declaration [#type-declaration-34] ### id [#id-12] > **id**: `string` ## Defined in [#defined-in-118] [clients/privateGateway.ts:21](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/privateGateway.ts#L21) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/privateGateway](../README.md) / GetPrivateGatewayBySlugArgs # Type Alias: GetPrivateGatewayBySlugArgs [#type-alias-getprivategatewaybyslugargs] > **GetPrivateGatewayBySlugArgs**: `object` ## Type declaration [#type-declaration-35] ### slug [#slug-1] > **slug**: `string` ## Defined in [#defined-in-119] [clients/privateGateway.ts:25](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/privateGateway.ts#L25) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/privateGateway](../README.md) / PrivateGateway # Type Alias: PrivateGateway [#type-alias-privategateway] > **PrivateGateway**: `Omit`\<[`createClient`](../../../index/variables/createClient.md), `"project"` | `"domains"` | `"domainsPaginated"` | `"primaryDomain"`> & `object` ## Type declaration [#type-declaration-36] ### project [#project] > **project**: `Pick`\<[`createClient`](../../../index/variables/createClient.md), `"id"`> ## Defined in [#defined-in-120] [clients/privateGateway.ts:26](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/privateGateway.ts#L26) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/privateGateway](../README.md) / UpdatePrivateGatewayArgs # Type Alias: UpdatePrivateGatewayArgs [#type-alias-updateprivategatewayargs] > **UpdatePrivateGatewayArgs**: `object` ## Type declaration [#type-declaration-37] ### id [#id-13] > **id**: `string` ### name [#name-7] > **name**: `string` ## Defined in [#defined-in-121] [clients/privateGateway.ts:24](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/privateGateway.ts#L24) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / clients/projects # clients/projects [#clientsprojects] ## Index [#index-8] ### Classes [#classes-8] * [ProjectsClient](classes/ProjectsClient.md) ### Type Aliases [#type-aliases-8] * [Project](type-aliases/Project.md) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/projects](../README.md) / ProjectsClient # Class: ProjectsClient [#class-projectsclient] ## Constructors [#constructors-8] ### new ProjectsClient() [#new-projectsclient] > **new ProjectsClient**(`options`): [`ProjectsClient`](ProjectsClient.md) #### Parameters [#parameters-66] • **options**: `ProjectsClientOptions` #### Returns [#returns-80] [`ProjectsClient`](ProjectsClient.md) #### Defined in [#defined-in-122] [clients/projects.ts:43](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/projects.ts#L43) ## Methods [#methods-8] ### create() [#create-4] > **create**(`__namedParameters`): `Promise`\<[`Project`](../type-aliases/Project.md)> #### Parameters [#parameters-67] • **\_\_namedParameters**: `CreateProjectArgs` #### Returns [#returns-81] `Promise`\<[`Project`](../type-aliases/Project.md)> #### Defined in [#defined-in-123] [clients/projects.ts:47](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/projects.ts#L47) *** ### get() [#get-5] > **get**(`__namedParameters`): `Promise`\<[`Project`](../type-aliases/Project.md)> #### Parameters [#parameters-68] • **\_\_namedParameters**: `GetProjectArgs` #### Returns [#returns-82] `Promise`\<[`Project`](../type-aliases/Project.md)> #### Defined in [#defined-in-124] [clients/projects.ts:80](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/projects.ts#L80) *** ### list() [#list-5] > **list**(): `Promise`\<[`Project`](../type-aliases/Project.md)\[]> #### Returns [#returns-83] `Promise`\<[`Project`](../type-aliases/Project.md)\[]> #### Defined in [#defined-in-125] [clients/projects.ts:96](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/projects.ts#L96) *** ### update() [#update-3] > **update**(`__namedParameters`): `Promise`\<[`Project`](../type-aliases/Project.md)> #### Parameters [#parameters-69] • **\_\_namedParameters**: `UpdateProjectArgs` #### Returns [#returns-84] `Promise`\<[`Project`](../type-aliases/Project.md)> #### Defined in [#defined-in-126] [clients/projects.ts:63](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/projects.ts#L63) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/projects](../README.md) / Project # Type Alias: Project [#type-alias-project] > **Project**: `Omit`\<[`createClient`](../../../index/variables/createClient.md), `"currentUserMembership"` | `"memberships"` | `"membershipsPaginated"`> ## Defined in [#defined-in-127] [clients/projects.ts:26](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/projects.ts#L26) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / clients/sites # clients/sites [#clientssites] ## Index [#index-9] ### Classes [#classes-9] * [SitesClient](classes/SitesClient.md) ### Type Aliases [#type-aliases-9] * [CreateCustomIpfsDeploymentArgs](type-aliases/CreateCustomIpfsDeploymentArgs.md) * [CreateSiteArgs](type-aliases/CreateSiteArgs.md) * [DeleteSiteArgs](type-aliases/DeleteSiteArgs.md) * [Deployment](type-aliases/Deployment.md) * [GetBySlugArgs](type-aliases/GetBySlugArgs.md) * [GetDeploymentArgs](type-aliases/GetDeploymentArgs.md) * [GetSiteArgs](type-aliases/GetSiteArgs.md) * [Site](type-aliases/Site.md) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/sites](../README.md) / SitesClient # Class: SitesClient [#class-sitesclient] ## Constructors [#constructors-9] ### new SitesClient() [#new-sitesclient] > **new SitesClient**(`options`): [`SitesClient`](SitesClient.md) #### Parameters [#parameters-70] • **options**: `SitesClientOptions` #### Returns [#returns-85] [`SitesClient`](SitesClient.md) #### Defined in [#defined-in-128] [clients/sites.ts:74](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/sites.ts#L74) ## Methods [#methods-9] ### create() [#create-5] > **create**(`__namedParameters`): `Promise`\<[`Site`](../type-aliases/Site.md)> #### Parameters [#parameters-71] • **\_\_namedParameters**: [`CreateSiteArgs`](../type-aliases/CreateSiteArgs.md) #### Returns [#returns-86] `Promise`\<[`Site`](../type-aliases/Site.md)> #### Defined in [#defined-in-129] [clients/sites.ts:139](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/sites.ts#L139) *** ### createCustomIpfsDeployment() [#createcustomipfsdeployment] > **createCustomIpfsDeployment**(`__namedParameters`): `Promise`\<[`Deployment`](../type-aliases/Deployment.md)> #### Parameters [#parameters-72] • **\_\_namedParameters**: `Required`\<`Pick`\<`DeploymentWithRelations`, `"siteId"` | `"cid"`>> #### Returns [#returns-87] `Promise`\<[`Deployment`](../type-aliases/Deployment.md)> #### Defined in [#defined-in-130] [clients/sites.ts:179](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/sites.ts#L179) *** ### delete() [#delete-4] > **delete**(`__namedParameters`): `Promise`\<[`Site`](../type-aliases/Site.md)> #### Parameters [#parameters-73] • **\_\_namedParameters**: [`DeleteSiteArgs`](../type-aliases/DeleteSiteArgs.md) #### Returns [#returns-88] `Promise`\<[`Site`](../type-aliases/Site.md)> #### Defined in [#defined-in-131] [clients/sites.ts:159](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/sites.ts#L159) *** ### get() [#get-6] > **get**(`__namedParameters`): `Promise`\<[`Site`](../type-aliases/Site.md)> #### Parameters [#parameters-74] • **\_\_namedParameters**: [`GetSiteArgs`](../type-aliases/GetSiteArgs.md) #### Returns [#returns-89] `Promise`\<[`Site`](../type-aliases/Site.md)> #### Defined in [#defined-in-132] [clients/sites.ts:78](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/sites.ts#L78) *** ### getBySlug() [#getbyslug-1] > **getBySlug**(`__namedParameters`): `Promise`\<[`Site`](../type-aliases/Site.md)> #### Parameters [#parameters-75] • **\_\_namedParameters**: [`GetBySlugArgs`](../type-aliases/GetBySlugArgs.md) #### Returns [#returns-90] `Promise`\<[`Site`](../type-aliases/Site.md)> #### Defined in [#defined-in-133] [clients/sites.ts:98](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/sites.ts#L98) *** ### getDeployment() [#getdeployment] > **getDeployment**(`__namedParameters`): `Promise`\<[`Deployment`](../type-aliases/Deployment.md)> #### Parameters [#parameters-76] • **\_\_namedParameters**: [`GetDeploymentArgs`](../type-aliases/GetDeploymentArgs.md) #### Returns [#returns-91] `Promise`\<[`Deployment`](../type-aliases/Deployment.md)> #### Defined in [#defined-in-134] [clients/sites.ts:199](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/sites.ts#L199) *** ### list() [#list-6] > **list**(): `Promise`\<[`Site`](../type-aliases/Site.md)\[]> #### Returns [#returns-92] `Promise`\<[`Site`](../type-aliases/Site.md)\[]> #### Defined in [#defined-in-135] [clients/sites.ts:118](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/sites.ts#L118) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/sites](../README.md) / CreateCustomIpfsDeploymentArgs # Type Alias: CreateCustomIpfsDeploymentArgs [#type-alias-createcustomipfsdeploymentargs] > **CreateCustomIpfsDeploymentArgs**: `Required`\<`Pick`\<[`createClient`](../../../index/variables/createClient.md), `"siteId"` | `"cid"`>> ## Defined in [#defined-in-136] [clients/sites.ts:43](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/sites.ts#L43) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/sites](../README.md) / CreateSiteArgs # Type Alias: CreateSiteArgs [#type-alias-createsiteargs] > **CreateSiteArgs**: `Pick`\<[`Site`](Site.md), `"name"`> ## Defined in [#defined-in-137] [clients/sites.ts:41](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/sites.ts#L41) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/sites](../README.md) / DeleteSiteArgs # Type Alias: DeleteSiteArgs [#type-alias-deletesiteargs] > **DeleteSiteArgs**: `Pick`\<[`Site`](Site.md), `"id"`> ## Defined in [#defined-in-138] [clients/sites.ts:42](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/sites.ts#L42) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/sites](../README.md) / Deployment # Type Alias: Deployment [#type-alias-deployment] > **Deployment**: `Pick`\<[`createClient`](../../../index/variables/createClient.md), `"id"` | `"status"` | `"storageType"` | `"siteId"` | `"cid"` | `"updatedAt"` | `"createdAt"`> ## Defined in [#defined-in-139] [clients/sites.ts:22](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/sites.ts#L22) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/sites](../README.md) / GetBySlugArgs # Type Alias: GetBySlugArgs [#type-alias-getbyslugargs] > **GetBySlugArgs**: `Pick`\<[`Site`](Site.md), `"slug"`> ## Defined in [#defined-in-140] [clients/sites.ts:40](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/sites.ts#L40) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/sites](../README.md) / GetDeploymentArgs # Type Alias: GetDeploymentArgs [#type-alias-getdeploymentargs] > **GetDeploymentArgs**: `Pick`\<[`createClient`](../../../index/variables/createClient.md), `"id"`> ## Defined in [#defined-in-141] [clients/sites.ts:46](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/sites.ts#L46) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/sites](../README.md) / GetSiteArgs # Type Alias: GetSiteArgs [#type-alias-getsiteargs] > **GetSiteArgs**: `Pick`\<[`Site`](Site.md), `"id"`> ## Defined in [#defined-in-142] [clients/sites.ts:39](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/sites.ts#L39) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/sites](../README.md) / Site # Type Alias: Site [#type-alias-site] > **Site**: `Pick`\<[`createClient`](../../../index/variables/createClient.md), `"id"` | `"name"` | `"slug"`> & `object` ## Type declaration [#type-declaration-38] ### deployments [#deployments] > **deployments**: [`Deployment`](Deployment.md)\[] ### domains [#domains] > **domains**: `Pick`\<[`createClient`](../../../index/variables/createClient.md)\[`"domains"`]\[`number`], `"id"` | `"hostname"`>\[] ### ipnsRecords [#ipnsrecords] > **ipnsRecords**: `Pick`\<[`createClient`](../../../index/variables/createClient.md)\[`"ipnsRecords"`]\[`number`], `"id"`>\[] ### primaryDomain? [#primarydomain] > `optional` **primaryDomain**: `Pick`\<[`createClient`](../../../index/variables/createClient.md), `"id"` | `"hostname"`> ### zones [#zones] > **zones**: `Pick`\<[`createClient`](../../../index/variables/createClient.md)\[`"zones"`]\[`number`], `"id"` | `"status"`>\[] ## Defined in [#defined-in-143] [clients/sites.ts:27](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/sites.ts#L27) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / clients/storage # clients/storage [#clientsstorage] ## Index [#index-10] ### Classes [#classes-10] * [StorageClient](classes/StorageClient.md) ### Type Aliases [#type-aliases-10] * [DeletePinArgs](type-aliases/DeletePinArgs.md) * [GetPinArgs](type-aliases/GetPinArgs.md) * [GetPinByFilenameArgs](type-aliases/GetPinByFilenameArgs.md) * [PinByCidArgs](type-aliases/PinByCidArgs.md) * [PinByFilenameArgs](type-aliases/PinByFilenameArgs.md) * [StoragePin](type-aliases/StoragePin.md) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/storage](../README.md) / StorageClient # Class: StorageClient [#class-storageclient] ## Constructors [#constructors-10] ### new StorageClient() [#new-storageclient] > **new StorageClient**(`options`): [`StorageClient`](StorageClient.md) #### Parameters [#parameters-77] • **options**: `StorageClientOptions` #### Returns [#returns-93] [`StorageClient`](StorageClient.md) #### Defined in [#defined-in-144] [clients/storage.ts:109](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/storage.ts#L109) ## Methods [#methods-10] ### delete() [#delete-5] > **delete**(`__namedParameters`): `Promise`\<`object`> #### Parameters [#parameters-78] • **\_\_namedParameters**: [`PinByCidArgs`](../type-aliases/PinByCidArgs.md) #### Returns [#returns-94] `Promise`\<`object`> ##### body [#body] > **body**: `any` ##### status [#status-4] > **status**: `number` = `response.status` #### Defined in [#defined-in-145] [clients/storage.ts:347](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/storage.ts#L347) *** ### get() [#get-7] > **get**(`__namedParameters`): `Promise`\<[`StoragePin`](../type-aliases/StoragePin.md)> #### Parameters [#parameters-79] • **\_\_namedParameters**: [`PinByCidArgs`](../type-aliases/PinByCidArgs.md) #### Returns [#returns-95] `Promise`\<[`StoragePin`](../type-aliases/StoragePin.md)> #### Defined in [#defined-in-146] [clients/storage.ts:225](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/storage.ts#L225) *** ### getByFilename() [#getbyfilename] > **getByFilename**(`__namedParameters`): `Promise`\<[`StoragePin`](../type-aliases/StoragePin.md)\[]> #### Parameters [#parameters-80] • **\_\_namedParameters**: [`PinByFilenameArgs`](../type-aliases/PinByFilenameArgs.md) #### Returns [#returns-96] `Promise`\<[`StoragePin`](../type-aliases/StoragePin.md)\[]> #### Defined in [#defined-in-147] [clients/storage.ts:263](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/storage.ts#L263) *** ### list() [#list-7] > **list**(): `Promise`\<[`StoragePin`](../type-aliases/StoragePin.md)\[]> #### Returns [#returns-97] `Promise`\<[`StoragePin`](../type-aliases/StoragePin.md)\[]> #### Defined in [#defined-in-148] [clients/storage.ts:304](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/storage.ts#L304) *** ### uploadDirectory() [#uploaddirectory] > **uploadDirectory**(`__namedParameters`): `Promise`\<[`UploadPinResponse`](../../uploadProxy/type-aliases/UploadPinResponse.md)> #### Parameters [#parameters-81] • **\_\_namedParameters**: `UploadDirectoryArgs` #### Returns [#returns-98] `Promise`\<[`UploadPinResponse`](../../uploadProxy/type-aliases/UploadPinResponse.md)> #### Defined in [#defined-in-149] [clients/storage.ts:114](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/storage.ts#L114) *** ### uploadFile() [#uploadfile] > **uploadFile**(`__namedParameters`): `Promise`\<[`UploadPinResponse`](../../uploadProxy/type-aliases/UploadPinResponse.md)> #### Parameters [#parameters-82] • **\_\_namedParameters**: `UploadFileArgs` #### Returns [#returns-99] `Promise`\<[`UploadPinResponse`](../../uploadProxy/type-aliases/UploadPinResponse.md)> #### Defined in [#defined-in-150] [clients/storage.ts:198](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/storage.ts#L198) *** ### uploadPrivateFile() [#uploadprivatefile] > **uploadPrivateFile**(`__namedParameters`): `Promise`\<[`UploadPinResponse`](../../uploadProxy/type-aliases/UploadPinResponse.md)> #### Parameters [#parameters-83] • **\_\_namedParameters**: `UploadPrivateFileArgs` #### Returns [#returns-100] `Promise`\<[`UploadPinResponse`](../../uploadProxy/type-aliases/UploadPinResponse.md)> #### Defined in [#defined-in-151] [clients/storage.ts:171](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/storage.ts#L171) *** ### uploadVirtualDirectory() [#uploadvirtualdirectory] > **uploadVirtualDirectory**(`__namedParameters`): `Promise`\<[`UploadPinResponse`](../../uploadProxy/type-aliases/UploadPinResponse.md)> #### Parameters [#parameters-84] • **\_\_namedParameters**: `UploadVirtualDirectoryArgs` #### Returns [#returns-101] `Promise`\<[`UploadPinResponse`](../../uploadProxy/type-aliases/UploadPinResponse.md)> #### Defined in [#defined-in-152] [clients/storage.ts:155](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/storage.ts#L155) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/storage](../README.md) / DeletePinArgs # Type Alias: DeletePinArgs [#type-alias-deletepinargs] > **DeletePinArgs**: [`PinByCidArgs`](PinByCidArgs.md) ## Defined in [#defined-in-153] [clients/storage.ts:49](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/storage.ts#L49) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/storage](../README.md) / GetPinArgs # Type Alias: GetPinArgs [#type-alias-getpinargs] > **GetPinArgs**: [`PinByCidArgs`](PinByCidArgs.md) ## Defined in [#defined-in-154] [clients/storage.ts:46](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/storage.ts#L46) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/storage](../README.md) / GetPinByFilenameArgs # Type Alias: GetPinByFilenameArgs [#type-alias-getpinbyfilenameargs] > **GetPinByFilenameArgs**: [`PinByFilenameArgs`](PinByFilenameArgs.md) ## Defined in [#defined-in-155] [clients/storage.ts:47](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/storage.ts#L47) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/storage](../README.md) / PinByCidArgs # Type Alias: PinByCidArgs [#type-alias-pinbycidargs] > **PinByCidArgs**: `Pick`\<[`createClient`](../../../index/variables/createClient.md), `"cid"`> ## Defined in [#defined-in-156] [clients/storage.ts:43](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/storage.ts#L43) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/storage](../README.md) / PinByFilenameArgs # Type Alias: PinByFilenameArgs [#type-alias-pinbyfilenameargs] > **PinByFilenameArgs**: `Pick`\<[`createClient`](../../../index/variables/createClient.md), `"filename"` | `"extension"`> ## Defined in [#defined-in-157] [clients/storage.ts:44](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/storage.ts#L44) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/storage](../README.md) / StoragePin # Type Alias: StoragePin [#type-alias-storagepin] > **StoragePin**: `Pick`\<[`createClient`](../../../index/variables/createClient.md), `"cid"` | `"filename"` | `"extension"` | `"arweavePin"`> & `object` ## Type declaration [#type-declaration-39] ### arweaveId? [#arweaveid] > `optional` **arweaveId**: `string` ### filecoinDealIds? [#filecoindealids] > `optional` **filecoinDealIds**: `string` ## Defined in [#defined-in-158] [clients/storage.ts:36](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/storage.ts#L36) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / clients/uploadProxy # clients/uploadProxy [#clientsuploadproxy] ## Index [#index-11] ### Classes [#classes-11] * [UploadProxyClient](classes/UploadProxyClient.md) ### Type Aliases [#type-aliases-11] * [UploadContentOptions](type-aliases/UploadContentOptions.md) * [UploadPinResponse](type-aliases/UploadPinResponse.md) * [UploadProgress](type-aliases/UploadProgress.md) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/uploadProxy](../README.md) / UploadProxyClient # Class: UploadProxyClient [#class-uploadproxyclient] ## Constructors [#constructors-11] ### new UploadProxyClient() [#new-uploadproxyclient] > **new UploadProxyClient**(`options`): [`UploadProxyClient`](UploadProxyClient.md) #### Parameters [#parameters-85] • **options**: `UploadProxyClientOptions` #### Returns [#returns-102] [`UploadProxyClient`](UploadProxyClient.md) #### Defined in [#defined-in-159] [clients/uploadProxy.ts:112](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/uploadProxy.ts#L112) ## Methods [#methods-11] ### delete() [#delete-6] > **delete**(`cid`): `Promise`\<`Response`> #### Parameters [#parameters-86] • **cid**: `string` #### Returns [#returns-103] `Promise`\<`Response`> #### Defined in [#defined-in-160] [clients/uploadProxy.ts:284](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/uploadProxy.ts#L284) *** ### uploadContent() [#uploadcontent] > **uploadContent**(`__namedParameters`): `Promise`\<[`UploadPinResponse`](../type-aliases/UploadPinResponse.md)> #### Parameters [#parameters-87] • **\_\_namedParameters**: `UploadContentArgs` #### Returns [#returns-104] `Promise`\<[`UploadPinResponse`](../type-aliases/UploadPinResponse.md)> #### Defined in [#defined-in-161] [clients/uploadProxy.ts:161](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/uploadProxy.ts#L161) *** ### uploadPrivateContent() [#uploadprivatecontent] > **uploadPrivateContent**(`__namedParameters`): `Promise`\<`object`> #### Parameters [#parameters-88] • **\_\_namedParameters**: `UploadPrivateContentArgs` #### Returns [#returns-105] `Promise`\<`object`> ##### duplicate [#duplicate] > **duplicate**: `boolean` = `false` ##### pin [#pin] > **pin**: `object` ##### pin.cid [#pincid] > **cid**: `any` = `response.data.cid` ##### pin.size [#pinsize] > **size**: `number` = `file.size` #### Defined in [#defined-in-162] [clients/uploadProxy.ts:117](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/uploadProxy.ts#L117) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/uploadProxy](../README.md) / UploadContentOptions # Type Alias: UploadContentOptions [#type-alias-uploadcontentoptions] > **UploadContentOptions**: `object` ## Type declaration [#type-declaration-40] ### functionName? [#functionname] > `optional` **functionName**: `string` ### siteId? [#siteid-4] > `optional` **siteId**: `string` ## Defined in [#defined-in-163] [clients/uploadProxy.ts:60](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/uploadProxy.ts#L60) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/uploadProxy](../README.md) / UploadPinResponse # Type Alias: UploadPinResponse [#type-alias-uploadpinresponse] > **UploadPinResponse**: `object` ## Type declaration [#type-declaration-41] ### duplicate [#duplicate-1] > **duplicate**: `boolean` ### pin [#pin-1] > **pin**: `Pick`\<[`createClient`](../../../index/variables/createClient.md), `"cid"` | `"size"`> ## Defined in [#defined-in-164] [clients/uploadProxy.ts:65](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/uploadProxy.ts#L65) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/uploadProxy](../README.md) / UploadProgress # Type Alias: UploadProgress [#type-alias-uploadprogress] > **UploadProgress**: `object` ## Type declaration [#type-declaration-42] ### loadedSize [#loadedsize] > **loadedSize**: `number` ### totalSize? [#totalsize] > `optional` **totalSize**: `number` ## Defined in [#defined-in-165] [clients/uploadProxy.ts:36](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/uploadProxy.ts#L36) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / clients/user # clients/user [#clientsuser] ## Index [#index-12] ### Classes [#classes-12] * [UserClient](classes/UserClient.md) *** [**@alternatefutures/sdk**](../../../README.md) • **Docs** *** [@alternatefutures/sdk](../../../README.md) / [clients/user](../README.md) / UserClient # Class: UserClient [#class-userclient] ## Constructors [#constructors-12] ### new UserClient() [#new-userclient] > **new UserClient**(`options`): [`UserClient`](UserClient.md) #### Parameters [#parameters-89] • **options**: `UserClientOptions` #### Returns [#returns-106] [`UserClient`](UserClient.md) #### Defined in [#defined-in-166] [clients/user.ts:10](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/user.ts#L10) ## Methods [#methods-12] ### deletePersonalAccessToken() [#deletepersonalaccesstoken] > **deletePersonalAccessToken**(`__namedParameters`): `Promise`\<`any`> #### Parameters [#parameters-90] • **\_\_namedParameters** • **\_\_namedParameters.id**: `string` #### Returns [#returns-107] `Promise`\<`any`> #### Defined in [#defined-in-167] [clients/user.ts:30](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/user.ts#L30) *** ### listPersonalAccessTokens() [#listpersonalaccesstokens] > **listPersonalAccessTokens**(): `Promise`\<`any`> #### Returns [#returns-108] `Promise`\<`any`> #### Defined in [#defined-in-168] [clients/user.ts:14](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/clients/user.ts#L14) *** [**@alternatefutures/sdk**](../README.md) • **Docs** *** [@alternatefutures/sdk](../README.md) / index # index [#index-13] ## Index [#index-14] ### Classes [#classes-13] * [AlternateFuturesSdk](classes/AlternateFuturesSdk.md) * [ApplicationAccessTokenService](classes/ApplicationAccessTokenService.md) * [PersonalAccessTokenService](classes/PersonalAccessTokenService.md) * [StaticAccessTokenService](classes/StaticAccessTokenService.md) ### Variables [#variables] * [createClient](variables/createClient.md) ## References [#references] ### AFFunction [#affunction] Re-exports [AFFunction](../clients/functions/type-aliases/AFFunction.md) *** ### AFFunctionStatus [#affunctionstatus] Renames and re-exports [createClient](variables/createClient.md) *** ### Application [#application] Re-exports [Application](../clients/applications/type-aliases/Application.md) *** ### ApplicationWhiteLabelDomain [#applicationwhitelabeldomain] Renames and re-exports [createClient](variables/createClient.md) *** ### ApplicationWhitelistDomain [#applicationwhitelistdomain] Renames and re-exports [createClient](variables/createClient.md) *** ### BillingClient [#billingclient] Re-exports [BillingClient](../clients/billing/classes/BillingClient.md) *** ### Client [#client] Renames and re-exports [createClient](variables/createClient.md) *** ### CurrentUsage [#currentusage] Re-exports [CurrentUsage](../clients/billing/type-aliases/CurrentUsage.md) *** ### Customer [#customer] Re-exports [Customer](../clients/billing/type-aliases/Customer.md) *** ### Deployment [#deployment] Re-exports [Deployment](../clients/sites/type-aliases/Deployment.md) *** ### Domain [#domain] Re-exports [Domain](../clients/domains/type-aliases/Domain.md) *** ### DomainStatus [#domainstatus] Renames and re-exports [createClient](variables/createClient.md) *** ### EnsRecord [#ensrecord] Re-exports [EnsRecord](../clients/ens/type-aliases/EnsRecord.md) *** ### Invoice [#invoice] Re-exports [Invoice](../clients/billing/type-aliases/Invoice.md) *** ### InvoiceLineItem [#invoicelineitem] Re-exports [InvoiceLineItem](../clients/billing/type-aliases/InvoiceLineItem.md) *** ### IpfsFile [#ipfsfile] Re-exports [IpfsFile](../clients/ipfs/type-aliases/IpfsFile.md) *** ### IpnsRecord [#ipnsrecord-1] Re-exports [IpnsRecord](../clients/ipns/type-aliases/IpnsRecord.md) *** ### Payment [#payment] Re-exports [Payment](../clients/billing/type-aliases/Payment.md) *** ### PaymentMethod [#paymentmethod] Re-exports [PaymentMethod](../clients/billing/type-aliases/PaymentMethod.md) *** ### PrivateGateway [#privategateway] Re-exports [PrivateGateway](../clients/privateGateway/type-aliases/PrivateGateway.md) *** ### Project [#project-1] Re-exports [Project](../clients/projects/type-aliases/Project.md) *** ### Site [#site-1] Re-exports [Site](../clients/sites/type-aliases/Site.md) *** ### StoragePin [#storagepin] Re-exports [StoragePin](../clients/storage/type-aliases/StoragePin.md) *** ### Subscription [#subscription] Re-exports [Subscription](../clients/billing/type-aliases/Subscription.md) *** ### UploadContentOptions [#uploadcontentoptions] Re-exports [UploadContentOptions](../clients/uploadProxy/type-aliases/UploadContentOptions.md) *** ### UploadPinResponse [#uploadpinresponse] Re-exports [UploadPinResponse](../clients/uploadProxy/type-aliases/UploadPinResponse.md) *** ### UploadProgress [#uploadprogress] Re-exports [UploadProgress](../clients/uploadProxy/type-aliases/UploadProgress.md) *** ### UsageMetric [#usagemetric] Re-exports [UsageMetric](../clients/billing/type-aliases/UsageMetric.md) *** ### UsageRecord [#usagerecord] Re-exports [UsageRecord](../clients/billing/type-aliases/UsageRecord.md) *** ### Zone [#zone] Re-exports [Zone](../clients/domains/type-aliases/Zone.md) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / [index](../README.md) / AlternateFuturesSdk # Class: AlternateFuturesSdk [#class-alternatefuturessdk] ## Constructors [#constructors-13] ### new AlternateFuturesSdk() [#new-alternatefuturessdk] > **new AlternateFuturesSdk**(`__namedParameters`): [`AlternateFuturesSdk`](AlternateFuturesSdk.md) #### Parameters [#parameters-91] • **\_\_namedParameters**: `AlternateFuturesSdkOptions` #### Returns [#returns-109] [`AlternateFuturesSdk`](AlternateFuturesSdk.md) #### Defined in [#defined-in-169] [AlternateFuturesSdk.ts:59](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/AlternateFuturesSdk.ts#L59) ## Methods [#methods-13] ### applications() [#applications] > **applications**(): [`ApplicationsClient`](../../clients/applications/classes/ApplicationsClient.md) #### Returns [#returns-110] [`ApplicationsClient`](../../clients/applications/classes/ApplicationsClient.md) #### Defined in [#defined-in-170] [AlternateFuturesSdk.ts:168](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/AlternateFuturesSdk.ts#L168) *** ### billing() [#billing] > **billing**(): [`BillingClient`](../../clients/billing/classes/BillingClient.md) #### Returns [#returns-111] [`BillingClient`](../../clients/billing/classes/BillingClient.md) #### Defined in [#defined-in-171] [AlternateFuturesSdk.ts:217](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/AlternateFuturesSdk.ts#L217) *** ### domains() [#domains-1] > **domains**(): [`DomainsClient`](../../clients/domains/classes/DomainsClient.md) #### Returns [#returns-112] [`DomainsClient`](../../clients/domains/classes/DomainsClient.md) #### Defined in [#defined-in-172] [AlternateFuturesSdk.ts:158](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/AlternateFuturesSdk.ts#L158) *** ### ens() [#ens] > **ens**(): [`EnsClient`](../../clients/ens/classes/EnsClient.md) #### Returns [#returns-113] [`EnsClient`](../../clients/ens/classes/EnsClient.md) #### Defined in [#defined-in-173] [AlternateFuturesSdk.ts:178](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/AlternateFuturesSdk.ts#L178) *** ### functions() [#functions] > **functions**(): [`FunctionsClient`](../../clients/functions/classes/FunctionsClient.md) #### Returns [#returns-114] [`FunctionsClient`](../../clients/functions/classes/FunctionsClient.md) #### Defined in [#defined-in-174] [AlternateFuturesSdk.ts:207](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/AlternateFuturesSdk.ts#L207) *** ### getVersion() [#getversion] > **getVersion**(): `Promise`\<`any`> #### Returns [#returns-115] `Promise`\<`any`> #### Defined in [#defined-in-175] [AlternateFuturesSdk.ts:101](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/AlternateFuturesSdk.ts#L101) *** ### ipfs() [#ipfs] > **ipfs**(): [`IpfsClient`](../../clients/ipfs/classes/IpfsClient.md) #### Returns [#returns-116] [`IpfsClient`](../../clients/ipfs/classes/IpfsClient.md) #### Defined in [#defined-in-176] [AlternateFuturesSdk.ts:126](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/AlternateFuturesSdk.ts#L126) *** ### ipns() [#ipns] > **ipns**(): [`IpnsClient`](../../clients/ipns/classes/IpnsClient.md) #### Returns [#returns-117] [`IpnsClient`](../../clients/ipns/classes/IpnsClient.md) #### Defined in [#defined-in-177] [AlternateFuturesSdk.ts:118](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/AlternateFuturesSdk.ts#L118) *** ### privateGateways() [#privategateways] > **privateGateways**(): [`PrivateGatewayClient`](../../clients/privateGateway/classes/PrivateGatewayClient.md) #### Returns [#returns-118] [`PrivateGatewayClient`](../../clients/privateGateway/classes/PrivateGatewayClient.md) #### Defined in [#defined-in-178] [AlternateFuturesSdk.ts:186](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/AlternateFuturesSdk.ts#L186) *** ### projects() [#projects] > **projects**(): [`ProjectsClient`](../../clients/projects/classes/ProjectsClient.md) #### Returns [#returns-119] [`ProjectsClient`](../../clients/projects/classes/ProjectsClient.md) #### Defined in [#defined-in-179] [AlternateFuturesSdk.ts:148](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/AlternateFuturesSdk.ts#L148) *** ### sites() [#sites] > **sites**(): [`SitesClient`](../../clients/sites/classes/SitesClient.md) #### Returns [#returns-120] [`SitesClient`](../../clients/sites/classes/SitesClient.md) #### Defined in [#defined-in-180] [AlternateFuturesSdk.ts:140](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/AlternateFuturesSdk.ts#L140) *** ### storage() [#storage-1] > **storage**(): [`StorageClient`](../../clients/storage/classes/StorageClient.md) #### Returns [#returns-121] [`StorageClient`](../../clients/storage/classes/StorageClient.md) #### Defined in [#defined-in-181] [AlternateFuturesSdk.ts:196](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/AlternateFuturesSdk.ts#L196) *** ### user() [#user] > **user**(): [`UserClient`](../../clients/user/classes/UserClient.md) #### Returns [#returns-122] [`UserClient`](../../clients/user/classes/UserClient.md) #### Defined in [#defined-in-182] [AlternateFuturesSdk.ts:110](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/AlternateFuturesSdk.ts#L110) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / [index](../README.md) / ApplicationAccessTokenService # Class: ApplicationAccessTokenService [#class-applicationaccesstokenservice] ## Extends [#extends] * `AccessTokenService` ## Constructors [#constructors-14] ### new ApplicationAccessTokenService() [#new-applicationaccesstokenservice] > **new ApplicationAccessTokenService**(`__namedParameters`): [`ApplicationAccessTokenService`](ApplicationAccessTokenService.md) #### Parameters [#parameters-92] • **\_\_namedParameters**: `ApplicationAccessTokenServiceOptions` #### Returns [#returns-123] [`ApplicationAccessTokenService`](ApplicationAccessTokenService.md) #### Overrides [#overrides] `AccessTokenService.constructor` #### Defined in [#defined-in-183] [libs/AccessTokenService/ApplicationAccessTokenService.ts:21](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/libs/AccessTokenService/ApplicationAccessTokenService.ts#L21) ## Methods [#methods-14] ### getAccessToken() [#getaccesstoken] > **getAccessToken**(): `Promise`\<`string`> #### Returns [#returns-124] `Promise`\<`string`> #### Overrides [#overrides-1] `AccessTokenService.getAccessToken` #### Defined in [#defined-in-184] [libs/AccessTokenService/ApplicationAccessTokenService.ts:54](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/libs/AccessTokenService/ApplicationAccessTokenService.ts#L54) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / [index](../README.md) / PersonalAccessTokenService # Class: PersonalAccessTokenService [#class-personalaccesstokenservice] ## Extends [#extends-1] * `AccessTokenService` ## Constructors [#constructors-15] ### new PersonalAccessTokenService() [#new-personalaccesstokenservice] > **new PersonalAccessTokenService**(`__namedParameters`): [`PersonalAccessTokenService`](PersonalAccessTokenService.md) #### Parameters [#parameters-93] • **\_\_namedParameters**: `PersonalAccessTokenServiceOptions` #### Returns [#returns-125] [`PersonalAccessTokenService`](PersonalAccessTokenService.md) #### Overrides [#overrides-2] `AccessTokenService.constructor` #### Defined in [#defined-in-185] [libs/AccessTokenService/PersonalAccessTokenService.ts:22](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/libs/AccessTokenService/PersonalAccessTokenService.ts#L22) ## Methods [#methods-15] ### close() [#close] > **close**(): `void` #### Returns [#returns-126] `void` #### Defined in [#defined-in-186] [libs/AccessTokenService/PersonalAccessTokenService.ts:86](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/libs/AccessTokenService/PersonalAccessTokenService.ts#L86) *** ### getAccessToken() [#getaccesstoken-1] > **getAccessToken**(): `Promise`\<`string`> #### Returns [#returns-127] `Promise`\<`string`> #### Overrides [#overrides-3] `AccessTokenService.getAccessToken` #### Defined in [#defined-in-187] [libs/AccessTokenService/PersonalAccessTokenService.ts:78](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/libs/AccessTokenService/PersonalAccessTokenService.ts#L78) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / [index](../README.md) / StaticAccessTokenService # Class: StaticAccessTokenService [#class-staticaccesstokenservice] ## Extends [#extends-2] * `AccessTokenService` ## Constructors [#constructors-16] ### new StaticAccessTokenService() [#new-staticaccesstokenservice] > **new StaticAccessTokenService**(`__namedParameters`): [`StaticAccessTokenService`](StaticAccessTokenService.md) #### Parameters [#parameters-94] • **\_\_namedParameters**: `StaticAccessTokenServiceOptions` #### Returns [#returns-128] [`StaticAccessTokenService`](StaticAccessTokenService.md) #### Overrides [#overrides-4] `AccessTokenService.constructor` #### Defined in [#defined-in-188] [libs/AccessTokenService/StaticAccessTokenService.ts:12](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/libs/AccessTokenService/StaticAccessTokenService.ts#L12) ## Methods [#methods-16] ### getAccessToken() [#getaccesstoken-2] > **getAccessToken**(): `Promise`\<`string`> #### Returns [#returns-129] `Promise`\<`string`> #### Overrides [#overrides-5] `AccessTokenService.getAccessToken` #### Defined in [#defined-in-189] [libs/AccessTokenService/StaticAccessTokenService.ts:22](https://github.com/alternatefutures/alternate-clouds-sdk/blob/f1f531c266f4d1cb6103c9a49bb310a573d5dd4a/src/libs/AccessTokenService/StaticAccessTokenService.ts#L22) *** [**@alternatefutures/sdk**](../../README.md) • **Docs** *** [@alternatefutures/sdk](../../README.md) / [index](../README.md) / createClient # Variable: createClient [#variable-createclient] > **createClient**: `any` *** # SDK overview (/sdk) The Alternate Futures SDK provides a JavaScript/TypeScript library for programmatic access to the platform. Build decentralized applications with IPFS storage, serverless functions, and more. ## Features [#features] * **Type-Safe** - Full TypeScript support with comprehensive type definitions * **Multi-Platform** - Works in both Node.js and browser environments * **Complete API Access** - Sites, storage, domains, IPNS, ENS, functions, and billing * **Multiple Auth Methods** - Personal access tokens, static tokens, and OAuth flows ## Installation [#installation] ```bash npm install @alternatefutures/sdk ``` ```bash pnpm add @alternatefutures/sdk ``` ```bash yarn add @alternatefutures/sdk ``` ## Quick Start [#quick-start] ### Node.js [#nodejs] ```typescript import { AlternateFuturesSdk, PersonalAccessTokenService } from '@alternatefutures/sdk/node'; // Initialize with personal access token const accessTokenService = new PersonalAccessTokenService({ personalAccessToken: process.env.AF_TOKEN, projectId: process.env.AF_PROJECT_ID, }); const af = new AlternateFuturesSdk({ accessTokenService, }); // List your sites const sites = await af.sites().list(); console.log('Sites:', sites); // Upload to IPFS const result = await af.ipfs().add('./dist'); console.log('CID:', result.pin.cid); ``` ### Browser [#browser] ```typescript import { AlternateFuturesSdk, StaticAccessTokenService } from '@alternatefutures/sdk'; const accessTokenService = new StaticAccessTokenService({ token: 'your-access-token', projectId: 'your-project-id', }); const af = new AlternateFuturesSdk({ accessTokenService, }); // Use SDK methods const sites = await af.sites().list(); ``` **Note:** The Node.js version (`@alternatefutures/sdk/node`) provides access to filesystem-dependent features like directory uploads. The browser version has a narrower feature set suitable for web applications. ## SDK Clients [#sdk-clients] | Client | Method | Description | | -------------------- | ---------------------- | ------------------------------------- | | **Sites** | `af.sites()` | Deploy and manage static sites | | **Projects** | `af.projects()` | Manage projects and settings | | **Domains** | `af.domains()` | Custom domain configuration | | **Storage** | `af.storage()` | Manage stored files | | **IPFS** | `af.ipfs()` | Direct IPFS operations (Node.js only) | | **IPNS** | `af.ipns()` | IPNS record management | | **ENS** | `af.ens()` | ENS domain integration | | **Functions** | `af.functions()` | Serverless function management | | **Applications** | `af.applications()` | OAuth application management | | **Private Gateways** | `af.privateGateways()` | IPFS gateway management | | **User** | `af.user()` | User account information | | **Billing** | `af.billing()` | Billing and usage data | ## Authentication Options [#authentication-options] The SDK supports three authentication methods: ### 1. Personal Access Token (Server-Side) [#1-personal-access-token-server-side] Best for backend services, scripts, and CI/CD pipelines. ```typescript import { PersonalAccessTokenService } from '@alternatefutures/sdk/node'; const accessTokenService = new PersonalAccessTokenService({ personalAccessToken: process.env.AF_TOKEN, projectId: process.env.AF_PROJECT_ID, }); ``` ### 2. Static Access Token (Browser) [#2-static-access-token-browser] Best for client-side apps where the token is already available. ```typescript import { StaticAccessTokenService } from '@alternatefutures/sdk'; const accessTokenService = new StaticAccessTokenService({ token: 'jwt-token', projectId: 'project-id', }); ``` ### 3. Application Access Token (OAuth) [#3-application-access-token-oauth] Best for building applications with user authentication. ```typescript import { ApplicationAccessTokenService } from '@alternatefutures/sdk'; const accessTokenService = new ApplicationAccessTokenService({ clientId: 'your-client-id', }); // Trigger user login await accessTokenService.login(); ``` ## Common Examples [#common-examples] ### Deploy a Site [#deploy-a-site] ```typescript // Create a new site const site = await af.sites().create({ name: 'my-site' }); // Upload content to IPFS const upload = await af.ipfs().add('./dist'); // Create deployment const deployment = await af.sites().createDeployment({ siteId: site.id, cid: upload.pin.cid, }); ``` ### Manage Storage [#manage-storage] ```typescript // List all stored files const files = await af.storage().list(); // Get file details const file = await af.storage().get({ cid: 'bafybei...' }); // Delete a file await af.storage().delete({ cid: 'bafybei...' }); ``` ### Work with IPNS [#work-with-ipns] ```typescript // Create IPNS record const ipns = await af.ipns().create({ siteId: 'site_abc123' }); // Publish new content await af.ipns().publish({ name: ipns.name, hash: 'bafybei...', }); // List all IPNS records const records = await af.ipns().list(); ``` ### Custom Domains [#custom-domains] ```typescript // Add a domain to a site const domain = await af.domains().create({ siteId: 'site_abc123', hostname: 'www.example.com', }); // Verify DNS configuration const verified = await af.domains().verify({ id: domain.id }); ``` ## TypeScript Support [#typescript-support] The SDK provides full TypeScript definitions: ```typescript import { AlternateFuturesSdk, PersonalAccessTokenService, type Site, type Deployment, type Domain, type IpnsRecord, type StoragePin, type Project, type AFFunction, } from '@alternatefutures/sdk/node'; // Types are automatically inferred const sites: Site[] = await af.sites().list(); ``` ## Requirements [#requirements] * Node.js 18.0.0 or higher * Works in both Node.js and modern browser environments ## Documentation [#documentation] * **[Installation Guide](./installation)** - Detailed installation and configuration * **[Quick Start](./quickstart)** - Get started in 5 minutes * **[API Reference](./api)** - Complete API documentation ## Getting Help [#getting-help] * **[CLI Documentation](/cli/)** - Command-line interface * **[Guides](/guides/)** - Tutorials and best practices * **[GitHub Issues](https://github.com/alternatefutures)** - Report bugs or request features # Install the SDK (/sdk/installation) Complete guide to installing and configuring the Alternate Futures SDK. ## Requirements [#requirements] * **Node.js 18.0.0 or higher** - [Download here](https://nodejs.org/) * **npm, pnpm, or yarn** - Package manager Check your Node.js version: ```bash node --version # Should be v18.0.0 or higher ``` ## Installation [#installation] ```bash npm install @alternatefutures/sdk ``` ```bash pnpm add @alternatefutures/sdk ``` ```bash yarn add @alternatefutures/sdk ``` ## Platform-Specific Imports [#platform-specific-imports] The SDK provides different entry points for Node.js and browser environments. ### Node.js [#nodejs] For server-side applications, use the `/node` entry point: ```typescript import { AlternateFuturesSdk, PersonalAccessTokenService } from '@alternatefutures/sdk/node'; ``` The Node.js version includes: * File system operations (upload directories) * Full IPFS functionality * Server-side authentication flows ### Browser [#browser] For browser applications, use the default import: ```typescript import { AlternateFuturesSdk, StaticAccessTokenService } from '@alternatefutures/sdk'; ``` The browser version has a narrower feature set optimized for web applications. ## Authentication Methods [#authentication-methods] The SDK supports multiple authentication approaches. Choose the one that fits your use case. ### 1. Personal Access Token (Recommended for Servers) [#1-personal-access-token-recommended-for-servers] Best for: Server-side applications, scripts, CI/CD pipelines. ```typescript import { AlternateFuturesSdk, PersonalAccessTokenService } from '@alternatefutures/sdk/node'; const accessTokenService = new PersonalAccessTokenService({ personalAccessToken: process.env.AF_TOKEN, projectId: process.env.AF_PROJECT_ID, }); const af = new AlternateFuturesSdk({ accessTokenService, }); ``` **Get your token:** 1. Log in to [clouds.alternatefutures.ai](https://clouds.alternatefutures.ai) 2. Go to Settings > API Keys 3. Create a new Personal Access Token 4. Copy the token (starts with `pat_`) ### 2. Static Access Token (Browser Apps) [#2-static-access-token-browser-apps] Best for: Client-side applications where the token is already available. ```typescript import { AlternateFuturesSdk, StaticAccessTokenService } from '@alternatefutures/sdk'; const accessTokenService = new StaticAccessTokenService({ token: 'your-jwt-token', projectId: 'your-project-id', }); const af = new AlternateFuturesSdk({ accessTokenService, }); ``` ### 3. Application Access Token (SDK-Powered Apps) [#3-application-access-token-sdk-powered-apps] Best for: Building applications that authenticate users via Alternate Futures. ```typescript import { AlternateFuturesSdk, ApplicationAccessTokenService } from '@alternatefutures/sdk'; const accessTokenService = new ApplicationAccessTokenService({ clientId: 'your-client-id', }); const af = new AlternateFuturesSdk({ accessTokenService, }); // User login flow await accessTokenService.login(); ``` ## Environment Configuration [#environment-configuration] ### Environment Variables [#environment-variables] Store your credentials securely using environment variables: ```bash # .env AF_TOKEN=pat_your_personal_access_token_here AF_PROJECT_ID=prj_your_project_id_here ``` **Important:** Add `.env` to your `.gitignore` to avoid committing secrets. ### Loading Environment Variables [#loading-environment-variables] **Node.js with dotenv:** ```typescript import 'dotenv/config'; import { AlternateFuturesSdk, PersonalAccessTokenService } from '@alternatefutures/sdk/node'; const af = new AlternateFuturesSdk({ accessTokenService: new PersonalAccessTokenService({ personalAccessToken: process.env.AF_TOKEN!, projectId: process.env.AF_PROJECT_ID!, }), }); ``` **Vite (browser):** ```typescript // Vite automatically loads .env files const token = import.meta.env.VITE_AF_TOKEN; ``` **Next.js:** ```typescript // Use NEXT_PUBLIC_ prefix for client-side access const token = process.env.NEXT_PUBLIC_AF_TOKEN; ``` ## TypeScript Configuration [#typescript-configuration] The SDK includes TypeScript definitions. For optimal type checking, ensure your `tsconfig.json` includes: ```json { "compilerOptions": { "moduleResolution": "bundler", "strict": true, "esModuleInterop": true } } ``` ### Importing Types [#importing-types] ```typescript import { AlternateFuturesSdk, PersonalAccessTokenService, type Site, type Deployment, type Domain, type IpnsRecord, type Project, type StoragePin, type AFFunction, } from '@alternatefutures/sdk/node'; ``` ## SDK Client Reference [#sdk-client-reference] The SDK exposes multiple clients for different features: | Client | Access Method | Description | | ---------------- | ---------------------- | ------------------------------------- | | Sites | `af.sites()` | Manage static sites and deployments | | Projects | `af.projects()` | Manage projects | | Domains | `af.domains()` | Custom domain configuration | | Storage | `af.storage()` | Manage stored files | | IPFS | `af.ipfs()` | Direct IPFS operations (Node.js only) | | IPNS | `af.ipns()` | IPNS record management | | ENS | `af.ens()` | ENS domain integration | | Functions | `af.functions()` | Serverless functions | | Applications | `af.applications()` | SDK-powered app management | | Private Gateways | `af.privateGateways()` | IPFS gateway management | | User | `af.user()` | User account information | | Billing | `af.billing()` | Billing and usage data | ## Complete Example [#complete-example] Here's a complete example showing SDK initialization and common operations: ```typescript import 'dotenv/config'; import { AlternateFuturesSdk, PersonalAccessTokenService, type Site, type StoragePin, } from '@alternatefutures/sdk/node'; async function main() { // Initialize SDK const accessTokenService = new PersonalAccessTokenService({ personalAccessToken: process.env.AF_TOKEN!, projectId: process.env.AF_PROJECT_ID!, }); const af = new AlternateFuturesSdk({ accessTokenService, }); // List all sites const sites: Site[] = await af.sites().list(); console.log('Sites:', sites.map(s => s.name)); // Upload a file to IPFS const uploadResult = await af.ipfs().add('./dist'); console.log('Uploaded CID:', uploadResult.pin.cid); // List storage const pins: StoragePin[] = await af.storage().list(); console.log('Stored files:', pins.length); // Get project info const projects = await af.projects().list(); console.log('Projects:', projects.map(p => p.name)); } main().catch(console.error); ``` ## Custom Configuration [#custom-configuration] ### Custom API Endpoints [#custom-api-endpoints] For self-hosted or development environments: ```typescript const af = new AlternateFuturesSdk({ accessTokenService, graphqlServiceApiUrl: 'https://custom-api.example.com/graphql', ipfsStorageApiUrl: 'https://custom-ipfs.example.com', uploadProxyApiUrl: 'https://custom-uploads.example.com', }); ``` ## Troubleshooting [#troubleshooting] ### "AuthorizationError" [#authorizationerror] * Verify your token is correct and not expired * Ensure the project ID matches an accessible project * Check that your token has the necessary permissions ### "SdkRequiredNodeRuntimeError" [#sdkrequirednoderuntimeerror] This error occurs when using Node.js-specific features (like `af.ipfs()`) in a browser environment. Use the browser-compatible methods instead. ### "EnvNotSetError" [#envnotseterror] Required environment variables are missing. Ensure these are set: * `SDK__GRAPHQL_API_URL` * `SDK__IPFS__STORAGE_API_URL` * `SDK__UPLOAD_PROXY_API_URL` When using the standard SDK installation, these are configured automatically. ### TypeScript Import Errors [#typescript-import-errors] If you see TypeScript errors with imports, ensure: 1. Your `moduleResolution` is set to `bundler` or `node16` 2. You're importing from the correct entry point (`/node` vs default) ## Next Steps [#next-steps] * **[Quick Start](./quickstart)** - Get started in 5 minutes * **[API Reference](./api)** - Complete SDK API documentation * **[CLI Documentation](/cli/)** - Command-line interface * **[Guides](/guides/)** - Tutorials and best practices # SDK quick start (/sdk/quickstart) Get started with the Alternate Futures SDK in under 5 minutes. ## Installation [#installation] ```bash npm install @alternatefutures/sdk ``` ```bash pnpm add @alternatefutures/sdk ``` ```bash yarn add @alternatefutures/sdk ``` ## Basic Setup [#basic-setup] ### Node.js [#nodejs] ```typescript import { AlternateFuturesSdk, PersonalAccessTokenService } from '@alternatefutures/sdk/node'; // Create the access token service const accessTokenService = new PersonalAccessTokenService({ personalAccessToken: process.env.AF_TOKEN, projectId: process.env.AF_PROJECT_ID, }); // Initialize the SDK const af = new AlternateFuturesSdk({ accessTokenService, }); // You're ready to go! const sites = await af.sites().list(); console.log('Sites:', sites); ``` ### Browser [#browser] ```typescript import { AlternateFuturesSdk, StaticAccessTokenService } from '@alternatefutures/sdk'; // For browser apps, use StaticAccessTokenService const accessTokenService = new StaticAccessTokenService({ token: 'your-access-token', projectId: 'your-project-id', }); const af = new AlternateFuturesSdk({ accessTokenService, }); ``` ## Common Operations [#common-operations] ### List Sites [#list-sites] ```typescript const sites = await af.sites().list(); for (const site of sites) { console.log(`${site.name} - ${site.slug}`); } ``` ### Upload to IPFS [#upload-to-ipfs] ```typescript // Node.js only - upload a file const result = await af.ipfs().add('./my-file.txt'); console.log('CID:', result.pin.cid); // Or upload content directly const result = await af.ipfs().addFromContent({ content: 'Hello, decentralized web!', path: 'hello.txt', }); ``` ### Manage Storage [#manage-storage] ```typescript // List stored files const pins = await af.storage().list(); // Get a specific file const file = await af.storage().get({ cid: 'bafybei...' }); // Delete a file await af.storage().delete({ cid: 'bafybei...' }); ``` ### Work with Domains [#work-with-domains] ```typescript // List domains for a site const domains = await af.domains().listBySite({ siteId: 'site_abc123' }); // Add a custom domain const domain = await af.domains().create({ siteId: 'site_abc123', hostname: 'www.example.com', }); ``` ### Create IPNS Records [#create-ipns-records] ```typescript // Create an IPNS record for a site const ipns = await af.ipns().create({ siteId: 'site_abc123' }); console.log('IPNS Name:', ipns.name); // Publish new content to IPNS await af.ipns().publish({ name: ipns.name, hash: 'bafybei...', }); ``` ## Error Handling [#error-handling] ```typescript import { AlternateFuturesSdk, PersonalAccessTokenService } from '@alternatefutures/sdk/node'; try { const af = new AlternateFuturesSdk({ accessTokenService: new PersonalAccessTokenService({ personalAccessToken: process.env.AF_TOKEN, projectId: process.env.AF_PROJECT_ID, }), }); const sites = await af.sites().list(); } catch (error) { if (error.name === 'AuthorizationError') { console.error('Invalid or expired token'); } else if (error.name === 'NotFoundError') { console.error('Resource not found'); } else { console.error('Unexpected error:', error.message); } } ``` ## TypeScript Support [#typescript-support] The SDK is fully typed. Import types for better IDE support: ```typescript import { AlternateFuturesSdk, PersonalAccessTokenService, type Site, type Domain, type IpnsRecord, type StoragePin, } from '@alternatefutures/sdk/node'; // Types are automatically inferred const sites: Site[] = await af.sites().list(); ``` ## Environment Variables [#environment-variables] For security, store your credentials in environment variables: ```bash # .env AF_TOKEN=pat_your_personal_access_token AF_PROJECT_ID=prj_your_project_id ``` ```typescript import 'dotenv/config'; import { AlternateFuturesSdk, PersonalAccessTokenService } from '@alternatefutures/sdk/node'; const af = new AlternateFuturesSdk({ accessTokenService: new PersonalAccessTokenService({ personalAccessToken: process.env.AF_TOKEN!, projectId: process.env.AF_PROJECT_ID!, }), }); ``` ## Next Steps [#next-steps] * **[Installation Guide](./installation)** - Detailed setup instructions * **[API Reference](./api)** - Complete SDK API documentation * **[CLI Documentation](/cli/)** - Command-line interface * **[Guides](/guides/)** - Tutorials and how-tos # Command reference (/cli/commands) {/* AUTO-GENERATED by scripts/generate-cli-docs.mjs from @alternatefutures/acc@1.1.0 — do not edit by hand. */} Use `acc --help` to see detailed help for any command. This page is auto-generated from the CLI source (v1.1.0). ## Global options [#global-options] * `--debug` · enable debug output * `--local` · use local dev services (separate credential slot) * `-V, --version` · print CLI version * `-h, --help` · help for any command ## Account [#account] ### `acc login` [#acc-login] Log in (opens browser) | Option | Description | | ------------------ | -------------------------------------------------- | | `-e, --email` | Login via email verification (no browser required) | | `--auth-url ` | Override auth service URL | ### `acc logout` [#acc-logout] Log out of the CLI ### `acc whoami` [#acc-whoami] Show your identity and active project | Option | Description | | -------- | --------------------------------------------- | | `--json` | Machine-readable JSON output (for agents/CI). | ## Compute [#compute] ### `acc projects` [#acc-projects] Manage your projects ### `acc projects list` [#acc-projects-list] List all projects ### `acc projects create` [#acc-projects-create] Create a new project | Option | Description | | ----------------- | ------------ | | `--name ` | Project name | ### `acc projects update [id]` [#acc-projects-update-id] Rename a project ### `acc projects switch [id]` [#acc-projects-switch-id] Switch to a different project ### `acc projects delete [id]` [#acc-projects-delete-id] Delete a project and all its services ### `acc services` [#acc-services] Manage services in a project | Option | Description | | ---------------------------- | ---------------------- | | `-p, --project ` | Use a specific project | ### `acc services list` [#acc-services-list] List all services in the project ### `acc services info [id]` [#acc-services-info-id] Show details for a service ### `acc services create` [#acc-services-create] Create a new service (from a template, Docker image, or empty server) | Option | Description | | ------------------------ | ----------------------------------------------------------------------------------------------------------------------- | | `--kind ` | Service kind: template \| docker \| server \| function \| github | | `--name ` | Service name (skips the name prompt; must be unique in the project) | | `--template ` | Template id (for --kind template — skips the catalog browse) | | `--image ` | Docker image (for --kind docker — e.g. nginx:latest) | | `--port ` | Container port (for --kind docker) | | `--os ` | Base OS image (for --kind server — e.g. ubuntu:24.04) | | `--confidential` | Deploy on a TEE: verifiable confidential compute. | | `--region ` | Curated region: us-east \| us-west \| eu \| asia. | | `--cpu ` | Override CPU (vCPUs). | | `--memory ` | Override memory (e.g. 4Gi). | | `--storage ` | Override storage (e.g. 20Gi). | | `--gpu` | Attach a GPU. | | `--no-gpu` | Skip GPU. | | `--gpu-model ` | GPU model. | | `--gpu-count ` | Number of GPUs. | | `--spend ` | Spend control: payg \| budget \| stop. | | `--budget-total ` | Budget cap (lifetime, USD). | | `--budget-monthly ` | Budget cap (per month, USD). | | `--stop-hours ` | Auto-stop after N hours. | | `--stop-days ` | Auto-stop after N days. | | `--env ` | Set required env var as KEY=VALUE. Repeatable. | | `--ssh-key ` | Break-glass OpenSSH public key (--kind server). Baked into the box so you keep direct SSH if the platform channel dies. | | `--ssh-key-file ` | Read the break-glass public key from a file (e.g. \~/.ssh/id\_ed25519.pub). | | `-y, --yes` | Skip confirmation prompts. | ### `acc services deploy [id]` [#acc-services-deploy-id] Deploy (or redeploy) a service | Option | Description | | ------------------------ | -------------------------------------------------------------------------------------------------- | | `--region ` | Curated region: us-east \| us-west \| eu \| asia. Omit for "Any (cheapest globally)". | | `--confidential` | Deploy on a TEE: verifiable confidential compute. | | `--cpu ` | Override CPU (vCPUs). | | `--memory ` | Override memory (e.g. 4Gi). | | `--storage ` | Override storage (e.g. 20Gi). | | `--gpu` | Attach a GPU. Use --gpu-model and --gpu-count to specify. | | `--no-gpu` | Skip GPU even if the template defaults to one. | | `--gpu-model ` | GPU model (H100, H200, A100, RTX4090, ...). | | `--gpu-count ` | Number of GPUs. | | `--spend ` | Spend control: payg \| budget \| stop. | | `--budget-total ` | Budget cap (lifetime, USD). | | `--budget-monthly ` | Budget cap (per month, USD). | | `--stop-hours ` | Auto-stop after N hours. | | `--stop-days ` | Auto-stop after N days. | | `--env ` | Set required env var as KEY=VALUE. Repeatable. | | `--ssh-key ` | Break-glass OpenSSH public key (raw servers only). Ignored for container and confidential deploys. | | `--ssh-key-file ` | Read the break-glass public key from a file (e.g. \~/.ssh/id\_ed25519.pub). | | `-y, --yes` | Skip confirmation prompts. | ### `acc services logs [id]` [#acc-services-logs-id] Fetch logs for a service | Option | Description | | ------------ | ----------------------------------- | | `--tail ` | Number of log lines (default: `50`) | ### `acc services close [id]` [#acc-services-close-id] Close the active deployment on a service ### `acc services delete [id]` [#acc-services-delete-id] Delete a service (closes deployment first if running) ### `acc services env` [#acc-services-env] Manage service environment variables ### `acc services list [service]` [#acc-services-list-service] List env vars for a service ### `acc services set ` [#acc-services-set-service-key-value] Set an env var (creates or updates) ### `acc services unset ` [#acc-services-unset-service-key] Delete an env var | Option | Description | | ----------- | ------------------------ | | `-y, --yes` | Skip confirmation prompt | ### `acc services link [source] [target]` [#acc-services-link-source-target] Link two services (target connection info exposed to source) | Option | Description | | ---------------- | -------------------------------------- | | `--alias ` | Alias used as env key prefix (e.g. DB) | ### `acc services unlink [source] [target]` [#acc-services-unlink-source-target] Remove a service link | Option | Description | | ----------- | ------------------------ | | `-y, --yes` | Skip confirmation prompt | ### `acc deployments` [#acc-deployments] List and view deployments | Option | Description | | ------------------------ | ----------------------------------------- | | `--project ` | Filter by project | | `--service ` | Filter by service | | `--status ` | Filter by status (active, failed, closed) | | `--all` | Include closed and old deployments | | `-l, --limit ` | Max deployments to show (default: `50`) | ### `acc deployments list` [#acc-deployments-list] List all deployments | Option | Description | | ------------------------ | --------------------------------------- | | `--project ` | Filter by project | | `--service ` | Filter by service | | `--status ` | Filter by status | | `--all` | Include closed and old deployments | | `-l, --limit ` | Max deployments to show (default: `50`) | ### `acc regions` [#acc-regions] List regions with availability and pricing | Option | Description | | ------------------- | ------------------------------------------------------------------------------ | | `--provider ` | Filter by provider: akash \| phala (default: akash) | | `--gpu ` | Surface median price for a specific GPU model (e.g. h100, h200, a100, rtx4090) | ### `acc templates` [#acc-templates] Browse available service templates ### `acc templates list` [#acc-templates-list] List available deployment templates | Option | Description | | --------------------------- | ---------------------------------------------------------------------------------- | | `-c, --category ` | Filter by category (AI\_ML, WEB\_SERVER, GAME\_SERVER, DATABASE, DEVTOOLS, CUSTOM) | ### `acc templates info ` [#acc-templates-info-templateid] Show detailed template information ### `acc ssh ` [#acc-ssh-serviceid] Open a shell in a deployment | Option | Description | | ------------------ | ------------------------------------------------ | | `--service ` | SDL service name (for multi-service deployments) | | `--command ` | Command to execute (default: /bin/bash) | ### `acc cp ` [#acc-cp-source-dest] Copy a file to/from a deployment. Mark the remote side as \:\. | Option | Description | | ------------------ | ------------------------------------------------ | | `--service ` | SDL service name (for multi-service deployments) | ### `acc attest ` [#acc-attest-serviceid] Fetch the TEE attestation report for a confidential deployment | Option | Description | | ---------- | ---------------------------------------------------------------------------------------------------------------------------------------- | | `--json` | Machine-readable JSON output (for agents/CI). | | `--verify` | Verify the quote client-side against Intel roots (@phala/dcap-qvl; collateral from Intel PCS) and check the MRCONFIGID V1 compose\_hash. | ## Chat [#chat] ### `acc chat` [#acc-chat] End-to-end encrypted chat ### `acc chat join [target]` [#acc-chat-join-target] Open an interactive encrypted chat session ### `acc chat send [target]` [#acc-chat-send-target] Send one message to a room, then exit (no TTY required) | Option | Description | | ------------------------- | ----------------------------------------------------------------------------------------- | | `--message ` | Message text (or pipe it on stdin) | | `--reply-to ` | Thread this as a reply to a message (copy the \:\ from acc chat read --json) | | `--json` | Machine-readable JSON output (for agents/CI) | ### `acc chat read [target]` [#acc-chat-read-target] Read room history; --watch to stream live (no TTY required) | Option | Description | | --------- | ------------------------------------------------------ | | `--watch` | Stay connected and stream new messages + presence | | `--json` | JSON snapshot; with --watch, NDJSON one event per line | ### `acc chat agent [target]` [#acc-chat-agent-target] Participate as an agent: driver mode (you answer) or --exec bot mode | Option | Description | | ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `--bridge` | BRIDGE mode: stay connected (one persistent presence) and relay via files — addressed messages → inbox, lines you append to outbox → sent. Best for a live LLM agent. | | `--inbox ` | BRIDGE inbox file (default \~/.af-chat/\.in.jsonl) | | `--outbox ` | BRIDGE outbox file (default \~/.af-chat/\.out) | | `--exec ` | BOT mode: a command that reads the message (stdin JSON + AF\_MSG\_\* env) and prints the reply, for a headless bot. | | `--mention ` | Comma-separated trigger words; reply only when a message contains one (default: your display name) | | `--all` | Reply to every message, not just when mentioned | | `--context ` | Recent messages of context passed to the brain (default 10) | | `--timeout ` | Max time for the brain to produce a reply (default 60000) | | `--cooldown ` | Minimum gap between replies — throttles runaway loops (default 0) | ## Billing [#billing] ### `acc billing` [#acc-billing] Manage billing and subscriptions ### `acc billing balance` [#acc-billing-balance] Show current credit balance ### `acc billing topup` [#acc-billing-topup] Add prepaid credits with a crypto stablecoin transfer | Option | Description | | ---------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | | `--crypto` | Pay with crypto (required — card payments are web-only) | | `--amount ` | Amount in USD, e.g. 25 | | `--chain ` | Network: base \| ethereum \| arbitrum \| optimism \| polygon (default: `base`) | | `--token ` | Stablecoin: USDC \| USDT \| DAI (default: `USDC`) | | `--refund-address
` | Address you control that receives the Relay refund if the sent amount does not exactly match the quote (prompted if omitted) | | `--org ` | Organization to credit (default: first org) | | `--no-wait` | Print the deposit address and exit without polling | ### `acc pat` [#acc-pat] ### `acc pat list` [#acc-pat-list] ### `acc pat create` [#acc-pat-create] ### `acc pat delete` [#acc-pat-delete] ## Environment variables [#environment-variables] | Variable | Purpose | | ----------------- | ------------------------------------------------------------- | | `AF_TOKEN` | Personal access token (overrides stored login, for CI/agents) | | `AF_PROJECT_ID` | Project to operate on (for CI/agents) | | `AF_ORG_ID` | Organization override | | `AF_API_URL` | Override cloud API base URL | | `AF_AUTH_API_URL` | Override auth service URL | # CLI overview (/cli) `acc` is the unified command line interface to Alternate Clouds - deploy AI agents, containers, GPU workloads, and confidential (TEE) services to decentralized infrastructure from your terminal. ## Install [#install] ```bash npm install -g @alternatefutures/acc acc --version ``` Requires Node.js 18.18.2 or later. ## Log in [#log-in] ```bash acc login # opens the browser to authorize the CLI acc login --email # email verification, no browser required acc whoami # verify who you are and your active project ``` ## Command groups [#command-groups] | Group | Commands | What it does | | ------- | ------------------------------------------------------------------------------------ | --------------------------------------------------- | | Account | `login`, `logout`, `whoami` | Authentication and identity | | Compute | `projects`, `services`, `deployments`, `regions`, `templates`, `ssh`, `cp`, `attest` | Create, deploy, and manage services | | Chat | `chat join`, `chat send`, `chat read`, `chat agent` | End-to-end-encrypted rooms, including agent bridges | | Billing | `billing balance`, `billing topup`, `pat` | Credits, topups, personal access tokens | See the [full command reference](/cli/commands) - it is auto-generated from the CLI source, so it always matches the released CLI. ## A 60-second deploy [#a-60-second-deploy] ```bash acc login acc projects create --name my-project acc services create --kind docker --image nginx:latest --port 80 -y acc services list acc services logs ``` ## For agents and CI [#for-agents-and-ci] Every command works non-interactively with environment variables: ```bash export AF_TOKEN= # from `acc pat create` export AF_PROJECT_ID= acc whoami --json # machine-readable pre-flight check acc services deploy -y ``` This entire docs site is available as plain markdown for AI agents: fetch [/llms.txt](/llms.txt) for an index or `/llms-full.txt` for everything in one file. Every page also has a Copy Markdown button. # Install the CLI (/cli/installation) ## Requirements [#requirements] * Node.js **18.18.2 or later** (`node --version`) * npm (bundled with Node.js) ## Install [#install] ```bash npm install -g @alternatefutures/acc ``` Verify the installation: ```bash acc --version acc --help ``` The CLI was renamed from `af` to `acc` in 2026. If you have the old `@alternatefutures/cli` package installed, remove it with `npm uninstall -g @alternatefutures/cli` to avoid confusion - the old `af` binary no longer matches the current platform. ## Authenticate [#authenticate] ```bash acc login # browser flow: approves this CLI session from the web app acc login --email # email code flow, no browser needed ``` Confirm you are logged in: ```bash acc whoami ``` ## Non-interactive use (CI, agents) [#non-interactive-use-ci-agents] Create a personal access token and export it instead of logging in: ```bash acc pat create --name ci-runner export AF_TOKEN= export AF_PROJECT_ID= acc whoami --json ``` ## Updating [#updating] ```bash npm update -g @alternatefutures/acc ``` ## Troubleshooting [#troubleshooting] * `command not found: acc` - your global npm bin directory is not on `PATH`. Run `npm bin -g` and add that directory to your shell profile. * Login loops or auth errors - run `acc logout` then `acc login` again; check `acc whoami` afterwards. * Corporate proxies - the CLI talks HTTPS to `alternatefutures.ai` hosts; make sure they are reachable.