diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml index 2a3b7b22780..1aa5c129479 100644 --- a/.github/workflows/production.yml +++ b/.github/workflows/production.yml @@ -6,31 +6,44 @@ on: workflow_dispatch: env: + ENVIRONMENT: production + PROJECT: website + DECLARATIVE_OWNER: appwrite-labs + DECLARATIVE_REPOSITORY: assets-applications + REGISTRY_GITHUB: ghcr.io + REGISTRY_DOCKERHUB: docker.io + IMAGE_NAME: appwrite/website TAG: ${{ github.event.release.tag_name || github.sha }} - STACK_FILE: docker/production.yml - REPOSITORY: website - REGISTRY_USERNAME: christyjacob4 jobs: build: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4.3.1 - - name: Login to DockerHub - uses: docker/login-action@v3 + - name: Login to GitHub Container Registry + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: - registry: ghcr.io + registry: ${{ env.REGISTRY_GITHUB }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} + - name: Login to Docker Hub + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + with: + registry: ${{ env.REGISTRY_DOCKERHUB }} + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and push - uses: docker/build-push-action@v6 + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: context: . push: true - tags: ghcr.io/appwrite/website:${{ env.TAG }} + tags: | + ${{ env.REGISTRY_GITHUB }}/${{ env.IMAGE_NAME }}:${{ env.TAG }} + ${{ env.REGISTRY_DOCKERHUB }}/${{ env.IMAGE_NAME }}:${{ env.TAG }} build-args: | "PUBLIC_APPWRITE_ENDPOINT=${{ vars.PUBLIC_APPWRITE_ENDPOINT }}" "PUBLIC_APPWRITE_DASHBOARD=${{ vars.PUBLIC_APPWRITE_DASHBOARD }}" @@ -49,49 +62,40 @@ jobs: "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" "SENTRY_RELEASE=${{ github.event.release.tag_name }}" - deploy_kubernetes: + deploy: if: github.event_name != 'release' || !contains(github.event.release.tag_name, '-rc') - strategy: - matrix: - region: [{ full: fra1, short: fra }] needs: build runs-on: ubuntu-latest + concurrency: + group: declarative-deploy-website + cancel-in-progress: false steps: - - name: Checkout the repo - uses: actions/checkout@v4 - - name: Install Kubectl - uses: azure/setup-kubectl@v4 - - name: Install Helm - uses: azure/setup-helm@v4 - - name: Install doctl - uses: digitalocean/action-doctl@v2 + - name: Get token for ${{ env.DECLARATIVE_REPOSITORY }} + id: app-token + uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2 with: - token: ${{ secrets.DIGITALOCEAN_ACCESS_TOKEN }} - - name: Save DigitalOcean kubeconfig with short-lived credentials - run: doctl kubernetes cluster kubeconfig save --expiry-seconds 600 assets-${{ matrix.region.full }}-prod - - - name: Ensure namespaces exist - run: | - kubectl create namespace website --dry-run=client -o yaml | kubectl apply -f - + app-id: ${{ vars.DECLARATIVE_DEPLOYMENT_GITHUB_APP_ID }} + private-key: ${{ secrets.DECLARATIVE_DEPLOYMENT_GITHUB_APP_PRIVATE_KEY }} + owner: ${{ env.DECLARATIVE_OWNER }} + repositories: ${{ env.DECLARATIVE_REPOSITORY }} - - name: Create docker pull secret - run: | - kubectl -n website create secret docker-registry ghcr \ - --docker-server=ghcr.io \ - --docker-username=${{ secrets.GHCR_USERNAME }} \ - --docker-password=${{ secrets.GHCR_TOKEN }} \ - --docker-email=ci@appwrite.io \ - --dry-run=client -o yaml | kubectl apply -f - + - name: Checkout ${{ env.DECLARATIVE_REPOSITORY }} + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 + with: + repository: ${{ env.DECLARATIVE_OWNER }}/${{ env.DECLARATIVE_REPOSITORY }} + token: ${{ steps.app-token.outputs.token }} - - name: Create app secrets - run: | - kubectl -n website create secret generic website-secrets \ - --from-literal=STATSIG_SERVER_SECRET='${{ secrets.STATSIG_SERVER_SECRET }}' \ - --dry-run=client -o yaml | kubectl apply -f - + - name: Update image tag + run: yq -i '.global.image.tag = strenv(TAG)' ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml - - name: Deploy + - name: Commit and push run: | - helm upgrade --install --namespace website website deploy/website/ \ - --values deploy/website/environments/production/${{ matrix.region.full }}.values.yaml \ - --set imagePullSecret='ghcr' \ - --set version=${{ env.TAG }} + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml + if git diff --cached --quiet; then + echo "No changes to commit" + else + git commit -m "chore(${{ env.ENVIRONMENT }}): ${{ env.PROJECT }} image tag to ${{ env.TAG }}" + git push + fi diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml index a581c48fbf5..9a6ba173d2a 100644 --- a/.github/workflows/staging.yml +++ b/.github/workflows/staging.yml @@ -25,24 +25,24 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout the repo - uses: actions/checkout@v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 - name: Login to GitHub Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: ${{ env.REGISTRY_GITHUB }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Login to Docker Hub - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: ${{ env.REGISTRY_DOCKERHUB }} username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Build and push - uses: docker/build-push-action@v6 + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: context: . push: true @@ -69,10 +69,13 @@ jobs: deploy: needs: build runs-on: ubuntu-latest + concurrency: + group: declarative-deploy-website + cancel-in-progress: false steps: - name: Get token for ${{ env.DECLARATIVE_REPOSITORY }} id: app-token - uses: actions/create-github-app-token@v2 + uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2.2.2 with: app-id: ${{ vars.DECLARATIVE_DEPLOYMENT_GITHUB_APP_ID }} private-key: ${{ secrets.DECLARATIVE_DEPLOYMENT_GITHUB_APP_PRIVATE_KEY }} @@ -80,19 +83,19 @@ jobs: repositories: ${{ env.DECLARATIVE_REPOSITORY }} - name: Checkout ${{ env.DECLARATIVE_REPOSITORY }} - uses: actions/checkout@v6 + uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 with: repository: ${{ env.DECLARATIVE_OWNER }}/${{ env.DECLARATIVE_REPOSITORY }} token: ${{ steps.app-token.outputs.token }} - name: Update image tag - run: yq -i '.website.image.tag = strenv(TAG)' ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/fra1.yaml + run: yq -i '.global.image.tag = strenv(TAG)' ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml - name: Commit and push run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git add ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/fra1.yaml + git add ${{ env.ENVIRONMENT }}/${{ env.PROJECT }}/default.yaml if git diff --cached --quiet; then echo "No changes to commit" else diff --git a/.optimize-cache.json b/.optimize-cache.json index f926af4a597..bbc57f5e6c4 100644 --- a/.optimize-cache.json +++ b/.optimize-cache.json @@ -202,6 +202,7 @@ "static/images/blog/announcing-appwrite-pro/credits.png": "285905e1fd8b8282cb45a4f2259debd851812c23665145d865e141f5133c0be0", "static/images/blog/announcing-appwrite-pro/header.png": "ab709ff45870607ec4472bd4dc9e4a028e320bbfb89009ec04c98ec69248a15a", "static/images/blog/announcing-appwrite-pro/pro.png": "01427f30610de4d6d19cd9160154d8849ffa75da04d063d12bf3e9bba481b4e7", + "static/images/blog/announcing-appwrite-react-library/cover.png": "db2536faba9c82ad441662e10bf69375c8f6d1716e151324e37b0a5bbca9ee48", "static/images/blog/announcing-appwrite-rust-sdk/cover.png": "b5b69e19f4fc1ac5eb985016c1b058bb9ed308680197f315f3b9b861f3377310", "static/images/blog/announcing-atomic-numeric-operations/cover.png": "9fbe339856b8040eb49fb01ca4353b5600609962ab8044dcfc34ffbe0e8a9738", "static/images/blog/announcing-auto-increment-support/cover.png": "83a7b1dd0e31ae86e49fa873cde0b6c0319a552b27dc447b4a214efd7f3fd534", @@ -258,6 +259,7 @@ "static/images/blog/apply-appwrite-how/cover.png": "d23f45ced245b42c8712c021f5d2068c17aebd94fd049cb90222cb9647a41a4a", "static/images/blog/appwrite-1-8-0-self-hosted-release/cover.png": "c15a9d88ccd16c2dc8333dc74e715e1f4a6c7818d3b4a05f4d68342eacdc0523", "static/images/blog/appwrite-1-8-1-self-hosted-release/cover.png": "82f0a396c56b6b299b24133079acc6a317c66b2bf02fd91f4862bd3be0f8f373", + "static/images/blog/appwrite-1-9-5-self-hosted-release/cover.png": "f5958ba97aa507888c54c11ba156bf8a4e0643d129ed900ef1c83915efa31e88", "static/images/blog/appwrite-1.5-now-available-on-cloud/cloud15.png": "a1df7388572a9f08d0e315e4b6bc8c9464c1418768e7efbec22758fd728eb970", "static/images/blog/appwrite-auth-methods/cover.png": "361513d8b59de8fde7b294dcc6688aada30c46e11933070c529733e486784690", "static/images/blog/appwrite-backups-and-restores/cover.png": "369b5d91f3dc515e7fb86588f8871aa5ffd788b40023e8373ac694840479c1ab", @@ -479,8 +481,10 @@ "static/images/blog/claude-code-tips-tricks/cover.png": "df329d51541267d46b2b913c376cca27c7ddf12b6a2a36986d418ec41253ddc9", "static/images/blog/claude-design/cover.png": "7530f6d1c1a999089f2a68038d6a17d9953435afb1535d09b462b485f77ce1df", "static/images/blog/claude-fable-5-and-mythos-5-access-suspended/cover.avif": "f6c50bbd5f1eaabef50803b5b76792f8f5f7a2fb009ed8670a08cd9ad1f23971", + "static/images/blog/claude-fable-5-returns-with-stronger-jailbreak-safeguards/cover.png": "bfe441fb7c04a21cb431119065ae05f2c1b044d9885cba7ef3651290f2ff3bb3", "static/images/blog/claude-mythos-preview/cover.png": "aea7b0c45c492939048fbf04a9b001b96c7bf727bcf7e5afc8274f84644dd35d", "static/images/blog/claude-mythos-release-date-what-we-know-so-far/cover.png": "0197caa87f00bc03063fb2b1872052cf02733298b2991871852762f32fcfa202", + "static/images/blog/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/cover.png": "15a3350966c037f6747c4b3626e9770ba4ee8065439702903ee3cde13a4573e2", "static/images/blog/claude-vs-gpt-vs-gemini-for-developers-who-wins-in-2026/cover.png": "b931411d483646bcc79649dfc518e86fa4768504b13dbd3d03885c9a2bbde531", "static/images/blog/client-dashboards-internal-tools/cover.png": "d758f2f517487e24037cef5b3e9036ade6c238cd2f216ef6c76ce5467c665d92", "static/images/blog/client-vs-server-components-react/cover.png": "b7ae8b7614902c8b4dd7826d59cfdb36db9abbe27bde99b3deb69c4bf178f425", @@ -1257,10 +1261,12 @@ "static/images/blog/what-is-an-ai-backend/cover.png": "cb36f49035cbdcd97a70ac658783741f275d3a220b7cfd16b39d4fb86a929edd", "static/images/blog/what-is-cdn/cover.png": "ef77860288e150c6c22f3950a5eae4c88aefefb6db204f10c2a0544e51548703", "static/images/blog/what-is-ciam/cover.png": "45a5261ae1bb8a38777f60a21ea60426c0832e3d58bf3164100548400d388ce1", + "static/images/blog/what-is-cicd-a-complete-guide-for-developers/cover.png": "7abddce55b1467188faab83abd58189173bf9aba84de3d9f28fff0be8c6e9276", "static/images/blog/what-is-docker-a-simple-guide-for-developers/cover.png": "acd9c50ad749fcf676dd58b38cc6bbffba913bf5d817c6b725bd2c305088689e", "static/images/blog/what-is-mcp/claude-mcp-chat.png": "26842cfebca3ec2cec89448e1c0d7ddb3f5421cc57acdb8780d48d30a54cad82", "static/images/blog/what-is-mcp/claude-mcp-tools.png": "3a5ae700867b8671b5c9e3af61b094aeb64611168463db66ff440e0d427ac6bc", "static/images/blog/what-is-mcp/cover.png": "dc4537990c91d6f1768c5ab8775e5c52239eb901b15e2e74fce8b5a018855c32", + "static/images/blog/what-is-redis-a-complete-guide-for-developers/cover.png": "b7b87a372bbb99421c2ab6df37430da960728b5cf339f1803c432644154c764f", "static/images/blog/when-custom-backend-stops-being-worth-it/cover.png": "d03b13c4e8f3294823a7883cdae89ca18a4030b170c51f597bd139c9ca274793", "static/images/blog/why-ai-generated-apps-need-backend/cover.png": "8761878c13c51dd8a720a625606b89b93d9c56651aed636fa1b2bd346bd4fd82", "static/images/blog/why-developers-choose-appwrite-auth/cover.png": "f56c37ebfc25191e113b928ff3cf144563be740159e46d75a427bdafdd11214b", diff --git a/CONTENT.md b/CONTENT.md index 0886ecd9dfb..91519c1361f 100644 --- a/CONTENT.md +++ b/CONTENT.md @@ -193,7 +193,7 @@ Remember to use a specific language label if the code is using an Appwrite SDK. ### Sections -Use sections when there is a clear step-by-step format to a page. This is used mainly in journey pages and tutorials. +Use sections when there is a clear step-by-step format to a page. This is used mainly in guide pages and tutorials. ```md {% section #featured-products-1 step=1 title="Title" %} diff --git a/STYLE.md b/STYLE.md index ece9cd70832..f5931914fd6 100644 --- a/STYLE.md +++ b/STYLE.md @@ -48,6 +48,11 @@ APIs section: - [GraphQL](https://appwrite.io/docs/apis/graphql) - [REST](https://appwrite.io/docs/apis/rest) - [Realtime](https://appwrite.io/docs/apis/realtime) +- [Events](https://appwrite.io/docs/apis/events) +- [Webhooks](https://appwrite.io/docs/apis/webhooks) +- [Response codes](https://appwrite.io/docs/apis/response-codes) +- [Release policy](https://appwrite.io/docs/apis/release-policy) +- [Error handling](https://appwrite.io/docs/apis/error-handling) Tooling section: @@ -57,7 +62,7 @@ Tooling section: Advanced section: -- [Platform](https://appwrite.io/docs/advanced/platform) +- [Billing](https://appwrite.io/docs/advanced/billing) - [Migrations](https://appwrite.io/docs/advanced/migrations) - [Self-hosting](https://appwrite.io/docs/advanced/self-hosting) - [Security](https://appwrite.io/docs/advanced/security) @@ -89,7 +94,7 @@ Each product page has three main sections - These pages usually align with sections shown in the product in the Appwrite Console. - Focused on describing concepts a user should know, but not actions you might take. - Cover all the details -- Journeys +- Guides - These pages focus on common actions and work flows - Detailed examples that span many concepts - Like cookbook at other organizations' documentation. @@ -214,10 +219,10 @@ Split content such that each piece makes sense without reading dependents or exp - [ ] Point Cloud to new version in [src/routes/docs/references/[version]/[platform]/[service]/+page.server.ts](src/routes/docs/references/[version]/[platform]/[service]/+page.server.ts) - [ ] Update install command in [/workspaces/website/src/routes/docs/advanced/self-hosting/+page.markdoc](/workspaces/website/src/routes/docs/advanced/self-hosting/+page.markdoc) - [ ] Update events [src/partials/[product]-events.md](src/partials/) -- [ ] Update response code [src/routes/docs/advanced/platform/response-codes/+page.markdoc](src/routes/docs/advanced/platform/response-codes/+page.markdoc) +- [ ] Update response code [src/routes/docs/apis/response-codes/+page.markdoc](src/routes/docs/apis/response-codes/+page.markdoc) - [ ] Bump latest SDK versions in SDKs page, quick start, and tutorials - [ ] Create new sections for new products -- [ ] Create new concept and journey pages for new features +- [ ] Create new concept and guide pages for new features - [ ] Update docs for breaking changes ### Documenting a new API @@ -346,7 +351,7 @@ easily, and the code example is expected to be runnable and complete. This means, you need to include imports, dependencies, and all parts needed to arrive at a functional example. -For concept and journey product pages, still try your best to have complete examples, unless: +For concept and guide product pages, still try your best to have complete examples, unless: 1. The example will become opinionated. We avoid opinionated implementation and choices in product pages. Keep them in blogs, quick starts, and tutorials. 2. The example cannot be given in a complete form cleanly. For example, many of the Messaging services's examples cannot be given in complete form because the boiler plate and set up is complex and documented in Android/Swift documentation. diff --git a/src/lib/components/compose-generator/composeData.ts b/src/lib/components/compose-generator/composeData.ts index ba23c21d4f4..7f54af998be 100644 --- a/src/lib/components/compose-generator/composeData.ts +++ b/src/lib/components/compose-generator/composeData.ts @@ -146,7 +146,7 @@ services: - appwrite appwrite: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 container_name: appwrite <<: *x-logging restart: unless-stopped @@ -290,7 +290,7 @@ services: appwrite-console: <<: *x-logging container_name: appwrite-console - image: appwrite/console:7.8.26 + image: appwrite/console:8.7.5 restart: unless-stopped networks: - appwrite @@ -310,7 +310,7 @@ services: - traefik.http.routers.appwrite_console_https.tls=true appwrite-realtime: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: realtime container_name: appwrite-realtime <<: *x-logging @@ -356,7 +356,7 @@ services: - _APP_LOGGING_CONFIG appwrite-worker-audits: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-audits <<: *x-logging container_name: appwrite-worker-audits @@ -385,7 +385,7 @@ services: - _APP_LOGGING_CONFIG appwrite-worker-webhooks: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-webhooks <<: *x-logging container_name: appwrite-worker-webhooks @@ -416,7 +416,7 @@ services: - _APP_LOGGING_CONFIG appwrite-worker-deletes: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-deletes <<: *x-logging container_name: appwrite-worker-deletes @@ -482,7 +482,7 @@ services: - _APP_EMAIL_CERTIFICATES appwrite-worker-databases: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-databases <<: *x-logging container_name: appwrite-worker-databases @@ -511,7 +511,7 @@ services: - _APP_LOGGING_CONFIG appwrite-worker-builds: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-builds <<: *x-logging container_name: appwrite-worker-builds @@ -554,6 +554,7 @@ services: - _APP_COMPUTE_CPUS - _APP_COMPUTE_MEMORY - _APP_COMPUTE_SIZE_LIMIT + - _APP_OPEN_RUNTIMES_NFT - _APP_OPTIONS_FORCE_HTTPS - _APP_OPTIONS_ROUTER_FORCE_HTTPS - _APP_DOMAIN @@ -581,8 +582,63 @@ services: - _APP_STORAGE_WASABI_BUCKET - _APP_DOMAIN_SITES + appwrite-worker-screenshots: + image: appwrite/appwrite:1.9.5 + entrypoint: worker-screenshots + <<: *x-logging + container_name: appwrite-worker-screenshots + restart: unless-stopped + networks: + - appwrite + volumes: + - appwrite-uploads:/storage/uploads:rw + depends_on: + redis: + condition: service_healthy + __DB_SERVICE__: + condition: service_healthy + environment: + - _APP_ENV + - _APP_WORKER_PER_CORE + - _APP_OPENSSL_KEY_V1 + - _APP_BROWSER_HOST + - _APP_OPTIONS_FORCE_HTTPS + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS + - _APP_DB_ADAPTER + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + - _APP_LOGGING_CONFIG + - _APP_STORAGE_DEVICE + - _APP_STORAGE_S3_ACCESS_KEY + - _APP_STORAGE_S3_SECRET + - _APP_STORAGE_S3_REGION + - _APP_STORAGE_S3_BUCKET + - _APP_STORAGE_S3_ENDPOINT + - _APP_STORAGE_DO_SPACES_ACCESS_KEY + - _APP_STORAGE_DO_SPACES_SECRET + - _APP_STORAGE_DO_SPACES_REGION + - _APP_STORAGE_DO_SPACES_BUCKET + - _APP_STORAGE_BACKBLAZE_ACCESS_KEY + - _APP_STORAGE_BACKBLAZE_SECRET + - _APP_STORAGE_BACKBLAZE_REGION + - _APP_STORAGE_BACKBLAZE_BUCKET + - _APP_STORAGE_LINODE_ACCESS_KEY + - _APP_STORAGE_LINODE_SECRET + - _APP_STORAGE_LINODE_REGION + - _APP_STORAGE_LINODE_BUCKET + - _APP_STORAGE_WASABI_ACCESS_KEY + - _APP_STORAGE_WASABI_SECRET + - _APP_STORAGE_WASABI_REGION + - _APP_STORAGE_WASABI_BUCKET + appwrite-worker-certificates: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-certificates <<: *x-logging container_name: appwrite-worker-certificates @@ -621,8 +677,36 @@ services: - _APP_DB_PASS - _APP_LOGGING_CONFIG + appwrite-worker-executions: + image: appwrite/appwrite:1.9.5 + entrypoint: worker-executions + <<: *x-logging + container_name: appwrite-worker-executions + restart: unless-stopped + networks: + - appwrite + depends_on: + redis: + condition: service_healthy + __DB_SERVICE__: + condition: service_healthy + environment: + - _APP_ENV + - _APP_WORKER_PER_CORE + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS + - _APP_DB_ADAPTER + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + - _APP_LOGGING_CONFIG + appwrite-worker-functions: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-functions <<: *x-logging container_name: appwrite-worker-functions @@ -665,7 +749,7 @@ services: - _APP_LOGGING_CONFIG appwrite-worker-mails: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-mails <<: *x-logging container_name: appwrite-worker-mails @@ -703,7 +787,7 @@ services: - _APP_OPTIONS_FORCE_HTTPS appwrite-worker-messaging: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-messaging <<: *x-logging container_name: appwrite-worker-messaging @@ -758,7 +842,7 @@ services: - _APP_STORAGE_WASABI_BUCKET appwrite-worker-migrations: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-migrations <<: *x-logging container_name: appwrite-worker-migrations @@ -796,7 +880,7 @@ services: - _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET appwrite-task-maintenance: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: maintenance <<: *x-logging container_name: appwrite-task-maintenance @@ -838,8 +922,45 @@ services: - _APP_MAINTENANCE_RETENTION_USAGE_HOURLY - _APP_MAINTENANCE_RETENTION_SCHEDULES + appwrite-task-interval: + image: appwrite/appwrite:1.9.5 + entrypoint: interval + <<: *x-logging + container_name: appwrite-task-interval + restart: unless-stopped + networks: + - appwrite + depends_on: + __DB_SERVICE__: + condition: service_healthy + redis: + condition: service_healthy + environment: + - _APP_ENV + - _APP_WORKER_PER_CORE + - _APP_OPENSSL_KEY_V1 + - _APP_DOMAIN + - _APP_DOMAIN_TARGET_CNAME + - _APP_DOMAIN_TARGET_AAAA + - _APP_DOMAIN_TARGET_A + - _APP_DOMAIN_TARGET_CAA + - _APP_DNS + - _APP_DOMAIN_FUNCTIONS + - _APP_DOMAIN_SITES + - _APP_REDIS_HOST + - _APP_REDIS_PORT + - _APP_REDIS_USER + - _APP_REDIS_PASS + - _APP_DB_ADAPTER + - _APP_DB_HOST + - _APP_DB_PORT + - _APP_DB_SCHEMA + - _APP_DB_USER + - _APP_DB_PASS + - _APP_LOGGING_CONFIG + appwrite-task-stats-resources: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 container_name: appwrite-task-stats-resources entrypoint: stats-resources <<: *x-logging @@ -871,7 +992,7 @@ services: - _APP_STATS_RESOURCES_INTERVAL appwrite-worker-stats-resources: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-stats-resources container_name: appwrite-worker-stats-resources <<: *x-logging @@ -902,7 +1023,7 @@ services: - _APP_STATS_RESOURCES_INTERVAL appwrite-worker-stats-usage: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: worker-stats-usage container_name: appwrite-worker-stats-usage <<: *x-logging @@ -933,7 +1054,7 @@ services: - _APP_USAGE_AGGREGATION_INTERVAL appwrite-task-scheduler-functions: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: schedule-functions container_name: appwrite-task-scheduler-functions <<: *x-logging @@ -949,6 +1070,7 @@ services: - _APP_ENV - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 + - _APP_MIGRATION_HOST - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -961,7 +1083,7 @@ services: - _APP_DB_PASS appwrite-task-scheduler-executions: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: schedule-executions container_name: appwrite-task-scheduler-executions <<: *x-logging @@ -977,6 +1099,7 @@ services: - _APP_ENV - _APP_WORKER_PER_CORE - _APP_OPENSSL_KEY_V1 + - _APP_MIGRATION_HOST - _APP_REDIS_HOST - _APP_REDIS_PORT - _APP_REDIS_USER @@ -989,7 +1112,7 @@ services: - _APP_DB_PASS appwrite-task-scheduler-messages: - image: appwrite/appwrite:1.9.0 + image: appwrite/appwrite:1.9.5 entrypoint: schedule-messages container_name: appwrite-task-scheduler-messages <<: *x-logging @@ -1026,12 +1149,12 @@ __ASSISTANT_BLOCK__ - appwrite openruntimes-executor: - container_name: openruntimes-executor + container_name: exc1 hostname: exc1 <<: *x-logging restart: unless-stopped stop_signal: SIGINT - image: openruntimes/executor:0.7.22 + image: openruntimes/executor:0.25.1 networks: - appwrite - runtimes @@ -1053,6 +1176,7 @@ __ASSISTANT_BLOCK__ - OPR_EXECUTOR_RUNTIMES=$_APP_FUNCTIONS_RUNTIMES,$_APP_SITES_RUNTIMES - OPR_EXECUTOR_SECRET=$_APP_EXECUTOR_SECRET - OPR_EXECUTOR_RUNTIME_VERSIONS=v5 + - OPEN_RUNTIMES_NFT=$_APP_OPEN_RUNTIMES_NFT - OPR_EXECUTOR_LOGGING_CONFIG=$_APP_LOGGING_CONFIG - OPR_EXECUTOR_STORAGE_DEVICE=$_APP_STORAGE_DEVICE - OPR_EXECUTOR_STORAGE_S3_ACCESS_KEY=$_APP_STORAGE_S3_ACCESS_KEY @@ -1240,6 +1364,7 @@ _APP_EXECUTOR_RUNTIME_NETWORK=appwrite_runtimes _APP_FUNCTIONS_ENVS=node-16.0,php-7.4,python-3.9,ruby-3.0 _APP_FUNCTIONS_INACTIVE_THRESHOLD=60 _APP_COMPUTE_INACTIVE_THRESHOLD=60 +_APP_OPEN_RUNTIMES_NFT=enabled DOCKERHUB_PULL_USERNAME= DOCKERHUB_PULL_PASSWORD= DOCKERHUB_PULL_EMAIL= @@ -1272,6 +1397,7 @@ _APP_GRAPHQL_INTROSPECTION=enabled _APP_GRAPHQL_MAX_BATCH_SIZE=10 _APP_GRAPHQL_MAX_COMPLEXITY=250 _APP_GRAPHQL_MAX_DEPTH=3 +_APP_MIGRATION_HOST=appwrite _APP_MIGRATIONS_FIREBASE_CLIENT_ID= _APP_MIGRATIONS_FIREBASE_CLIENT_SECRET= _APP_ASSISTANT_OPENAI_API_KEY=__ASSISTANT_KEY__ diff --git a/src/partials/account-vs-user.md b/src/partials/account-vs-user.md index 4a7c3949bbf..c189d9f8f85 100644 --- a/src/partials/account-vs-user.md +++ b/src/partials/account-vs-user.md @@ -1,7 +1,7 @@ {% info title="Account vs Users API" %} The Account API is the API you should use in your **client applications** with [Client SDKs](/docs/sdks#client) like web, Flutter, mobile, and native apps. Account API creates sessions, which represent an authenticated user and is attached to a user's [account](/docs/products/auth/accounts). -Sessions respect [permissions](/docs/advanced/platform/permissions), which means users can only access resources if they have been granted the correct permissions. +Sessions respect [permissions](/docs/advanced/security/permissions), which means users can only access resources if they have been granted the correct permissions. The Users API is a dedicated API for managing users from an admin's perspective. It should be used with backend or server-side applications with [Server SDKs](/docs/sdks#server). Users API uses API keys instead of sessions. diff --git a/src/partials/auth-security.md b/src/partials/auth-security.md index ea744e1fc32..bd1eb8c5a0f 100644 --- a/src/partials/auth-security.md +++ b/src/partials/auth-security.md @@ -22,7 +22,7 @@ You can change the session limit in the **Security** tab of the Auth Service in # Permissions {% #permissions %} Security is very important to protect users' data and privacy. -Appwrite uses a [permissions model](/docs/advanced/platform/permissions) coupled with user sessions to ensure users need correct permissions to access resources. +Appwrite uses a [permissions model](/docs/advanced/security/permissions) coupled with user sessions to ensure users need correct permissions to access resources. With all Appwrite services, including databases and storage, access is granted at the collection, bucket, document, or file level. These permissions are enforced for client SDKs and server SDKs when using JWT, but are ignored when using a server SDK with an API key. @@ -45,7 +45,7 @@ Password history can be enabled in the Auth service's **Security** tab on the Ap # Password dictionary {% #password-dictionary %} -Password dictionary protects users from using bad passwords. It compares the user's password to the [10,000 most common passwords](https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/10k-most-common.txt) and throws an error if there's a match. Together with [rate limits](/docs/advanced/platform/rate-limits), password dictionary will significantly reduce the chance of a malicious actor guessing user passwords. +Password dictionary protects users from using bad passwords. It compares the user's password to the [10,000 most common passwords](https://github.com/danielmiessler/SecLists/blob/master/Passwords/Common-Credentials/10k-most-common.txt) and throws an error if there's a match. Together with [rate limits](/docs/advanced/security/rate-limits), password dictionary will significantly reduce the chance of a malicious actor guessing user passwords. Password dictionary can be enabled in the Auth service's **Security** tab on the Appwrite Console. diff --git a/src/partials/functions-env-vars.md b/src/partials/functions-env-vars.md index 1c5bcde396a..bfd57444145 100644 --- a/src/partials/functions-env-vars.md +++ b/src/partials/functions-env-vars.md @@ -1,14 +1,29 @@ -| Variable | Description | Available at Build and/or Run Time | -| ----------------------------------- | ---------------------------------------------------------- | ---------------------------------- | -| `APPWRITE_FUNCTION_API_ENDPOINT` | The API endpoint of the running function | Both | -| `APPWRITE_VERSION` | The Appwrite version used to run the function | Both | -| `APPWRITE_REGION` | The region where the function will run from | Both | -| `APPWRITE_FUNCTION_API_KEY` | The function API key used for server authentication | Build time | -| `APPWRITE_FUNCTION_ID` | The ID of the running function | Both | -| `APPWRITE_FUNCTION_NAME` | The name of the running function | Both | -| `APPWRITE_FUNCTION_DEPLOYMENT` | The deployment ID of the running function | Both | -| `APPWRITE_FUNCTION_PROJECT_ID` | The project ID of the running function | Both | -| `APPWRITE_FUNCTION_RUNTIME_NAME` | The runtime of the running function | Both | -| `APPWRITE_FUNCTION_RUNTIME_VERSION` | The runtime version of the running function | Both | -| `APPWRITE_FUNCTION_CPUS` | The CPU (runtime) specification of the running function | Both | -| `APPWRITE_FUNCTION_MEMORY` | The memory (runtime) specification of the running function | Both | +| Variable | Description | Available at Build and/or Run Time | +| ------------------------------------ | ------------------------------------------------------------- | ---------------------------------- | +| `APPWRITE_FUNCTION_API_ENDPOINT` | The API endpoint of the running function | Both | +| `APPWRITE_VERSION` | The Appwrite version used to run the function | Both | +| `APPWRITE_REGION` | The region where the function will run from | Both | +| `APPWRITE_DEPLOYMENT_TYPE` | The deployment source type, such as `manual`, `cli`, or `vcs` | Both | +| `APPWRITE_FUNCTION_API_KEY` | The function API key used for server authentication | Build time | +| `APPWRITE_FUNCTION_ID` | The ID of the running function | Both | +| `APPWRITE_FUNCTION_NAME` | The name of the running function | Both | +| `APPWRITE_FUNCTION_DEPLOYMENT` | The deployment ID of the running function | Both | +| `APPWRITE_FUNCTION_PROJECT_ID` | The project ID of the running function | Both | +| `APPWRITE_FUNCTION_RUNTIME_NAME` | The runtime of the running function | Both | +| `APPWRITE_FUNCTION_RUNTIME_VERSION` | The runtime version of the running function | Both | +| `APPWRITE_FUNCTION_CPUS` | The CPU (runtime) specification of the running function | Both | +| `APPWRITE_FUNCTION_MEMORY` | The memory (runtime) specification of the running function | Both | +| `APPWRITE_VCS_REPOSITORY_ID` | The provider repository ID for VCS deployments | Both | +| `APPWRITE_VCS_REPOSITORY_NAME` | The provider repository name for VCS deployments | Both | +| `APPWRITE_VCS_REPOSITORY_OWNER` | The owner of the provider repository | Both | +| `APPWRITE_VCS_REPOSITORY_URL` | The URL of the provider repository | Both | +| `APPWRITE_VCS_REPOSITORY_BRANCH` | The branch used for the VCS deployment | Both | +| `APPWRITE_VCS_REPOSITORY_BRANCH_URL` | The URL of the branch used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_HASH` | The commit hash used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_MESSAGE` | The commit message used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_URL` | The URL of the commit used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_AUTHOR_NAME` | The name of the VCS commit author | Both | +| `APPWRITE_VCS_COMMIT_AUTHOR_URL` | The URL of the VCS commit author | Both | +| `APPWRITE_VCS_ROOT_DIRECTORY` | The root directory configured for the VCS deployment | Both | + +VCS metadata variables are populated for Git deployments. For manual and CLI deployments, VCS fields may be empty. diff --git a/src/partials/sites-env-vars.md b/src/partials/sites-env-vars.md index 906c9f246ae..936da5d21ef 100644 --- a/src/partials/sites-env-vars.md +++ b/src/partials/sites-env-vars.md @@ -1,10 +1,29 @@ -| Variable | Description | Available at Build and/or Run Time | -| ------------------------------- | ------------------------------------------------------- | ---------------------------------- | -| `APPWRITE_SITE_API_ENDPOINT` | The API endpoint of the running site | Both | -| `APPWRITE_SITE_NAME` | The name of the running site. | Both | -| `APPWRITE_SITE_DEPLOYMENT` | The deployment ID of the running sites. | Both | -| `APPWRITE_SITE_PROJECT_ID` | The project ID of the running site. | Both | -| `APPWRITE_SITE_RUNTIME_NAME` | The runtime name of the running site. | Both | -| `APPWRITE_SITE_RUNTIME_VERSION` | The runtime version of the running site. | Both | -| `APPWRITE_SITE_CPUS` | The CPU (runtime) specification of the running site. | Both | -| `APPWRITE_SITE_MEMORY` | The memory (runtime) specification of the running site. | Both | +| Variable | Description | Available at Build and/or Run Time | +| ------------------------------------ | ------------------------------------------------------------- | ---------------------------------- | +| `APPWRITE_SITE_API_ENDPOINT` | The API endpoint of the running site | Both | +| `APPWRITE_VERSION` | The Appwrite version used to run the site | Both | +| `APPWRITE_REGION` | The region where the site will run from | Both | +| `APPWRITE_DEPLOYMENT_TYPE` | The deployment source type, such as `manual`, `cli`, or `vcs` | Both | +| `APPWRITE_SITE_API_KEY` | The site API key used for server authentication | Build time | +| `APPWRITE_SITE_ID` | The ID of the running site | Both | +| `APPWRITE_SITE_NAME` | The name of the running site | Both | +| `APPWRITE_SITE_DEPLOYMENT` | The deployment ID of the running site | Both | +| `APPWRITE_SITE_PROJECT_ID` | The project ID of the running site | Both | +| `APPWRITE_SITE_RUNTIME_NAME` | The runtime name of the running site | Both | +| `APPWRITE_SITE_RUNTIME_VERSION` | The runtime version of the running site | Both | +| `APPWRITE_SITE_CPUS` | The CPU (runtime) specification of the running site | Both | +| `APPWRITE_SITE_MEMORY` | The memory (runtime) specification of the running site | Both | +| `APPWRITE_VCS_REPOSITORY_ID` | The provider repository ID for VCS deployments | Both | +| `APPWRITE_VCS_REPOSITORY_NAME` | The provider repository name for VCS deployments | Both | +| `APPWRITE_VCS_REPOSITORY_OWNER` | The owner of the provider repository | Both | +| `APPWRITE_VCS_REPOSITORY_URL` | The URL of the provider repository | Both | +| `APPWRITE_VCS_REPOSITORY_BRANCH` | The branch used for the VCS deployment | Both | +| `APPWRITE_VCS_REPOSITORY_BRANCH_URL` | The URL of the branch used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_HASH` | The commit hash used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_MESSAGE` | The commit message used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_URL` | The URL of the commit used for the VCS deployment | Both | +| `APPWRITE_VCS_COMMIT_AUTHOR_NAME` | The name of the VCS commit author | Both | +| `APPWRITE_VCS_COMMIT_AUTHOR_URL` | The URL of the VCS commit author | Both | +| `APPWRITE_VCS_ROOT_DIRECTORY` | The root directory configured for the VCS deployment | Both | + +VCS metadata variables are populated for Git deployments. For manual and CLI deployments, VCS fields may be empty. diff --git a/src/redirects.json b/src/redirects.json index 17340a23b84..af48ad0536c 100644 --- a/src/redirects.json +++ b/src/redirects.json @@ -201,15 +201,15 @@ }, { "link": "/docs/keys", - "redirect": "/docs/advanced/platform/api-keys" + "redirect": "/docs/advanced/security/api-keys" }, { "link": "/docs/permissions", - "redirect": "/docs/advanced/platform/permissions" + "redirect": "/docs/advanced/security/permissions" }, { "link": "/docs/events", - "redirect": "/docs/advanced/platform/events" + "redirect": "/docs/apis/events" }, { "link": "/docs/queries", @@ -221,23 +221,23 @@ }, { "link": "/docs/webhooks", - "redirect": "/docs/advanced/platform/webhooks" + "redirect": "/docs/apis/webhooks" }, { "link": "/docs/custom-domains", - "redirect": "/docs/advanced/platform/custom-domains" + "redirect": "/docs/products/network/custom-domains" }, { "link": "/docs/email-and-sms-templates", - "redirect": "/docs/advanced/platform/message-templates" + "redirect": "/docs/products/auth/message-templates" }, { "link": "/docs/response-codes", - "redirect": "/docs/advanced/platform/response-codes" + "redirect": "/docs/apis/response-codes" }, { "link": "/docs/rate-limits", - "redirect": "/docs/advanced/platform/rate-limits" + "redirect": "/docs/advanced/security/rate-limits" }, { "link": "/docs/configuration", @@ -445,7 +445,7 @@ }, { "link": "/docs/permissions/", - "redirect": "/docs/advanced/platform/permissions" + "redirect": "/docs/advanced/security/permissions" }, { "link": "/docs/models/bucket", @@ -915,5 +915,133 @@ { "link": "/heroes", "redirect": "/" + }, + { + "link": "/docs/advanced/platform", + "redirect": "/docs" + }, + { + "link": "/docs/advanced/platform/billing", + "redirect": "/docs/advanced/billing/payments" + }, + { + "link": "/docs/advanced/platform/free", + "redirect": "/docs/advanced/billing/free" + }, + { + "link": "/docs/advanced/platform/pro", + "redirect": "/docs/advanced/billing/pro" + }, + { + "link": "/docs/advanced/platform/scale", + "redirect": "/docs/advanced/billing/pro" + }, + { + "link": "/docs/advanced/platform/enterprise", + "redirect": "/docs/advanced/billing/enterprise" + }, + { + "link": "/docs/advanced/platform/oss", + "redirect": "/docs/advanced/billing/oss" + }, + { + "link": "/docs/advanced/platform/compute", + "redirect": "/docs/advanced/billing/compute" + }, + { + "link": "/docs/advanced/platform/phone-otp", + "redirect": "/docs/advanced/billing/phone-otp" + }, + { + "link": "/docs/advanced/platform/image-transformations", + "redirect": "/docs/advanced/billing/image-transformations" + }, + { + "link": "/docs/advanced/platform/database-reads-and-writes", + "redirect": "/docs/advanced/billing/database-reads-and-writes" + }, + { + "link": "/docs/advanced/platform/support-sla", + "redirect": "/docs/advanced/billing/support-sla" + }, + { + "link": "/docs/advanced/platform/uptime-sla", + "redirect": "/docs/advanced/billing/uptime-sla" + }, + { + "link": "/docs/advanced/platform/fair-use-policy", + "redirect": "/docs/advanced/billing/fair-use-policy" + }, + { + "link": "/docs/advanced/platform/abuse", + "redirect": "/docs/advanced/billing/abuse" + }, + { + "link": "/docs/advanced/platform/refund-policy", + "redirect": "/docs/advanced/billing/refund-policy" + }, + { + "link": "/docs/advanced/platform/events", + "redirect": "/docs/apis/events" + }, + { + "link": "/docs/advanced/platform/webhooks", + "redirect": "/docs/apis/webhooks" + }, + { + "link": "/docs/advanced/platform/response-codes", + "redirect": "/docs/apis/response-codes" + }, + { + "link": "/docs/advanced/platform/error-handling", + "redirect": "/docs/apis/response-codes#error-handling" + }, + { + "link": "/docs/advanced/platform/release-policy", + "redirect": "/docs/apis/release-policy" + }, + { + "link": "/docs/advanced/release-policy", + "redirect": "/docs/apis/release-policy" + }, + { + "link": "/docs/advanced/platform/permissions", + "redirect": "/docs/advanced/security/permissions" + }, + { + "link": "/docs/advanced/platform/rate-limits", + "redirect": "/docs/advanced/security/rate-limits" + }, + { + "link": "/docs/advanced/platform/api-keys", + "redirect": "/docs/advanced/security/api-keys" + }, + { + "link": "/docs/advanced/platform/dev-keys", + "redirect": "/docs/advanced/security/dev-keys" + }, + { + "link": "/docs/advanced/platform/roles", + "redirect": "/docs/advanced/security/roles" + }, + { + "link": "/docs/advanced/platform/message-templates", + "redirect": "/docs/products/auth/message-templates" + }, + { + "link": "/docs/advanced/platform/custom-domains", + "redirect": "/docs/products/network/custom-domains" + }, + { + "link": "/docs/advanced/platform/shortcuts", + "redirect": "/docs/tooling/command-center/shortcuts" + }, + { + "link": "/docs/advanced/platform/environment-variables", + "redirect": "/docs/advanced/security/environment-variables" + }, + { + "link": "/docs/advanced/integration", + "redirect": "/docs/apis/rest" } ] diff --git a/src/routes/(init)/init/+page.svelte b/src/routes/(init)/init/+page.svelte index c3f5174c34e..f7d440da5c4 100644 --- a/src/routes/(init)/init/+page.svelte +++ b/src/routes/(init)/init/+page.svelte @@ -127,7 +127,7 @@ }, { title: 'Dev Keys', - url: '/docs/advanced/platform/dev-keys', + url: '/docs/advanced/security/dev-keys', type: 'Docs', label: 'Visit docs' } diff --git a/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc new file mode 100644 index 00000000000..5e869c472b6 --- /dev/null +++ b/src/routes/blog/post/announcing-appwrite-react-library/+page.markdoc @@ -0,0 +1,138 @@ +--- +layout: post +title: "Announcing the Appwrite React library" +description: A small set of React hooks and SSR adapters that take the busywork out of wiring Appwrite Auth into Vite, Next.js, and TanStack Start apps. +date: 2026-06-26 +cover: /images/blog/announcing-appwrite-react-library/cover.avif +timeToRead: 5 +author: atharva +category: announcement, authentication +faqs: + - question: 'What is an authentication library?' + answer: 'An authentication library is a package that handles the common pieces of user sign-up, sign-in, sign-out, session management, and OAuth on your behalf, so you do not have to wire each one up from scratch in every project.' + - question: 'Why use an authentication library instead of building auth yourself?' + answer: 'Auth touches sessions, cookies, password handling, OAuth callbacks, and a handful of edge cases that are easy to get subtly wrong. A library gives you a tested implementation of those pieces and a small, consistent API on top, so you spend your time on product features instead of re-implementing the same flows.' + - question: 'Which React versions are supported?' + answer: 'React 18 and React 19, on both client-rendered apps and SSR frameworks. Next.js 15+ and TanStack Start are supported out of the box.' + - question: 'Is the source code open?' + answer: 'Yes. The library lives in the [appwrite/sdk-for-react](https://github.com/appwrite/sdk-for-react) repository on GitHub under the BSD-3-Clause license, like the rest of the Appwrite SDKs.' + - question: 'Does it support magic URL, phone, or other authentication methods?' + answer: 'The current hooks cover email and password sign-in, sign-up, sign-out, and OAuth. For magic URL, phone, anonymous, or JWT flows, drop down to the Web SDK via `useAppwrite().account` and call the method directly. More dedicated hooks are planned.' + - question: 'Where do I start?' + answer: 'Pick the framework you are using: [Vite React](/docs/quick-starts/react), [Next.js](/docs/quick-starts/nextjs), or [TanStack Start](/docs/quick-starts/tanstack-start). Each quickstart walks through install, configuration, and a working sign-up flow.' +--- + +Every React developer who has wired Appwrite into a project knows the drill. You install the Web SDK, write a small `appwrite.ts` file with a `Client` and an `Account`, and then build the same `useUser` hook and sign-in form you have built for every other project. For client-only apps that is fine, but the moment SSR enters the picture (`cookies()` in Next.js, server functions in TanStack Start) you also start hand-rolling session cookies, server helpers, and the `setSession` plumbing that hydrates the client from the request. + +Today, we are releasing the [Appwrite React library](/docs/products/auth/react), an official package that gives you that whole layer out of the box. + +# The provider and hooks + +The library exposes a single `AppwriteProvider` and five auth hooks: + +- `useAuth` for the combined user, sign-in, sign-up, and sign-out surface +- `useUser` for the current authenticated user +- `useSignIn` for email/password and OAuth sign-in +- `useSignUp` for account creation +- `useSignOut` for ending the current session + +It is built on top of the existing [Appwrite Web SDK](/docs/sdks) and uses TanStack Query underneath, so cached user state stays in sync across components automatically. + +What makes it different from a hand-rolled `useUser` is what happens on the server. The library ships dedicated entrypoints for Next.js App Router and TanStack Start that handle the cookie, hydration, and admin-client wiring for you, so the hooks behave the same in a Vite SPA as they do in a server-rendered page. + +# Client-side setup + +For a Vite app, setup is two imports. Wrap the tree with the provider, then call `useAuth` wherever you need it. + +```tsx +// main.tsx +import { AppwriteProvider } from "@appwrite.io/react"; + + + +; +``` + +With the provider in place, every component can pull the current user, sign-in, sign-up, and sign-out methods from a single hook. + +```tsx +// App.tsx +import { useAuth } from "@appwrite.io/react"; + +function App() { + const { user, signIn, signOut } = useAuth(); + // render auth UI +} +``` + +That is the entire client setup. The library handles the service file, the initial account fetching on mount, and the auth context that you would otherwise write by hand. The full walkthrough lives in the [Vite React quickstart](/docs/quick-starts/react). + +# Server-side rendering + +For server-rendered React, the package adds three pieces: + +- A handler route that processes sign-in, sign-up, sign-out, and OAuth callback requests on your server. +- Server helpers that resolve the current user, session, or session-scoped client from the request cookie. +- An SSR mode on the provider that hydrates the client with the server-side session, so the first paint already knows the user. + +Concretely, in a Next.js layout, you read the cookie server-side, pass the value through the provider, and the client hooks pick it up. + +```tsx +// app/layout.tsx +const helpers = createNextServerHelpers(appwrite); +const session = await helpers.readSessionCookie(); + +return {children}; +``` + +The same helpers can be called inside any server component to fetch the user before the page is sent to the browser. + +```tsx +// app/page.tsx +const user = await helpers.getLoggedInUser(); +``` + +The same flow on TanStack Start runs through `createServerFn` and `Route.useLoaderData()`. The hooks themselves do not change. + +# Session client + +For per-request operations on behalf of the signed-in user, the framework helpers expose `createSessionClient`. It returns a `node-appwrite` client already authenticated with the request cookie, so server components and loaders can act as the user without re-implementing session handling. + +```ts +const helpers = createNextServerHelpers(appwrite); +const session = await helpers.createSessionClient(); + +if (session) { + const user = await session.account.get(); +} +``` + +# Admin client + +For privileged operations, pass an `apiKey` into the framework helper and call `createAdminClient()` on it. The returned object exposes every `node-appwrite` service (`users`, `tablesDB`, `storage`, `teams`, `functions`, and so on), so the rest of your server code keeps using the official Node SDK. + +```ts +const helpers = createNextServerHelpers({ + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, + apiKey: process.env.APPWRITE_API_KEY!, +}); + +const admin = helpers.createAdminClient(); +const users = await admin.users.list(); +``` + +# Where to start + +Three quickstarts ship alongside the library: + +- [Vite React](/docs/quick-starts/react) for client-rendered apps +- [Next.js App Router](/docs/quick-starts/nextjs) for server-rendered React on Next.js +- [TanStack Start](/docs/quick-starts/tanstack-start) for server-rendered React on TanStack Start + +Each one ends with a working sign-up, sign-in, and sign-out flow. From there, the [React library docs](/docs/products/auth/react) cover the hooks, the server helpers, OAuth, and the handler configuration in depth. + +We would love to hear what you build with it. Drop into the [Appwrite Discord](https://appwrite.io/discord) and tell us how the SSR story feels in your framework of choice. diff --git a/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc b/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc new file mode 100644 index 00000000000..ec17b06d9df --- /dev/null +++ b/src/routes/blog/post/appwrite-1-9-5-self-hosted-release/+page.markdoc @@ -0,0 +1,132 @@ +--- +layout: post +title: Announcing Appwrite 1.9.5 for self-hosted deployments +description: Appwrite 1.9.5 brings the Presences API, BigInt columns, the Rust runtime, X OAuth, Bun and Deno build runtimes, Git deployment triggers, faster Storage uploads, and broader migrations to self-hosted deployments. +cover: /images/blog/appwrite-1-9-5-self-hosted-release/cover.avif +date: 2026-06-30 +timeToRead: 6 +author: chirag-aggarwal +category: announcement +featured: false +callToAction: true +faqs: + - question: "What is new in Appwrite 1.9.5 for self-hosted deployments?" + answer: "Appwrite 1.9.5 brings the Presences API, BigInt columns for [Databases](/docs/products/databases), the Rust runtime for [Functions](/docs/products/functions), X OAuth for [Auth](/docs/products/auth), Bun and Deno build runtimes and Git deployment triggers for [Sites](/docs/products/sites), faster Storage uploads with parallel chunks, and broader migration coverage." + - question: "How do I self-host Appwrite 1.9.5?" + answer: "Run the Docker installer with the 1.9.5 image, then open the setup wizard on port 20080 to finish configuration. See the [self-hosting installation guide](/docs/advanced/self-hosting/installation) for the full command and system requirements." + - question: "How do I upgrade my self-hosted instance to 1.9.5?" + answer: "Back up your data, pull the 1.9.5 image, run the upgrade command, and run the migration. Always test the upgrade on a staging environment first." + - question: "What is the Presences API used for?" + answer: "The Presences API tracks short-lived user states such as online, away, typing, editing, or viewing. You can use it to build online indicators, typing states, collaborative editors, multiplayer features, and live activity feeds without managing presence channels yourself." + - question: "What are BigInt columns in Appwrite?" + answer: "BigInt columns store 64-bit signed integers in [Databases](/docs/products/databases). They are suited to large counters, external IDs, high-resolution timestamps, and financial values that need integer precision without floating-point rounding." + - question: "Does Appwrite Functions support Rust?" + answer: "Yes. Appwrite 1.9.5 adds Rust as a first-class [Functions](/docs/products/functions) runtime, so you can write and deploy functions in Rust and pair them with the official Appwrite Rust SDK." + - question: "Can I build my Appwrite Sites with Bun or Deno?" + answer: "Yes. Appwrite [Sites](/docs/products/sites) can now build Node-based frameworks with Bun or Deno. You can switch the build runtime per Site from its Runtime settings, and the change applies on the next deployment." + - question: "How much faster are Storage uploads in 1.9.5?" + answer: "Appwrite SDKs now upload Storage file chunks in parallel. In our Node SDK benchmark, a 1.28 GB upload dropped from 4 minutes 44 seconds to under 40 seconds, a 7.10x improvement, with no API changes required." +--- + +**Appwrite 1.9.5** is now available for self-hosted deployments. + +Over the past few months, we have shipped a steady stream of features across Appwrite Cloud. This release brings them to teams running Appwrite on their own infrastructure. + +Here is what is new in Appwrite 1.9.5. + +# Presences API + +The Presences API tracks short-lived user states such as online, away, typing, editing, and viewing. It gives you a managed way to build online indicators, typing states, multiplayer presence, collaborative editors, and live activity feeds, without wiring up presence channels by hand. Entries carry custom metadata and expire automatically, so stale sessions clear themselves. + +{% arrow_link href="/blog/post/announcing-presences-api" %} +Read the announcement +{% /arrow_link %} + +# BigInt columns + +Appwrite Databases now support 64-bit signed integers through the BigInt column type. BigInt is the right choice for large counters, external identifiers, high-resolution timestamps, and financial values that need integer precision without floating-point rounding. + +{% arrow_link href="/blog/post/announcing-bigint-columns" %} +Read the announcement +{% /arrow_link %} + +# Rust runtime for Functions + +Appwrite Functions now supports Rust as a first-class runtime. You can write and deploy functions in Rust, pair them with the official Appwrite Rust SDK, and use them for performance-sensitive workloads such as webhook verification, image processing, and data transformation. + +{% arrow_link href="/blog/post/announcing-rust-runtime" %} +Read the announcement +{% /arrow_link %} + +# Bun and Deno build runtimes for Sites + +Appwrite Sites can now build Node-based frameworks with Bun or Deno. You can switch the build runtime per Site from its Runtime settings, and the change applies on the next deployment. + +{% arrow_link href="/blog/post/announcing-bun-deno-runtimes" %} +Read the announcement +{% /arrow_link %} + +# Git deployment triggers + +Git deployment triggers give you control over which changes create a deployment. Use branch filters to separate production, staging, and preview workflows, and path filters so each Function or Site only deploys when relevant files change. + +{% arrow_link href="/blog/post/announcing-git-deployment-triggers" %} +Read the announcement +{% /arrow_link %} + +# X OAuth provider + +Appwrite Auth now supports signing in with X (formerly Twitter) through OAuth 2.0 with PKCE. You can enable it from the Console by adding your X app credentials, with no additional configuration in your application code. + +{% arrow_link href="/blog/post/x-oauth2-appwrite" %} +Read the announcement +{% /arrow_link %} + +# Faster uploads with parallel chunks + +Appwrite SDKs now upload Storage file chunks in parallel. In our Node SDK benchmark, a 1.28 GB upload dropped from 4 minutes 44 seconds to under 40 seconds, a 7.10x improvement, with no API changes required. + +{% arrow_link href="/blog/post/faster-storage-uploads-parallel-chunks" %} +Read the announcement +{% /arrow_link %} + +# Improved migrations + +Migrations in 1.9.5 carry over far more than your data. Project configuration now transfers alongside it, including API keys, project variables, webhooks, OAuth providers, SMTP settings, email templates, custom domains, and security policies. Moving a project between Appwrite instances, such as from Appwrite Cloud to a self-hosted instance, now reproduces its setup instead of just its records. + +# Self-host Appwrite 1.9.5 + +If you are setting up Appwrite for the first time, all you need is Docker installed. Run the installer with the 1.9.5 image, then open `http://localhost:20080` to complete the setup wizard. + +```bash +docker run -it --rm \ + --publish 20080:20080 \ + --volume /var/run/docker.sock:/var/run/docker.sock \ + --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ + --entrypoint="install" \ + appwrite/appwrite:1.9.5 +``` + +For system requirements and the full walkthrough, see the [installation guide](/docs/advanced/self-hosting/installation). + +# Upgrade your self-hosted instance + +If you are already running Appwrite, back up your data first, then run the upgrade command: + +```bash +docker run -it --rm \ + --publish 20080:20080 \ + --volume /var/run/docker.sock:/var/run/docker.sock \ + --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ + --entrypoint="upgrade" \ + appwrite/appwrite:1.9.5 +``` + +After the upgrade is complete, run the migration: + +```sh +cd appwrite/ +docker compose exec appwrite migrate +``` + +To view the complete list of changes, fixes, and contributions, check out the full [release notes](https://github.com/appwrite/appwrite/releases/tag/1.9.5). diff --git a/src/routes/blog/post/best-vibe-coding-tools-for-beginners-in-2026/+page.markdoc b/src/routes/blog/post/best-vibe-coding-tools-for-beginners-in-2026/+page.markdoc index 7de45498bb0..4c6d0bd4c62 100644 --- a/src/routes/blog/post/best-vibe-coding-tools-for-beginners-in-2026/+page.markdoc +++ b/src/routes/blog/post/best-vibe-coding-tools-for-beginners-in-2026/+page.markdoc @@ -1,7 +1,7 @@ --- layout: post title: Best vibe coding tools for beginners in 2026 -description: Compare the best vibe coding tools for beginners in 2026 and learn how to choose the right AI coding tool to build faster, avoid setup friction, and ship your app with Appwrite. +description: Compare the best vibe coding tools for beginners in 2026 and learn how to choose the right AI coding tool to build faster with Appwrite. date: 2026-05-25 cover: /images/blog/best-vibe-coding-tools-for-beginners-in-2026/cover.avif timeToRead: 5 @@ -47,7 +47,7 @@ With those filters in mind, here is the list. Claude Code is Anthropic's agentic coding tool that started in the terminal and now works across the terminal, IDE, desktop app, and browser. The terminal sounds intimidating, but the experience is closer to texting a senior engineer than writing shell commands. It reads your repo, makes changes, runs tests, and explains what it did in plain English. -Best for: beginners who want UI to be the major focus of their projects and prefer workflows like subagents to handle many tasks at once. +Best for: beginners who want UI to be the major focus of their projects and prefer workflows like subagents to handle many tasks at once. ## 2. Codex @@ -129,6 +129,8 @@ Vibe coding tools are great at scaffolding the app you can see. The part you can Appwrite is a backend platform developers can use once their projects need more than a quick prototype. A Cloud version that gets out of your way so you can ship. One platform for auth, database, storage, functions, messaging, and realtime, with SDKs that feel native in whatever framework your AI just spun up. +Recent releases have added [MongoDB support, Appwrite 1.9.0, realtime upgrades, and new AI tooling](https://dev.to/appwrite/april-product-update-mongodb-support-appwrite-190-realtime-upgrades-and-ai-tooling-1eg6), with [more landing every few weeks](https://dev.to/appwrite/may-product-update-presences-api-rust-runtime-7x-faster-storage-uploads-and-more-9h5). We post weekly roundups of product announcements, AI updates, and [developer insights](https://dev.to/appwrite/weekly-roundup-presences-api-git-deployment-triggers-and-ai-updates-58lj) on the [Appwrite blog](https://appwrite.io/blog) and across our developer channels, so follow along wherever you read. + Sign up for [Appwrite Cloud](https://cloud.appwrite.io/) or set up a self-hosted instance, and give your AI-built app a real backend for auth, data, storage, functions, messaging, and realtime. # Resources diff --git a/src/routes/blog/post/claude-fable-5-returns-with-stronger-jailbreak-safeguards/+page.markdoc b/src/routes/blog/post/claude-fable-5-returns-with-stronger-jailbreak-safeguards/+page.markdoc new file mode 100644 index 00000000000..3f35928f596 --- /dev/null +++ b/src/routes/blog/post/claude-fable-5-returns-with-stronger-jailbreak-safeguards/+page.markdoc @@ -0,0 +1,130 @@ +--- +layout: post +title: Claude Fable 5 returns with stronger jailbreak safeguards +description: Claude Fable 5 is back after export controls lifted, now with an upgraded jailbreak safety classifier and deeper US government collaboration. +date: 2026-07-02 +cover: /images/blog/claude-fable-5-returns-with-stronger-jailbreak-safeguards/cover.avif +timeToRead: 5 +author: aishwari +category: ai +featured: false +faqs: + - question: Why was Claude Fable 5 suspended? + answer: On June 12, the US government applied export controls to both models, requiring Anthropic to restrict access for foreign nationals. Because the order took effect immediately and there was no reliable way to verify nationality in real time, Anthropic suspended access to both models for everyone. + - question: Is Claude Fable 5 available again? + answer: Yes. As of June 30 the export controls were lifted, and Fable 5 is available again starting Wednesday, July 1, to users globally on the Claude Platform, Claude.ai, Claude Code, and Claude Cowork. + - question: What happened to Claude Fable 5? + answer: Anthropic released Fable 5 and Mythos 5 on June 9. The US government applied export controls on June 12, forcing a full suspension. Those controls were lifted June 30, and Fable 5 is rolling back out globally. + - question: What jailbreak was found in Claude Fable 5? + answer: Amazon researchers found a technique that prompted the model to identify a number of software vulnerabilities, and in one case the model produced code demonstrating how a specific vulnerability could be exploited. Anthropic classified it as a minor jailbreak involving routine defensive cybersecurity work. + - question: What is the difference between Claude Fable 5 and Mythos 5? + answer: They share the same underlying model but differ in how safeguards are applied. Fable 5 shipped with strong safeguards for general use, while Mythos 5 launched with fewer safeguards to a small number of trusted Project Glasswing partners for defensive cybersecurity work. +--- +Claude Fable 5 is back. After a little over two weeks offline, Anthropic has [redeployed](https://www.anthropic.com/news/redeploying-fable-5) its most capable generally available model following the removal of US export controls that had forced a full suspension. Starting Wednesday, July 1, Fable 5 is available again to users worldwide, and it returns with an upgraded safety classifier, a proposed industry framework for scoring jailbreaks, and a deeper set of commitments to the US government. + +If you build on Fable 5, or you were mid-project when it went dark on June 12, here is what changed, why it happened, and what the redeployment means for the way you build. + +# What happened to Claude Fable 5? + +The short version is a timeline. Anthropic released Claude Fable 5 and Claude Mythos 5 on Tuesday, June 9. The two share the same underlying model but differ in how safeguards are applied: Fable 5 shipped with strong safeguards for general use, while Mythos 5 launched with fewer safeguards to a small number of trusted Project Glasswing partners for defensive cybersecurity work. + +On Friday, June 12, the US government applied export controls to both models. Those controls required Anthropic to restrict access for foreign nationals, whether inside or outside the United States. Because the order took effect immediately and there was no reliable way to verify nationality in real time, Anthropic suspended access to both models for everyone. + +As of June 30, those export controls have been lifted. Fable 5 is rolling back out globally, and access to Mythos 5 has been restored for a set of US organizations after the government's approval on June 26. + +# Why were Fable 5 and Mythos 5 suspended? + +The export control directive followed a report from Amazon researchers who found a way to bypass Fable 5's safeguards. The technique prompted the model so that it identified a number of software vulnerabilities, and in one case the model produced code demonstrating how a specific vulnerability could be exploited. + +Over the following two weeks, Anthropic worked with the government and partners, including Amazon, to review the report and the evidence behind it. The suspension was a direct consequence of the export order taking effect with no real-time nationality check available, so the safest option was to pull access for all users rather than risk non-compliance. + +# What the investigation found + +The review put the reported bypass in context, and the findings are worth reading closely if you're trying to gauge real risk. + +Anthropic's testing confirmed that many less capable models could identify the same vulnerabilities that Fable 5 did in the report, including Claude Opus 4.8, GPT-5.5, and Kimi K2.7. When it came to the single demonstration of how to exploit a vulnerability, every model tested could produce the same demonstration as Fable 5. That list included Claude Haiku 4.5, Sonnet 4.6, Opus 4.6, Opus 4.7, and Opus 4.8, alongside GPT-5.4, GPT-5.5, and Kimi K2.7. + +Crucially, the reported technique did not expose any unique Mythos-level cyber capabilities. It reflected a borderline case for Fable 5's safeguards. As explained below, some tasks are unlikely to be dangerous but are still blocked out of an abundance of caution, and the reported technique only reached one such behavior, which involved routine defensive cybersecurity work. + +# Claude Fable 5's new safety classifier + +Even though the bypass touched only routine defensive work, Anthropic moved quickly to close it. Working with the government, the team trained an improved safety classifier that targets and blocks the behavior described in the Amazon report. + +For builders, the practical mechanics matter: + +* If a request to Fable 5 is blocked, the user is notified. +* The blocked request is then sent to Claude Opus 4.8 instead. +* The new classifier blocks the specific technique from the report in over 99% of cases. + +In a very small fraction of cases, the model may still return information, but not detailed enough to help a cyberattacker. Researchers from the US Department of Commerce's Center for AI Standards and Innovation (CAISI) tested both the prior and the new safeguards and agreed they are extraordinarily strong. + +There is a tradeoff. The new classifier flags benign requests more often during routine coding and debugging. Anthropic says it will keep refining the classifier to better separate genuine misuse from legitimate requests and to reduce false positives. + +# How Anthropic's cybersecurity safeguards work + +To understand why a routine coding request can occasionally get caught, it helps to understand the safeguard design. Fable 5 launched with the strongest safeguards Anthropic has ever applied to a model, and in the month before launch the company doubled the number of researchers and engineers on the problem by moving staff across teams. + +## Defense in depth + +No single mechanism provides perfect protection, so Fable 5 stacks several. Some defenses train the model to decline dangerous requests. Others retroactively analyze patterns of misuse. Combined, they make the model very difficult to misuse. + +## Classifiers and the safety margin + +One of the most important mechanisms is the classifier: a smaller automated AI system that detects, during an interaction, when the model is asked to perform a potentially harmful cybersecurity task or produce a potentially harmful output. When that happens, the classifier blocks the model from responding. The goal is to stop uniquely dangerous behaviors. + +Because classifiers can miss content or be jailbroken, Anthropic deliberately tunes them to trigger on some requests that are likely benign. A request has to look very clearly safe to avoid tripping the classifier, which users experience as the model declining some reasonable, non-harmful requests. This buffer is the "safety margin." For Fable 5, that margin was set much larger than in any prior launch, so more benign requests get blocked, but fewer genuinely harmful ones slip through. This is the deliberate tradeoff that keeps the rest of Fable 5's capabilities widely available. + +## How jailbreaks are categorized + +The safety margin also helps blunt jailbreaks, and Anthropic sorts them by severity: + +* **Minor jailbreaks** unblock behavior that still sits inside the safety margin. It is very unlikely to be harmful. Anthropic's view is that the jailbreaks reported for Fable 5 so far fall into this category. +* **Narrow harmful jailbreaks** breach the classifiers to unlock a specific harmful behavior. These are typically low to moderate severity because their narrowness limits the attacker. +* **Universal jailbreaks** unblock a whole class of harmful behaviors and are the most concerning. + +Anthropic is candid that it is probably impossible to make any model fully impervious to jailbreaks. It expects many minor ones and some narrow harmful ones over time. At the time of writing, no universal jailbreaks for Fable 5 have been discovered, and expert red-teamers continue to probe it. The aim is for Anthropic and its safety partners to find and fix major jailbreaks before malicious actors can use them. + +# Deeper collaboration with the US government + +The redeployment comes with a broader set of commitments tied to the June 2 Executive Order on Promoting Advanced Artificial Intelligence Innovation and Security. Anthropic's engagement spanned the Office of the National Cyber Director, the Office of Science and Technology Policy, the Treasury, the Department of Commerce including CAISI, and national security agencies. + +The commitments include: + +* Expanded early access for designated government partners to evaluate frontier models and safeguards before broad release +* Faster information sharing when significant jailbreaks or misuse patterns appear +* Dedicated teams and compute for joint research +* Work toward a shared, voluntary security and evaluation standard across frontier model providers + +Anthropic frames the goal as durable, transparent rules that give cyber defenders more certainty around access to powerful models. + +# Claude Fable 5 availability and pricing after redeployment + +Here is the part that affects your rollout plans. + +Claude Fable 5 is available starting Wednesday, July 1, to users globally on the Claude Platform, Claude.ai, Claude Code, and Claude Cowork. For Pro, Max, Team, and select Enterprise plans, Fable 5 is included for up to 50% of weekly usage limits through July 7, after which it is available via usage credits. Anthropic will re-enable access on AWS, Google Cloud, and Microsoft Foundry as quickly as possible. + +A note for Enterprise: standard Enterprise seats have no included Fable 5 allowance, so all usage is billed through usage credits, and Fable 5 will not work unless credits are enabled. Premium Enterprise seats include Fable 5 through July 7, drawing from each member's seat usage at no additional cost, after which enabling usage credits keeps it running. + +Access to Mythos 5 has been restored for a set of US organizations following the government's June 26 approval, and Anthropic says it is still coordinating to expand access across the broader Glasswing program. + +# What this means if you build on Appwrite + +The takeaway for developers is that Fable 5's long-horizon strengths, such as codebase-wide migrations and multi-step autonomous work, are back on the table, but the redeployment also comes with an important caveat. If a request is flagged as cybersecurity-adjacent, the classifier may route it to Opus 4.8 instead of continuing on Fable 5. + +That may prevent some requests from failing outright, but it can also create friction if an agent changes models mid-workflow. If you are building agentic apps, this is something to account for in testing, logs, and user experience. + +Beyond model behavior, agents still need the usual product infrastructure around them: authentication, stored state, file persistence, and server-side logic between steps. In other words, they still need a backend, and wiring one up by hand can slow down the path from prototype to product. + +If you want your Fable 5 agent to stand up that backend without manually assembling infrastructure, the [Appwrite plugin for Claude Code](https://appwrite.io/docs/tooling/claude-code) bundles the [Appwrite API MCP server](https://appwrite.io/docs/tooling/mcp), the Appwrite Docs MCP server, and SDK-specific agent skills into a single install. With the right project access and permissions, an agent can work directly with Appwrite APIs and docs to set up [Auth](https://appwrite.io/docs/products/auth), [Databases](https://appwrite.io/docs/products/databases), [Storage](https://appwrite.io/docs/products/storage), [Sites](https://appwrite.io/docs/products/sites), and [Functions](https://appwrite.io/docs/products/functions). + +# Build agentic apps on Appwrite + +Spin up the backend your next app needs in minutes. [Start for free on Appwrite Cloud](https://cloud.appwrite.io/), and let Appwrite handle Auth, Databases, Storage, Functions, Messaging, and Sites. Your Fable 5 agent builds the app, Appwrite runs the backend behind it, and you ship the product instead of wiring up the infrastructure. + +# Resources + +* [Appwrite MCP server docs](/docs/tooling/ai/mcp-servers/) +* [Start building on Appwrite Cloud](https://cloud.appwrite.io/) +* [Appwrite AI tooling](/docs/tooling/ai) +* [Appwrite integrations](/integrations) +* [Join the Appwrite Discord](https://appwrite.io/discord) \ No newline at end of file diff --git a/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc b/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc new file mode 100644 index 00000000000..386d2f54561 --- /dev/null +++ b/src/routes/blog/post/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/+page.markdoc @@ -0,0 +1,129 @@ +--- +layout: post +title: "Claude Sonnet 5 is Anthropic's most agentic Sonnet yet" +description: "Claude Sonnet 5 is Anthropic's most agentic Sonnet model, nearing Opus 4.8 performance at lower prices. See benchmarks, pricing, and how to build on Appwrite." +date: 2026-07-01 +cover: /images/blog/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/cover.avif +timeToRead: 5 +author: aishwari +category: ai +featured: false +faqs: + - question: When was Claude Sonnet 5 released? + answer: Anthropic launched Claude Sonnet 5 on June 30, 2026. It is available everywhere from day one, including Claude Code, the Claude Platform, and the Claude API. + - question: How much does Claude Sonnet 5 cost? + answer: Claude Sonnet 5 launched with introductory pricing of $2 per million input tokens and $10 per million output tokens through August 31, 2026. After that it moves to standard pricing of $3 per million input tokens and $15 per million output tokens. For reference, Opus 4.8 costs $5 input and $25 output per million tokens. + - question: What is new in Claude Sonnet 5 compared with Sonnet 4.6? + answer: Better reasoning, tool use, coding, and knowledge work. It is more persistent on long tasks, checks its own output, and is safer overall. + - question: Is Claude Sonnet 5 good for coding? + answer: Yes. It scores 63.2% on SWE-bench Pro and 80.4% on Terminal-Bench 2.1, close to Opus 4.8 and well ahead of Sonnet 4.6. + - question: Is Claude Sonnet 5 free? + answer: Yes, in the consumer apps. Claude Sonnet 5 is the default model on the Free and Pro plans, and is also available to Max, Team, and Enterprise users. Developers who call it through the Claude API pay per token at the rates above. +--- +Anthropic just [launched Claude Sonnet 5](https://www.anthropic.com/news/claude-sonnet-5), the most agentic Sonnet model it has released. It can make plans, drive tools like browsers and terminals, and run autonomously on work that only a few months ago demanded larger, more expensive models. For anyone building agents, that shift matters. The capability you used to reach for an Opus-class model to get is now available in a Sonnet-class one, at a Sonnet-class price. You call it through the Claude API with the model id `claude-sonnet-5`. + +The agentic AI era arguably started with Sonnet-class models. Claude Sonnet 3.5, 3.6, and 3.7 were the first to show serious skill at coding and tool use. Since then, the sharpest gains had been concentrated in Opus-class models. Claude Sonnet 5 narrows that gap: its performance lands close to Opus 4.8 on many tasks, while carrying lower input and output token pricing than Opus 4.8. + +# What is Claude Sonnet 5? + +Claude Sonnet 5 is Anthropic's newest mid-tier model and the successor to Claude Sonnet 4.6. It's a substantial upgrade on the aspects of agentic performance that developers care about most: reasoning, tool use, coding, and knowledge work. The headline is efficiency. Sonnet 5 gets close to Opus 4.8 quality on a range of tasks while staying priced as a Sonnet, which makes it the natural default for high-volume, long-running agent workloads where cost per run adds up fast. + +It's available everywhere from launch. Sonnet 5 is the default model on Free and Pro plans, and is available to Max, Team, and Enterprise users. It also ships in Claude Code and on the Claude Platform, and developers can call it directly via the Claude API. + +One implementation detail worth knowing before you migrate: Sonnet 5 uses an updated tokenizer (the same change Anthropic introduced with Claude Opus 4.7). It changes how the model processes text to improve performance, with the tradeoff that the same input can map to more tokens, roughly 1.0 to 1.35 times as many depending on the content type. Anthropic set the introductory pricing so that moving from Sonnet 4.6 to Sonnet 5 is roughly cost-neutral despite this. + +# Claude Sonnet 5 benchmarks + +Anthropic published a benchmark table comparing Sonnet 5 against its predecessor Sonnet 4.6 and against Opus 4.8, which sits above it as a more generally capable reference model. Across the board, Sonnet 5 improves on Sonnet 4.6 and closes much of the distance to Opus 4.8. + +| Benchmark | Claude Sonnet 5 | Claude Sonnet 4.6 | Claude Opus 4.8 (for reference) | +| -------------------------------------------------------------- | --------------- | ----------------- | ------------------------------- | +| Agentic coding (SWE-bench Pro) | 63.2% | 58.1% | **69.2%** | +| Agentic coding (Terminal-Bench 2.1) | 80.4% | 67.0% | **82.7%** | +| Multidisciplinary reasoning (Humanity's Last Exam, no tools) | 43.2% | 34.6% | **49.8%** | +| Multidisciplinary reasoning (Humanity's Last Exam, with tools) | 57.4% | 46.8% | **57.9%** | +| Computer use (OSWorld-Verified) | 81.2% | 78.5% | **83.4%** | +| Knowledge work (GDPval-AA v2) | **1618** | 1395 | 1615 | + +*Scores for Sonnet 5 on a range of evaluations compared with Sonnet 4.6 and Opus 4.8 (a more generally capable model, shown for reference). The* [Claude Sonnet 5 System Card](https://www.anthropic.com/news/claude-sonnet-5) *reports a broader set of evaluations in detail.* + +**The pattern** + +* Sonnet 5 beats Sonnet 4.6 on every benchmark, often by a wide margin, and lands within a few points of Opus 4.8 on most of them. +* Terminal-Bench 2.1: 80.4% vs Opus 4.8's 82.7%. +* OSWorld-Verified: 81.2% vs 83.4%. +* Knowledge work (GDPval-AA v2): edges past Opus 4.8, 1618 to 1615. +* Clearest remaining gap: the harder SWE-bench Pro coding tasks, where Opus 4.8 still leads. + +**A note on shifting reference numbers** + +* A couple of these reference numbers moved recently for methodology reasons, so it's worth being precise. +* Anthropic updated the grader model for Humanity's Last Exam, so Sonnet 4.6 now sits at 34.6% (no tools) and 46.8% (with tools) rather than its original launch figures. +* Changes to how OSWorld-Verified is run, meant to better reflect real-world performance, moved Sonnet 4.6's score to 78.5%. +* If you compare against older blog posts, expect small discrepancies for exactly this reason. + +# How Claude Sonnet 5 compares to Opus 4.8 + +The most useful way to think about Sonnet 5 is not as a cheaper Sonnet upgrade, but as part of Anthropic's newer 5-series generation, alongside models like Fable 5. It is more capable than Sonnet 4.6 and has lower per-token pricing than Opus 4.8, but that does not automatically make every run cheaper. + +Anthropic lets developers adjust the effort level, from lower settings for faster runs up to max mode for harder tasks that need deeper reasoning. The important caveat is that Sonnet 5 tends to spend far more tokens at higher reasoning levels, so lower per-token pricing does not always mean lower task cost. In Artificial Analysis' benchmark, Sonnet 5 at max effort cost more overall than Fable 5 and Opus 4.8, officially being the most expensive model on their benchmark. That makes the tradeoff less about "cheap Sonnet vs expensive Opus" and more about choosing the right effort level for the workload. + +The practical takeaway is to treat cost as a mix of model price, total tokens used, and effort level: + +* Use lower or medium effort for high-volume tasks where speed and cost control matter. +* Use max mode only when the task genuinely needs stronger reasoning or longer autonomous work. +* Do not assume Sonnet 5 is cheaper overall just because its per-token pricing is lower than Opus 4.8. + +# What Claude Sonnet 5 is good at + +Anthropic's early-access partners were consistent in their feedback: Sonnet 5 is much more agentic than its predecessors. The concrete behaviors they highlighted map neatly onto what an agent actually needs to do. + +* **Finishing long tasks.** Testers described Sonnet 5 completing complex, multi-step tasks where previous Sonnet models would stop short. That persistence across a long chain of steps is exactly what separates a usable agent from one that needs constant hand-holding. +* **Checking its own work.** Partners noted that Sonnet 5 verifies its own output without being explicitly told to. Self-checking is a small behavior with an outsized effect on reliability, because it catches errors before they compound down the chain. +* **Tool use and reasoning.** The gains over Sonnet 4.6 in tool use, reasoning, and coding are what let it operate browsers and terminals autonomously and recover when a step doesn't go as planned. + +# Claude Sonnet 5's safety and safeguards + +More autonomy also raises the bar for safety. Since Sonnet 5 is designed for tool-heavy agentic work, Anthropic evaluated how well it handles malicious requests, prompt injection, hallucination, sycophancy, and cyber misuse. + +* Anthropic's pre-deployment evaluations found Sonnet 5 to be an overall improvement on Sonnet 4.6 for safety. It's better at refusing malicious requests and at resisting hijack attempts in prompt injection attacks, a meaningful property for agents that read untrusted web content or tool output. It also shows lower rates of hallucination and sycophancy than Sonnet 4.6. +* On Anthropic's automated behavioral audit, which tests for a wide range of misaligned behaviors such as cooperation with misuse and deception, Sonnet 5 scored lower (that is, safer) overall than Sonnet 4.6. It did show somewhat higher rates of misaligned behavior than the more capable Opus 4.8 and Claude Mythos Preview, which is the expected pattern for a smaller model. +* On cybersecurity, the key point is that Sonnet 5 simply isn't that capable of causing cyber harm. Anthropic did not deliberately train it on cyber tasks. It can handle routine, non-harmful cyber work but performs substantially worse than Opus 4.8 and Mythos 5 on potentially dangerous skills such as developing software exploits. On an evaluation built with Mozilla that tested exploit development against Firefox vulnerabilities (since patched), Sonnet 5 never produced a full working exploit. It showed a slightly higher partial-success rate than Sonnet 4.6, a shift Anthropic attributes to general intelligence gains rather than any cyber-specific training. +* Because Sonnet 5 is somewhat stronger than its predecessor here, it launches with cyber safeguards enabled by default. These are the same real-time detection-and-blocking safeguards present in Claude Opus 4.7 and 4.8, and they're deliberately less strict than the safeguards shipped with Fable 5, reflecting Anthropic's judgment that Sonnet 5's overall cyber risk is low. Sonnet 5 is also part of Anthropic's Cyber Verification Program. + +# Claude Sonnet 5 pricing + +Claude Sonnet 5 launches with introductory pricing, per million tokens: + +* **Input:** $2 +* **Output:** $10 + +That introductory rate runs through **August 31, 2026**, after which it moves to standard pricing of **$3 per million input tokens and $15 per million output tokens**. For comparison, Opus 4.8 is priced at $5 input and $25 output per million tokens. + +Keep the tokenizer change in mind when you model your bill: because the same input can map to more tokens under Sonnet 5's tokenizer, the introductory pricing is calibrated to keep the transition from Sonnet 4.6 roughly cost-neutral. Anthropic also raised rate limits across Chat, Cowork, Claude Code, and the Claude Platform to accommodate the higher token usage that comes with higher effort levels. + +# Claude Sonnet 5 availability + +Sonnet 5 is available everywhere today. It's the default model on Free and Pro plans and is available to Max, Team, and Enterprise users. Developers can reach it in Claude Code and on the Claude Platform, and call it directly through the Claude API using the model id `claude-sonnet-5`. There's no staged rollout to wait through, so you can start building on it now. + +# What this means if you build on Appwrite + +Sonnet 5's biggest strength is long-horizon, autonomous work at a price that makes running it at scale realistic: agents that plan, use tools, check their own output, and keep going across many steps. An agent doing that kind of work needs somewhere to authenticate users, store state, persist files between steps, and run server-side logic. In other words, it needs a backend, and wiring one up by hand is usually the slow part of shipping an agentic app. + +If you want your Sonnet 5 powered agent to stand up that backend without manually assembling infrastructure, the [Appwrite plugin for Claude Code](https://appwrite.io/docs/tooling/claude-code) bundles the [Appwrite API MCP server](https://appwrite.io/docs/tooling/mcp), the Appwrite Docs MCP server, and SDK-specific agent skills into a single install. With the right project access and permissions, an agent can work directly with Appwrite APIs and docs to set up [Auth](https://appwrite.io/docs/products/auth), [Databases](https://appwrite.io/docs/products/databases), [Storage](https://appwrite.io/docs/products/storage), [Sites](https://appwrite.io/docs/products/sites), and [Functions](https://appwrite.io/docs/products/functions). + +Because Sonnet 5 lets you tune effort against cost, it pairs especially well with high-volume agent workloads: run at medium effort for the bulk of routine steps, and dial up only when a task genuinely needs it. + +# Build agentic apps on Appwrite + +Spin up the backend your next app needs in minutes. Start for free on Appwrite Cloud, connect the Claude API with the model id `claude-sonnet-5`, and let Appwrite handle Auth, Databases, Storage, Functions, Messaging, and Sites. Your Sonnet 5 agent builds the app, Appwrite runs the backend behind it, and you ship the product instead of wiring up infrastructure. + +Recent releases have added [MongoDB support, Appwrite 1.9.0, realtime upgrades, and new AI tooling](https://dev.to/appwrite/april-product-update-mongodb-support-appwrite-190-realtime-upgrades-and-ai-tooling-1eg6), with [more landing every few weeks](https://dev.to/appwrite/may-product-update-presences-api-rust-runtime-7x-faster-storage-uploads-and-more-9h5). We post weekly roundups of product announcements, AI updates, and [developer insights](https://dev.to/appwrite/weekly-roundup-presences-api-git-deployment-triggers-and-ai-updates-58lj) on the [Appwrite blog](https://appwrite.io/blog) and across our developer channels, so follow along wherever you read. + +# Resources + +* [Appwrite MCP server docs](/docs/tooling/ai/mcp-servers/) +* [Start building on Appwrite Cloud](https://cloud.appwrite.io/) +* [Appwrite AI tooling](/docs/tooling/ai) +* [Appwrite integrations](/integrations) +* [Join the Appwrite Discord](https://appwrite.io/discord) diff --git a/src/routes/blog/post/what-developers-actually-want-from-a-backend-platform/+page.markdoc b/src/routes/blog/post/what-developers-actually-want-from-a-backend-platform/+page.markdoc index a0f19f21edf..fe8a7eba35f 100644 --- a/src/routes/blog/post/what-developers-actually-want-from-a-backend-platform/+page.markdoc +++ b/src/routes/blog/post/what-developers-actually-want-from-a-backend-platform/+page.markdoc @@ -96,7 +96,7 @@ A backend platform should handle the following by default: - Rate limiting on authentication endpoints - Session management with configurable expiry -Appwrite's [permissions model](/docs/products/databases/permissions) operates at the table and row-level. Combined with [roles and labels](/docs/products/auth/roles) on user accounts, you can model granular access patterns without writing custom middleware for every endpoint. +Appwrite's [permissions model](/docs/products/databases/permissions) operates at the table and row-level. Combined with [roles and labels](/docs/advanced/security/roles) on user accounts, you can model granular access patterns without writing custom middleware for every endpoint. # Scalability from first commit to production diff --git a/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc b/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc new file mode 100644 index 00000000000..cd19d3c57fb --- /dev/null +++ b/src/routes/blog/post/what-is-cicd-a-complete-guide-for-developers/+page.markdoc @@ -0,0 +1,130 @@ +--- +layout: post +title: What is CI/CD? A complete guide for developers +description: Learn what CI/CD means, how continuous integration and delivery work, the pipeline stages, delivery vs deployment, and best practices, in this developer guide. +date: 2026-06-26 +cover: /images/blog/what-is-cicd-a-complete-guide-for-developers/cover.avif +timeToRead: 5 +author: atharva +category: devops +featured: false +unlisted: true +faqs: + - question: "What's the difference between CI and CD?" + answer: "CI (continuous integration) automates building and testing code as it's merged. CD (continuous delivery or deployment) automates releasing that tested code to production." + - question: Do I need Docker or Kubernetes for CI/CD? + answer: No, but they pair well. CI/CD works with any deployment target. Containers and orchestration simply make builds more consistent and deployments more reliable. + - question: Is CI/CD only for large teams? + answer: No. Even solo developers benefit from automated testing and deployment. You can start with a simple pipeline and expand it as your project grows. + - question: Is CI/CD the same as DevOps? + answer: No. DevOps is a broader culture and set of practices for uniting development and operations. CI/CD is a key technical practice within DevOps, but DevOps also covers monitoring, infrastructure, and collaboration. +--- +CI/CD is a set of practices that automate building, testing, and releasing software, so teams can ship changes quickly, frequently, and reliably. It stands for continuous integration and continuous delivery (or continuous deployment), and together these practices form the backbone of modern software development and DevOps. + +This guide explains what CI/CD is, what each part means, how a pipeline works, the difference between delivery and deployment, the tools that power it, and how to get started. It's written for developers who want a complete picture, not just a definition. + +# What does CI/CD stand for? + +CI/CD combines two related practices. **CI** stands for **continuous integration**, the practice of frequently merging code changes into a shared repository, where each change is automatically built and tested. **CD** stands for either **continuous delivery** or **continuous deployment**, both of which automate getting that tested code into production. + +You can think of CI/CD as an assembly line for software. Instead of manually compiling, testing, and shipping every change by hand, you build an automated line that takes code from a developer's commit and moves it through a series of checks until it's ready to release, or released automatically. The goal is to make releasing software a routine, low-risk event rather than a stressful, error-prone one. + +CI/CD grew out of the DevOps movement, which aims to break down the wall between development and operations. By automating the path from code to production, teams release faster and with more confidence. + +# Why does CI/CD matter? + +CI/CD matters because manual building, testing, and deploying is slow, inconsistent, and error-prone. Here is why teams adopt it: + +* **Faster releases.** Automation lets teams ship updates daily or even many times a day instead of every few weeks or months. +* **Fewer bugs in production.** Automated testing on every change catches problems early, when they're cheapest to fix. +* **Consistency.** The same automated process runs every time, eliminating "it worked on my machine" surprises. +* **Faster feedback.** Developers learn within minutes whether a change broke something, instead of finding out days later. +* **Less risk.** Small, frequent releases are easier to test and roll back than large, infrequent ones. + +# What is continuous integration (CI)? + +Continuous integration is the practice of merging code changes into a shared branch frequently, often several times a day, with each merge triggering an automated build and test run. The core idea is that integrating small changes often is far less painful than integrating large changes rarely. + +When a developer pushes code, a CI system automatically pulls the latest code, builds it, and runs the test suite. If anything fails, the team is notified immediately and can fix it before it spreads. This keeps the shared codebase in a working state at all times and prevents the dreaded "integration hell" of merging months of divergent work at once. + +Good CI depends on a strong automated test suite, because the tests are what give the team confidence that each change is safe. + +# What is continuous delivery and continuous deployment (CD)? + +The "CD" in CI/CD refers to two related but distinct practices. + +**Continuous delivery** means every change that passes the automated pipeline is automatically prepared and ready to release to production, but the final release is triggered manually by a human. The software is always in a deployable state, and shipping is a one-click decision. + +**Continuous deployment** goes one step further: every change that passes all automated checks is released to production automatically, with no human approval step. This requires a high degree of confidence in your automated tests, since there's no manual gate before users see the change. + +Both build on continuous integration. The difference is simply whether the final push to production is automatic or requires a human to press the button. + +# How does a CI/CD pipeline work? + +A **CI/CD pipeline** is the automated sequence of steps that code passes through on its way from commit to production. While details vary, most pipelines share the same core stages: + +1. **Source.** A developer pushes code to a repository, which triggers the pipeline. +2. **Build.** The system compiles the code and its dependencies into a runnable artifact, often a [Docker](https://www.docker.com/) container image. +3. **Test.** Automated tests run, from fast unit tests to integration and end-to-end tests, validating the change. +4. **Deploy.** The artifact is released to an environment, such as staging or production, sometimes managed by [Kubernetes](https://kubernetes.io/). + +Each stage acts as a gate: if a step fails, the pipeline stops and the team is notified, so broken code never reaches users. Many pipelines also include extra stages for security scanning, performance checks, and approvals. + +# Popular CI/CD tools + +A range of tools automate CI/CD pipelines, and most integrate directly with your code repository: + +* **GitHub Actions**, built into GitHub, defines pipelines as YAML workflows right alongside your code. +* **GitLab CI/CD**, tightly integrated with GitLab repositories. +* **Jenkins**, a long-standing open-source automation server known for its flexibility and plugins. You can learn more at [jenkins.io](https://www.jenkins.io/). +* **CircleCI** and **Travis CI**, popular cloud-based CI/CD services. + +Many of these work hand in hand with containers and orchestration, building Docker images in the pipeline and deploying them to Kubernetes or a managed platform. + +# Common CI/CD use cases + +* **Web and mobile app delivery.** Automatically test and ship application updates on every merge. +* **Microservices.** Deploy many independent services reliably without coordinating manual releases. +* **Library and package publishing.** Automatically run tests and publish new versions when code is tagged. +* **Infrastructure as code.** Apply and validate infrastructure changes through the same automated pipeline. +* **Automated quality gates.** Enforce tests, linting, and security scans before any code merges. + +# How to get started with CI/CD + +Getting started is easier than it sounds, and you can begin small. + +1. **Put your code in version control** like Git, which is the foundation everything else builds on. +2. **Write automated tests**, even a small suite, since CI is only as valuable as the tests it runs. +3. **Choose a CI/CD tool**, such as GitHub Actions if your code is already on GitHub. +4. **Create a simple pipeline** that builds your project and runs your tests on every push. +5. **Add a deployment stage** to ship to a staging environment, then production, as your confidence grows. + +A backend platform like [Appwrite](https://appwrite.io/docs) pairs well with CI/CD, giving you auth, databases, storage, and functions that your pipeline can deploy against. + +# CI/CD best practices + +* **Keep the pipeline fast** so developers get feedback in minutes, not hours. +* **Build once, deploy everywhere.** Create a single artifact and promote it through environments rather than rebuilding. +* **Automate your tests thoroughly**, since the pipeline's value depends entirely on test quality. +* **Fail fast.** Run the quickest checks first so failures surface early. +* **Keep secrets out of your pipeline config**, using a secrets manager or encrypted variables. +* **Make rollbacks easy** so you can recover instantly if a release causes problems. + +# Conclusion + +CI/CD is the practice of automating the path from code to production, combining continuous integration to build and test every change with continuous delivery or deployment to release it reliably. Understanding its core pieces, namely the integration of frequent changes, the automated pipeline stages, and the distinction between delivery and deployment, gives you the foundation to ship software faster and with far more confidence. It's one of the highest-impact habits a team can adopt, and it scales from a solo project to a large organization. The best way to learn CI/CD is to build a simple pipeline that tests your code on every push, then grow it one stage at a time. + +# Start building + +Appwrite is open-source, self-hostable, and built for developers who want to ship fast without surrendering control. + +Whether you are prototyping your next idea or scaling a production app, Appwrite gives you Auth, Databases, Storage, Sites, Functions, and Realtime in one open-source platform. [Sign up for Appwrite Cloud](https://cloud.appwrite.io/) or spin up a self-hosted instance in minutes, and give your next build a real backend to grow on. + +## Resources + +* [Appwrite documentation](/docs) +* [Appwrite Functions](/docs/products/functions) +* [Appwrite integrations](/integrations) +* [Appwrite quick start guides](/docs/quick-starts) +* [Appwrite on GitHub](https://github.com/appwrite/appwrite) +* [Join the Appwrite Discord](https://appwrite.io/discord) diff --git a/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc b/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc new file mode 100644 index 00000000000..f7367fed43f --- /dev/null +++ b/src/routes/blog/post/what-is-redis-a-complete-guide-for-developers/+page.markdoc @@ -0,0 +1,128 @@ +--- +layout: post +title: What is Redis? A complete guide for developers +description: "Learn what Redis is, why it's so fast, how it works, its data structures, what it's used for, and how it compares to databases, in this guide for developers." +date: 2026-06-30 +cover: /images/blog/what-is-redis-a-complete-guide-for-developers/cover.avif +timeToRead: 5 +author: aditya-oberai +category: architecture +featured: false +unlisted: true +faqs: + - question: Is Redis a database or a cache? + answer: Both. Redis is an in-memory data store that can act as a database, a cache, and a message broker. It's most commonly used as a cache, but it's flexible enough to fill all three roles. + - question: Does Redis store data permanently? + answer: It can. By default Redis keeps data in memory, but with persistence options like RDB snapshots or AOF logging enabled, it saves data to disk and can recover after a restart. + - question: What is Redis used for most often? + answer: Caching is the most common use, storing frequently accessed data to speed up applications and reduce database load. It's also widely used for sessions, real-time features, and queues. + - question: Is Redis a SQL or NoSQL database? + answer: Redis is a NoSQL data store. It uses a key-value model with rich data structures rather than the tables and SQL queries of a relational database. +--- + +**Redis is an open-source, in-memory data store used as a database, cache, and message broker, prized for its extreme speed because it keeps data in memory rather than on disk.** Its name stands for Remote Dictionary Server, and it's one of the most popular tools for making applications fast, handling everything from caching to real-time features. + +This guide explains what Redis is, why it's so fast, how it works, the data structures it supports, what it's used for, and how to get started. It's written for developers who want a complete picture, not just a definition. + +# What does Redis do? + +Redis stores data in memory as key-value pairs and serves it back almost instantly. Where a traditional database reads from disk, Redis keeps its data in RAM, which is dramatically faster. This speed makes Redis ideal for any situation where you need to read or write data very quickly, such as caching frequently used results, storing user sessions, or powering real-time features. + +You can think of Redis as the short-term memory of your application. Your main database is like a filing cabinet, reliable but slower to access. Redis is like the notepad on your desk, where you keep the information you need right now so you can grab it instantly. It complements your primary database rather than replacing it. + +Redis is versatile enough to act as a database, a cache, and a message broker, often all at once, which is why it appears in so many production systems. + +# Why is Redis so fast? + +Redis is fast for two main reasons. First, it stores data **in memory** rather than on disk, and reading from RAM is orders of magnitude quicker than reading from a disk. Second, Redis is built around simple, efficient data structures and operations, and it's single-threaded for command execution, which avoids the overhead of managing concurrent access to the same data. + +The result is that Redis can handle a very large number of operations per second with extremely low latency, often under a millisecond. This is why it's the go-to choice for caching and other speed-critical tasks. The trade-off is that memory is more limited and more expensive than disk, so Redis is used for data that benefits from being fast to access rather than for storing everything. + +# How does Redis work? + +At its core, Redis is a key-value store: every piece of data is associated with a unique key, and you retrieve data by its key. What makes Redis powerful is that the values aren't limited to simple text. They can be rich data structures like lists, sets, and hashes, each with specialized commands. + +Although Redis keeps data in memory for speed, it can also **persist** data to disk so it isn't lost when the server restarts. It offers two main persistence options: point-in-time snapshots (RDB), which save the dataset periodically, and append-only files (AOF), which log every write operation. You can use either, both, or neither depending on how important durability is for your use case. + +Redis also supports replication, clustering, and expiration of keys, which let it scale and automatically clean up temporary data. + +# What data structures does Redis support? + +One of Redis's defining features is its rich set of data structures, which go far beyond simple strings: + +- **Strings**, the most basic type, holding text or numbers. +- **Lists**, ordered collections useful for queues and timelines. +- **Sets**, unordered collections of unique values, great for membership checks. +- **Sorted sets**, sets ordered by a score, ideal for leaderboards and ranking. +- **Hashes**, maps of field-value pairs, perfect for representing objects. +- **Streams, bitmaps, and more**, for specialized use cases like event logs and counters. + +These structures, combined with fast operations on them, are what let Redis power so many different features elegantly. + +# What is Redis used for? + +Redis appears across a wide range of real-world scenarios: + +- **Caching.** Store frequently accessed data or query results to reduce load on your main database and speed up responses. +- **Session storage.** Keep user session data in a fast, shared store accessible across servers. +- **Real-time analytics and counters.** Increment and read counters instantly for things like views or rate limits. +- **Leaderboards and ranking.** Sorted sets make ranking by score fast and simple. +- **Message queues and pub/sub.** Pass messages between parts of a system or broadcast events in real time. +- **Rate limiting.** Track and limit how often an action happens within a time window. + +# Redis vs traditional databases: what's the difference? + +Redis and a traditional database serve different roles, and they often work together rather than competing. A traditional database (relational or document) stores data on disk durably and is designed for complex queries and long-term storage. Redis stores data in memory for speed and is designed for fast, simple access patterns. + +| Aspect | Redis | Traditional database | +| --- | --- | --- | +| Storage | In memory (with optional disk) | On disk | +| Speed | Extremely fast | Slower for reads | +| Data model | Key-value with rich structures | Tables or documents | +| Querying | Simple, key-based | Complex queries | +| Best for | Caching, real-time, sessions | Durable, primary storage | + +In most architectures, Redis sits in front of or alongside a primary database, handling the fast, frequently accessed data while the main database remains the source of truth. + +# Does Redis lose data if it restarts? + +By default, Redis keeps data in memory, so without persistence configured, data would be lost on restart. However, Redis offers persistence options precisely to prevent this. With RDB snapshots, AOF logging, or both enabled, Redis can recover its dataset after a restart. The right choice depends on your needs: pure caching often doesn't need persistence, while using Redis as a primary store for some data calls for durable persistence. Redis also supports replication, keeping copies on other servers for resilience. + +# How to get started with Redis + +Getting hands-on is the fastest way to understand Redis. + +1. **Install Redis locally** or use a managed Redis service, then connect with the `redis-cli` tool. +2. **Try basic commands** like `SET key value` and `GET key` to store and retrieve data. +3. **Experiment with data structures**, such as pushing to a list or adding to a sorted set. +4. **Set an expiry** on a key with `EXPIRE` to see how Redis handles temporary data, the heart of caching. +5. **Integrate Redis into an app** as a cache in front of your database, and measure the speedup. + +Appwrite uses Redis-like technology internally for list caching, while developers can still use Redis alongside Appwrite when their own apps need caching, queues, sessions, or fast temporary data. + +# Redis best practices + +- **Set expiration on cached data** so stale entries clean themselves up and memory stays under control. +- **Choose the right data structure** for each task rather than forcing everything into strings. +- **Plan for memory limits**, since Redis data lives in RAM, and configure an eviction policy. +- **Enable persistence** when you need durability, and replication for resilience. +- **Avoid storing huge values** in single keys, which can hurt performance. +- **Use Redis as a complement** to your primary database, not usually as your only store. + +# Conclusion + +Redis is an in-memory data store that delivers extreme speed by keeping data in memory, making it the go-to tool for caching, sessions, real-time features, and more. Understanding its core pieces, namely the key-value model, the rich data structures it supports, the persistence options that protect data, and how it complements rather than replaces a primary database, gives you the foundation to make applications dramatically faster. Because speed matters in almost every system, Redis is one of the most valuable tools a developer can know. The best way to learn Redis is to install it, run a few commands, and put a cache in front of a real database to feel the difference. + +# Start building + +Appwrite Cloud gives developers a fully managed backend so you can ship fast without provisioning or maintaining any infrastructure. You get Auth, Databases, Storage, Functions, Sites, and Realtime out of the box, scaling automatically as your app grows. Recent releases have added [MongoDB support, Appwrite 1.9.0, realtime upgrades, and new AI tooling](https://dev.to/appwrite/april-product-update-mongodb-support-appwrite-190-realtime-upgrades-and-ai-tooling-1eg6), with [more landing every few weeks](https://dev.to/appwrite/may-product-update-presences-api-rust-runtime-7x-faster-storage-uploads-and-more-9h5). We post weekly roundups of product announcements, AI updates, and [developer insights](https://dev.to/appwrite/weekly-roundup-presences-api-git-deployment-triggers-and-ai-updates-58lj) on the [Appwrite blog](https://appwrite.io/blog) and across our developer channels, so follow along wherever you read. + +Whether you're prototyping your next idea or scaling a production app, Appwrite Cloud gives you a complete backend in one place, with no servers to manage and nothing to set up. [Sign up for Appwrite Cloud](https://cloud.appwrite.io/) and give your next build a real backend to grow on in minutes. + +## Resources + +- [Appwrite documentation](/docs) +- [Appwrite integrations](/integrations) +- [Appwrite quick start guides](/docs/quick-starts) +- [Appwrite on GitHub](https://github.com/appwrite/appwrite) +- [Join the Appwrite Discord](https://appwrite.io/discord) diff --git a/src/routes/changelog/(entries)/2026-06-26.markdoc b/src/routes/changelog/(entries)/2026-06-26.markdoc new file mode 100644 index 00000000000..6d7a9a77b9e --- /dev/null +++ b/src/routes/changelog/(entries)/2026-06-26.markdoc @@ -0,0 +1,14 @@ +--- +layout: changelog +title: 'Announcing the Appwrite React library' +date: 2026-06-26 +cover: /images/blog/announcing-appwrite-react-library/cover.avif +--- + +The **Appwrite React library** is now available. It is primarily made for authentication for now, shipping an `AppwriteProvider` and a small set of hooks (`useAuth`, `useUser`, `useSignIn`, `useSignUp`, `useSignOut`) that handle the boilerplate around session hydration, OAuth, and current user state. + +The Appwrite React library helps with authentication across client-side rendered frameworks and server-side rendered frameworks such as **Next.js** and **TanStack Start**. + +{% arrow_link href="/blog/post/announcing-appwrite-react-library" %} +Read the announcement +{% /arrow_link %} diff --git a/src/routes/changelog/(entries)/2026-06-29.markdoc b/src/routes/changelog/(entries)/2026-06-29.markdoc new file mode 100644 index 00000000000..e4db05efe3e --- /dev/null +++ b/src/routes/changelog/(entries)/2026-06-29.markdoc @@ -0,0 +1,11 @@ +--- +layout: changelog +title: 'Paused free projects are deleted after 90 days' +date: 2026-06-29 +--- + +Starting today, free projects that stay paused for 90 days will be deleted, including all of their resources. Affected projects receive email alerts before anything is deleted. + +Reclaiming resources from long-inactive free projects keeps the platform sustainable, affordable, and reliable for everyone building on Appwrite. Projects on Pro and Enterprise plans are never paused or deleted for inactivity, so your production workloads stay untouched. + +This only applies to projects on free-tier organizations. To keep a paused project, open it in the Appwrite Console to resume it, or upgrade its organization to a paid plan before the 90-day window ends. diff --git a/src/routes/changelog/(entries)/2026-06-30.markdoc b/src/routes/changelog/(entries)/2026-06-30.markdoc new file mode 100644 index 00000000000..b5d147d4b15 --- /dev/null +++ b/src/routes/changelog/(entries)/2026-06-30.markdoc @@ -0,0 +1,27 @@ +--- +layout: changelog +title: Announcing Appwrite 1.9.5 for self-hosted deployments +date: 2026-06-30 +cover: /images/blog/appwrite-1-9-5-self-hosted-release/cover.avif +--- + +After multiple updates and fixes, Appwrite 1.9.5 is now available for self-hosting. + +Most notably, this release includes: + +- Presences API for online, typing, and activity states +- BigInt columns for Databases +- Rust runtime for Functions +- X (formerly Twitter) OAuth support for Auth +- Bun and Deno build runtimes for Sites +- Git deployment triggers for Functions and Sites +- Parallel chunk uploads for faster Storage uploads +- Broader migration coverage for project settings, keys, and integrations + +Head over to our [migration guide](https://appwrite.io/docs/advanced/self-hosting/production/updates) to learn how you can upgrade your Appwrite instance. Please run the [migrate command](https://appwrite.io/docs/advanced/self-hosting/production/updates#running-the-migration) even if you are upgrading from 1.9.0. + +For the complete list of updates and fixes, check out the [release notes](https://github.com/appwrite/appwrite/releases/tag/1.9.5) on GitHub. + +{% arrow_link href="/docs/advanced/self-hosting/production/updates" %} +Upgrade your self-hosted instance +{% /arrow_link %} diff --git a/src/routes/docs/Sidebar.svelte b/src/routes/docs/Sidebar.svelte index c03804aa501..a3334b9bdc1 100644 --- a/src/routes/docs/Sidebar.svelte +++ b/src/routes/docs/Sidebar.svelte @@ -111,10 +111,9 @@ label: 'APIS', items: [ { - label: 'Realtime', - href: '/docs/apis/realtime', - icon: 'icon-clock', - isParent: true + label: 'Overview', + href: '/docs/apis', + icon: 'icon-view-grid' }, { label: 'REST', @@ -125,6 +124,12 @@ label: 'GraphQL', href: '/docs/apis/graphql', icon: 'icon-graphql' + }, + { + label: 'Realtime', + href: '/docs/apis/realtime', + icon: 'icon-clock', + isParent: true } ] }, @@ -152,7 +157,8 @@ { label: 'Command Center', href: '/docs/tooling/command-center', - icon: 'web-icon-command' + icon: 'web-icon-command', + isParent: true }, { label: 'The Appwriter', @@ -165,9 +171,9 @@ label: 'Advanced', items: [ { - label: 'Platform', - href: '/docs/advanced/platform', - icon: 'web-icon-platform', + label: 'Billing', + href: '/docs/advanced/billing', + icon: 'icon-credit-card', isParent: true }, { diff --git a/src/routes/docs/advanced/billing/+layout.svelte b/src/routes/docs/advanced/billing/+layout.svelte new file mode 100644 index 00000000000..bfeff43e6e9 --- /dev/null +++ b/src/routes/docs/advanced/billing/+layout.svelte @@ -0,0 +1,102 @@ + + + + + + diff --git a/src/routes/docs/advanced/billing/+page.markdoc b/src/routes/docs/advanced/billing/+page.markdoc new file mode 100644 index 00000000000..1592f0259e8 --- /dev/null +++ b/src/routes/docs/advanced/billing/+page.markdoc @@ -0,0 +1,93 @@ +--- +layout: article +title: Billing +description: Understand Appwrite's plans, add-ons, service level agreements, and billing policies. +--- + +Learn how to manage billing for your organization, find the plan that best suits your needs, explore optional add-ons, and understand Appwrite's service level agreements and billing policies. + +# Manage billing {% #manage-billing %} + +Configure your organization's plan, payment methods, and spending controls. + +{% cards %} +{% cards_item href="/docs/advanced/billing/payments" title="Manage billing" %} +Manage your plan, billing periods, payment methods, budget caps, and invoices. +{% /cards_item %} +{% /cards %} + +# Plans {% #plans %} + +Learn which plan best suits your organization. + +{% cards %} +{% cards_item href="/docs/advanced/billing/free" title="Free" %} +Learn about Appwrite Free plan. Free plan for hobby projects and learners. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/pro" title="Pro" %} +Learn about Appwrite Pro, for growing organizations that need to scale. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/enterprise" title="Enterprise" %} +Learn about Appwrite Enterprise, for large organizations with advanced needs. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/oss" title="Open source" %} +Appwrite provides special plans for open source projects. +{% /cards_item %} +{% /cards %} + +# Add ons {% #add-ons %} + +Learn about additional features and functionalities that Appwrite offers. + +{% cards %} +{% cards_item href="/docs/advanced/billing/compute" title="Compute" %} +CPU and memory for Functions and Sites, including build and runtime specs. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/phone-otp" title="Phone OTP" %} +Learn how Appwrite handles SMS-based OTP authentication. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/image-transformations" title="Image Transformations" %} +Learn how to transform images dynamically with Appwrite. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/database-reads-and-writes" title="Database Reads and Writes" %} +Learn how Appwrite handles database reads and writes. +{% /cards_item %} +{% /cards %} + +# Service level agreements {% #slas %} + +Understand the service level agreements available on Appwrite's paid plans. + +{% cards %} +{% cards_item href="/docs/advanced/billing/support-sla" title="Support SLA" %} +Learn about Appwrite's support response time commitments. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/uptime-sla" title="Uptime SLA" %} +Learn about Appwrite's uptime commitments. +{% /cards_item %} +{% /cards %} + +# Policies {% #policies %} + +Understand the policies that govern usage and billing on Appwrite. + +{% cards %} +{% cards_item href="/docs/advanced/billing/fair-use-policy" title="Fair use" %} +Understand Appwrite's usage limits, prohibited activities, and enforcement actions. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/abuse" title="Abuse" %} +Guidelines on abusive behavior, prohibited activities, and reporting mechanisms. +{% /cards_item %} + +{% cards_item href="/docs/advanced/billing/refund-policy" title="Refund" %} +Learn about Appwrite's refund policy, eligibility criteria, and request process. +{% /cards_item %} +{% /cards %} diff --git a/src/routes/docs/advanced/platform/abuse/+page.markdoc b/src/routes/docs/advanced/billing/abuse/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/abuse/+page.markdoc rename to src/routes/docs/advanced/billing/abuse/+page.markdoc diff --git a/src/routes/docs/advanced/platform/compute/+page.markdoc b/src/routes/docs/advanced/billing/compute/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/compute/+page.markdoc rename to src/routes/docs/advanced/billing/compute/+page.markdoc diff --git a/src/routes/docs/advanced/platform/database-reads-and-writes/+page.markdoc b/src/routes/docs/advanced/billing/database-reads-and-writes/+page.markdoc similarity index 92% rename from src/routes/docs/advanced/platform/database-reads-and-writes/+page.markdoc rename to src/routes/docs/advanced/billing/database-reads-and-writes/+page.markdoc index a01378c52fc..c33120354ec 100644 --- a/src/routes/docs/advanced/platform/database-reads-and-writes/+page.markdoc +++ b/src/routes/docs/advanced/billing/database-reads-and-writes/+page.markdoc @@ -3,9 +3,6 @@ layout: article title: Database Reads and Writes description: Learn how Appwrite handles database reads and writes and their associated costs. --- -{% info title="Note" %} -Updated pricing will take effect on April 10th, 2025. Check out this [blog post](/blog/post/announcing-database-reads-and-writes-pricing) for more information. -{% /info %} Appwrite provides powerful database capabilities through its [Database API](/docs/products/databases), allowing you to perform read and write operations across your application data. Understanding how these operations are counted and billed is essential for planning your application's scalability. diff --git a/src/routes/docs/advanced/platform/enterprise/+page.markdoc b/src/routes/docs/advanced/billing/enterprise/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/enterprise/+page.markdoc rename to src/routes/docs/advanced/billing/enterprise/+page.markdoc diff --git a/src/routes/docs/advanced/platform/fair-use-policy/+page.markdoc b/src/routes/docs/advanced/billing/fair-use-policy/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/fair-use-policy/+page.markdoc rename to src/routes/docs/advanced/billing/fair-use-policy/+page.markdoc diff --git a/src/routes/docs/advanced/platform/free/+page.markdoc b/src/routes/docs/advanced/billing/free/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/free/+page.markdoc rename to src/routes/docs/advanced/billing/free/+page.markdoc diff --git a/src/routes/docs/advanced/platform/image-transformations/+page.markdoc b/src/routes/docs/advanced/billing/image-transformations/+page.markdoc similarity index 89% rename from src/routes/docs/advanced/platform/image-transformations/+page.markdoc rename to src/routes/docs/advanced/billing/image-transformations/+page.markdoc index e789d372c29..80e219b45ab 100644 --- a/src/routes/docs/advanced/platform/image-transformations/+page.markdoc +++ b/src/routes/docs/advanced/billing/image-transformations/+page.markdoc @@ -4,10 +4,6 @@ title: Image Transformations description: Learn how to transform images using Appwrite's storage API. --- -{% info title="Note" %} -Changes will take effect on April 1st, 2025. Check out this [blog post](/blog/post/announcing-image-transformations-pricing) for more information. -{% /info %} - Appwrite enables the transformation of images before retrieval using the [getFilePreview](/docs/references/cloud/client-web/storage#getFilePreview) endpoint. This functionality supports resizing images by width and height, adjusting quality, and applying filters such as opacity, border colour, border radius, and more. ### Origin Image diff --git a/src/routes/docs/advanced/platform/oss/+page.markdoc b/src/routes/docs/advanced/billing/oss/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/oss/+page.markdoc rename to src/routes/docs/advanced/billing/oss/+page.markdoc diff --git a/src/routes/docs/advanced/platform/billing/+page.markdoc b/src/routes/docs/advanced/billing/payments/+page.markdoc similarity index 99% rename from src/routes/docs/advanced/platform/billing/+page.markdoc rename to src/routes/docs/advanced/billing/payments/+page.markdoc index 43f8c77a578..92e27708111 100644 --- a/src/routes/docs/advanced/platform/billing/+page.markdoc +++ b/src/routes/docs/advanced/billing/payments/+page.markdoc @@ -1,6 +1,6 @@ --- layout: article -title: Billing +title: Manage billing description: Understand Appwrite's billing features, like budget caps, billing periods, taxes, and more. --- diff --git a/src/routes/docs/advanced/platform/phone-otp/+page.markdoc b/src/routes/docs/advanced/billing/phone-otp/+page.markdoc similarity index 98% rename from src/routes/docs/advanced/platform/phone-otp/+page.markdoc rename to src/routes/docs/advanced/billing/phone-otp/+page.markdoc index 620464cca2b..c7449377750 100644 --- a/src/routes/docs/advanced/platform/phone-otp/+page.markdoc +++ b/src/routes/docs/advanced/billing/phone-otp/+page.markdoc @@ -4,10 +4,6 @@ title: Phone OTP description: Learn how Appwrite handles SMS-based OTP authentication for secure user verification. --- -{% info title="Note" %} -Changes will take effect on February 10th, 2025. Check out this [blog post](https://appwrite.io/blog/post/announcing-phone-OTP-pricing) for more information. -{% /info %} - Appwrite supports SMS-based OTP (One-Time Password) authentication to provide secure and reliable user verification. This feature enhances your app's security by adding an extra layer of authentication. # Free testing {% #free-testing %} diff --git a/src/routes/docs/advanced/platform/pro/+page.markdoc b/src/routes/docs/advanced/billing/pro/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/pro/+page.markdoc rename to src/routes/docs/advanced/billing/pro/+page.markdoc diff --git a/src/routes/docs/advanced/platform/refund-policy/+page.markdoc b/src/routes/docs/advanced/billing/refund-policy/+page.markdoc similarity index 97% rename from src/routes/docs/advanced/platform/refund-policy/+page.markdoc rename to src/routes/docs/advanced/billing/refund-policy/+page.markdoc index 18010eadfa8..126ac079c27 100644 --- a/src/routes/docs/advanced/platform/refund-policy/+page.markdoc +++ b/src/routes/docs/advanced/billing/refund-policy/+page.markdoc @@ -44,7 +44,7 @@ The following scenarios do **not** qualify for refunds: - **Incorrect setup or inactivity:** Customer misconfiguration, failure to complete onboarding, or lack of usage - **Expired refund window:** Requests submitted more than 30 days after the transaction date - **Third-party limitations:** Issues caused by third-party tools, plugins, or unsupported integrations -- **Terms of service violations:** Any usage found to be in breach of Appwrite's [Terms](/terms) or [Fair use](/docs/advanced/platform/fair-use-policy) policy +- **Terms of service violations:** Any usage found to be in breach of Appwrite's [Terms](/terms) or [Fair use](/docs/advanced/billing/fair-use-policy) policy # Request process {% #request-process %} diff --git a/src/routes/docs/advanced/platform/support-sla/+page.markdoc b/src/routes/docs/advanced/billing/support-sla/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/support-sla/+page.markdoc rename to src/routes/docs/advanced/billing/support-sla/+page.markdoc diff --git a/src/routes/docs/advanced/platform/uptime-sla/+page.markdoc b/src/routes/docs/advanced/billing/uptime-sla/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/uptime-sla/+page.markdoc rename to src/routes/docs/advanced/billing/uptime-sla/+page.markdoc diff --git a/src/routes/docs/advanced/integration/+layout.svelte b/src/routes/docs/advanced/integration/+layout.svelte deleted file mode 100644 index ff3459764ea..00000000000 --- a/src/routes/docs/advanced/integration/+layout.svelte +++ /dev/null @@ -1,30 +0,0 @@ - - - - - - diff --git a/src/routes/docs/advanced/integration/+page.markdoc b/src/routes/docs/advanced/integration/+page.markdoc deleted file mode 100644 index d08ff00e889..00000000000 --- a/src/routes/docs/advanced/integration/+page.markdoc +++ /dev/null @@ -1,6 +0,0 @@ ---- -layout: article -title: Integration -description: Learn how to use Appwrite Migrations service to move projects from other vendors to Appwrite Cloud or from self-hosting to Cloud and the other way around. ---- -Integration \ No newline at end of file diff --git a/src/routes/docs/advanced/migrations/firebase/+page.markdoc b/src/routes/docs/advanced/migrations/firebase/+page.markdoc index d0eb175d45e..ecfc6322cc5 100644 --- a/src/routes/docs/advanced/migrations/firebase/+page.markdoc +++ b/src/routes/docs/advanced/migrations/firebase/+page.markdoc @@ -56,7 +56,7 @@ To begin migrating to Appwrite, follow these steps. 1. In your Appwrite Console, navigate to **Overview** > **Integrations** > **Platforms**, add the platforms for your Web, Flutter, Android, and iOS apps. Appwrite will reject requests from unknown web, Flutter, and mobile apps to protect from malicious attacks. You app **must be added as a platform** for Appwrite to accept requests. -1. Remember to [add appropriate permissions](/docs/advanced/platform/permissions) to the migrated resources to protect user data and privacy. +1. Remember to [add appropriate permissions](/docs/advanced/security/permissions) to the migrated resources to protect user data and privacy. 1. Migrate functions manually, by [pick a runtime](/docs/products/functions/runtimes) and [learn to develop Appwrite Functions](/docs/products/functions/develop). diff --git a/src/routes/docs/advanced/migrations/nhost/+page.markdoc b/src/routes/docs/advanced/migrations/nhost/+page.markdoc index 66f9a709ddd..9650aabd8a8 100644 --- a/src/routes/docs/advanced/migrations/nhost/+page.markdoc +++ b/src/routes/docs/advanced/migrations/nhost/+page.markdoc @@ -43,7 +43,7 @@ Before migrating to Appwrite make sure you've read the [migration overview](/doc 1. In your Appwrite Console, navigate to **Overview** > **Integrations** > **Platforms**, add the platforms for your Web, Flutter, Android, and iOS apps. Appwrite will reject requests from unknown web, Flutter, and mobile apps to protect from malicious attacks. You app **must be added as a platform** for Appwrite to accept requests. -1. Remember to [add appropriate permissions](/docs/advanced/platform/permissions) to the migrated resources to protect user data and privacy. +1. Remember to [add appropriate permissions](/docs/advanced/security/permissions) to the migrated resources to protect user data and privacy. 1. Migrate functions manually, by [pick a runtime](/docs/products/functions/runtimes) and [learn to develop Appwrite Functions](/docs/products/functions/develop). diff --git a/src/routes/docs/advanced/migrations/supabase/+page.markdoc b/src/routes/docs/advanced/migrations/supabase/+page.markdoc index 8c9fd3628bc..0b715f06cc4 100644 --- a/src/routes/docs/advanced/migrations/supabase/+page.markdoc +++ b/src/routes/docs/advanced/migrations/supabase/+page.markdoc @@ -51,7 +51,7 @@ Before migrating to Appwrite make sure you've read the [migration overview](/doc 1. In your Appwrite Console, navigate to **Overview** > **Integrations** > **Platforms**, add the platforms for your Web, Flutter, Android, and iOS apps. Appwrite will reject requests from unknown web, Flutter, and mobile apps to protect from malicious attacks. You app **must be added as a platform** for Appwrite to accept requests. -1. Remember to [add appropriate permissions](/docs/advanced/platform/permissions) to the migrated resources to protect user data and privacy. +1. Remember to [add appropriate permissions](/docs/advanced/security/permissions) to the migrated resources to protect user data and privacy. 1. Migrate functions manually, by [pick a runtime](/docs/products/functions/runtimes) and [learn to develop Appwrite Functions](/docs/products/functions/develop). diff --git a/src/routes/docs/advanced/platform/+layout.svelte b/src/routes/docs/advanced/platform/+layout.svelte deleted file mode 100644 index 219c63c770e..00000000000 --- a/src/routes/docs/advanced/platform/+layout.svelte +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - diff --git a/src/routes/docs/advanced/platform/+page.markdoc b/src/routes/docs/advanced/platform/+page.markdoc deleted file mode 100644 index d85400548e1..00000000000 --- a/src/routes/docs/advanced/platform/+page.markdoc +++ /dev/null @@ -1,123 +0,0 @@ ---- -layout: article -title: Platform -description: Appwrite is a development platform designed to adapt to your unique use cases. It provides features that help you maintain and scale your application. ---- - -Appwrite is a development platform designed to adapt your unique use cases. -Appwrite provides features that help you maintain, scale, and integrate Appwrite with other platforms. - -# Integration {% #integration %} - -Appwrite is designed to integrate with both frontend and backend apps. -Learn about advanced integrations and API response codes. - -{% cards %} -{% cards_item href="/docs/advanced/platform/events" title="Events" %} -Appwrite allows you to react to events that occur on the platform. -{% /cards_item %} - -{% cards_item href="/docs/advanced/platform/webhooks" title="Webhooks" %} -Use webhooks to update backend integrations about Appwrite events. -{% /cards_item %} - -{% cards_item - href="/docs/advanced/platform/response-codes" - title="Response codes" %} -Learn about response codes and errors returned by Appwrite APIs. -{% /cards_item %} -{% /cards %} - -# Access control {% #access-control %} - -Appwrite is secure by default and provides tools for you to manage -access control and prevent abuse. - -{% cards %} -{% cards_item - href="/docs/advanced/platform/permissions" - title="Permissions" %} -Control which users can access which resources. -{% /cards_item %} - -{% cards_item - href="/docs/advanced/platform/rate-limits" - title="Rate limits" %} -Appwrite has rate limits on some endpoints to prevent abuse. -{% /cards_item %} - -{% cards_item href="/docs/advanced/platform/api-keys" title="API keys" %} -Create and manage API keys used by Server SDKs. -{% /cards_item %} - -{% cards_item href="/docs/advanced/platform/dev-keys" title="Dev keys" %} -Create and manage dev keys used by Client SDKs in dev environments. -{% /cards_item %} -{% /cards %} - -# Plans {% #plans %} - -Learn which plan best suits your organization and how to manage billing. - -{% cards %} -{% cards_item href="/docs/advanced/platform/billing" title="Billing" %} -Learn to manage your billing information. -{% /cards_item %} - -{% cards_item href="/docs/advanced/platform/free" title="Free" %} -Learn about Appwrite Free plan. Free plan for hobby projects and learners. -{% /cards_item %} - -{% cards_item href="/docs/advanced/platform/pro" title="Pro" %} -Learn about Appwrite Pro, for growing organizations that need to scale. -{% /cards_item %} - -{% cards_item href="/docs/advanced/platform/scale" title="Scale" %} -Coming soon. -{% /cards_item %} - -{% cards_item href="/docs/advanced/platform/enterprise" title="Enterprise" %} -Learn about Appwrite Enterprise, for large organizations with advanced needs. -{% /cards_item %} - -{% cards_item href="/docs/advanced/platform/oss" title="Open source" %} -Appwrite provides special plans for open source projects. -{% /cards_item %} -{% /cards %} - -# Configuration {% #configuration %} - -Configure custom domains and customize communication templates. - -{% cards %} -{% cards_item - href="/docs/advanced/platform/custom-domains" - title="Custom domains" %} -Add a custom domain for your Appwrite APIs. -{% /cards_item %} - -{% cards_item - href="/docs/advanced/platform/message-templates" - title="Message templates" %} -Create custom branding and messages when you communicate with users. -{% /cards_item %} -{% /cards %} - -# Add Ons {% #add-ons %} - -Learn about additional features and functionalities that Appwrite offers. - -{% cards %} -{% cards_item href="/docs/advanced/platform/compute" title="Compute" %} -CPU and memory for Functions and Sites, including build and runtime specs. -{% /cards_item %} -{% cards_item href="/docs/advanced/platform/phone-otp" title="Phone OTP" %} -Learn how Appwrite handles SMS-based OTP authentication. -{% /cards_item %} -{% cards_item href="/docs/advanced/platform/image-transformations" title="Image Transformations" %} -Learn how to transform images dynamically with Appwrite. -{% /cards_item %} -{% cards_item href="/docs/advanced/platform/database-reads-and-writes" title="Database Reads and Writes" %} -Learn how Appwrite handles database reads and writes. -{% /cards_item %} -{% /cards %} \ No newline at end of file diff --git a/src/routes/docs/advanced/platform/error-handling/+page.markdoc b/src/routes/docs/advanced/platform/error-handling/+page.markdoc deleted file mode 100644 index 1e6102f9f2e..00000000000 --- a/src/routes/docs/advanced/platform/error-handling/+page.markdoc +++ /dev/null @@ -1,67 +0,0 @@ ---- -layout: article -title: Error handling -description: Best practices for handling Appwrite errors in your applications. Learn how to provide friendly error messages to your users while effectively troubleshooting issues. ---- - -When integrating Appwrite into your applications, proper error handling is important for delivering a good user experience while still being able to troubleshoot issues effectively. - -# Consider user-friendly error messages - -**It's generally best to avoid returning Appwrite's raw error messages directly to your users.** These messages are designed for developers and may contain technical details that: - -- Could confuse non-technical users -- Might expose implementation details -- Often create an inconsistent user experience - -Instead, consider this approach: - -1. Catch errors from Appwrite -2. Identify the error type -3. Return a user-friendly message appropriate for your application - -# Use error types for better handling - -Appwrite returns not just HTTP status codes but also specific error types that provide more precise information about what went wrong. These error types are available in the `type` field of the error response: - -```json -{ - "message": "Invalid credentials. Please check the email and password.", - "type": "user_invalid_credentials", - "code": 401 -} -``` - -By checking the error type rather than just the status code, you can create more precise error handling logic. This approach allows you to: - -- Display contextual error messages based on what actually went wrong -- Implement different recovery strategies for different error types -- Log specific errors for debugging while showing friendly messages to users -- Handle temporary issues (like network problems) differently from permanent ones - -# Common error types and suggested messages - -Here are some examples of how you might map Appwrite error types to user-friendly messages: - -| Error Type | Technical Meaning | User-Friendly Message | -|------------|-------------------|----------------------| -| `user_invalid_credentials` | Invalid credentials. Please check the email and password. | "The email or password you entered is incorrect. Please try again." | -| `user_blocked` | The current user has been blocked. | "Your account has been temporarily suspended. Please contact support." | -| `general_rate_limit_exceeded` | Rate limit for the current endpoint has been exceeded. | "Please wait a moment before trying again." | -| `storage_file_not_found` | The requested file could not be found. | "The file you requested is not available." | -| `row_not_found` | Row with the requested ID could not be found. | "The information you're looking for could not be found." | - -# Complete list of error types - -Appwrite provides a comprehensive list of error types organized by category. For a complete reference, see the [Response codes](/docs/advanced/platform/response-codes#error-types) documentation. - -# Recommended practices - -- **Log the actual errors server-side** for debugging while returning friendly messages to users -- **Handle common error scenarios** with specific user guidance -- **Provide clear next steps** when possible (e.g., "Try resetting your password") -- **Use consistent error message styling** throughout your application -- **Consider different error categories** (validation errors, authentication issues, server problems) -- **Consider implementing retry logic** for transient errors like rate limiting (429) or service unavailability (503) - -By implementing thoughtful error handling, you improve both the user experience of your application and your ability to troubleshoot issues effectively. \ No newline at end of file diff --git a/src/routes/docs/advanced/platform/scale/+page.markdoc b/src/routes/docs/advanced/platform/scale/+page.markdoc deleted file mode 100644 index 3703eac6f6d..00000000000 --- a/src/routes/docs/advanced/platform/scale/+page.markdoc +++ /dev/null @@ -1,9 +0,0 @@ ---- -layout: article -title: Scale -description: Appwrite's Scale plan fully supports scaling your application. ---- - -Appwrite's Scale plan is designed for growing development teams and agencies with many organizational members and large projects. -The plan offers unlimited seats across your organization and dedicated resources per project. -Scale plan organizations will receive additional compliance measures, organization roles, and dedicated support. diff --git a/src/routes/docs/advanced/security/+layout.svelte b/src/routes/docs/advanced/security/+layout.svelte index 7caeaa87a58..a2ae4390282 100644 --- a/src/routes/docs/advanced/security/+layout.svelte +++ b/src/routes/docs/advanced/security/+layout.svelte @@ -82,6 +82,40 @@ href: '/docs/advanced/security/abuse-protection' } ] + }, + { + label: 'Access control', + items: [ + { + label: 'Permissions', + href: '/docs/advanced/security/permissions' + }, + { + label: 'Roles', + href: '/docs/advanced/security/roles' + }, + { + label: 'Rate limits', + href: '/docs/advanced/security/rate-limits' + }, + { + label: 'API keys', + href: '/docs/advanced/security/api-keys' + }, + { + label: 'Dev keys', + href: '/docs/advanced/security/dev-keys' + } + ] + }, + { + label: 'Configuration', + items: [ + { + label: 'Environment variables', + href: '/docs/advanced/security/environment-variables' + } + ] } ]; diff --git a/src/routes/docs/advanced/security/+page.markdoc b/src/routes/docs/advanced/security/+page.markdoc index f3a43824ee9..53173a62f4c 100644 --- a/src/routes/docs/advanced/security/+page.markdoc +++ b/src/routes/docs/advanced/security/+page.markdoc @@ -9,7 +9,7 @@ Appwrite is compliant with [GDPR](/docs/advanced/security/gdpr), [CCPA](/docs/ad [HIPAA](/docs/advanced/security/hipaa), and [SOC 2](/docs/advanced/security/soc2). Appwrite also employs [enhanced password protection and encryption](/docs/products/auth/security), [rate limits](/docs/advanced/security/abuse-protection), -[robust permission systems](/docs/advanced/platform/permissions), and [HTTPS/TLS](/docs/advanced/security/tls) to protect you and your users' data. +[robust permission systems](/docs/advanced/security/permissions), and [HTTPS/TLS](/docs/advanced/security/tls) to protect you and your users' data. # Compliance {% #compliance %} @@ -54,12 +54,17 @@ Appwrite encrypts sensitive data and files in Appwrite Databases and Storage. {% /cards_item %} +{% cards_item href="/docs/advanced/security/mfa" title="Multi-factor authentication" %} +Add a second layer of protection by requiring +users to verify their identity with multiple factors. +{% /cards_item %} + {% cards_item href="/docs/advanced/security/https" title="HTTPS" %} Appwrite Cloud enforces HTTPS on all endpoints to prevent on-path attacks like packet sniffing. {% /cards_item %} -{% cards_item href="/docs/advanced/security/https" title="TLS" %} +{% cards_item href="/docs/advanced/security/tls" title="TLS" %} Appwrite assigns TLS certificates on all Appwrite and user provided domains connected to Appwrite. {% /cards_item %} @@ -86,6 +91,43 @@ like DoS and brute-force attacks. {% /cards %} +# Access control {% #access-control %} + +Appwrite is secure by default and provides tools for you to manage +access control and prevent abuse. + +{% cards %} +{% cards_item href="/docs/advanced/security/permissions" title="Permissions" %} +Control which users can access which resources. +{% /cards_item %} + +{% cards_item href="/docs/advanced/security/roles" title="Roles" %} +Learn about Console organization member roles and the access each one grants. +{% /cards_item %} + +{% cards_item href="/docs/advanced/security/rate-limits" title="Rate limits" %} +Appwrite has rate limits on some endpoints to prevent abuse. +{% /cards_item %} + +{% cards_item href="/docs/advanced/security/api-keys" title="API keys" %} +Create and manage API keys used by Server SDKs. +{% /cards_item %} + +{% cards_item href="/docs/advanced/security/dev-keys" title="Dev keys" %} +Create and manage dev keys used by Client SDKs in dev environments. +{% /cards_item %} +{% /cards %} + +# Configuration {% #configuration %} + +Pass constants and secrets to your Appwrite resources. + +{% cards %} +{% cards_item href="/docs/advanced/security/environment-variables" title="Environment variables" %} +Use project, function, and site environment variables to pass constants and secrets to your Functions and Sites. +{% /cards_item %} +{% /cards %} + # Reporting vulnerabilities {% #reporting-vulnerabilities %} If you discover security vulnerabilities, please contact us at security@appwrite.io. Please avoid **posting a public issue** on GitHub or elsewhere online to prevent malicious actors diff --git a/src/routes/docs/advanced/security/abuse-protection/+page.markdoc b/src/routes/docs/advanced/security/abuse-protection/+page.markdoc index d44dc44992a..95063ed3874 100644 --- a/src/routes/docs/advanced/security/abuse-protection/+page.markdoc +++ b/src/routes/docs/advanced/security/abuse-protection/+page.markdoc @@ -14,7 +14,7 @@ Rate limits limit the number of requests a user or IP can make against an API wi Rate limits help protect against brute force attacks against authentication endpoints and other forms of API abuse like [denial of service attacks](https://en.wikipedia.org/wiki/Denial-of-service_attack). -{% arrow_link href="/docs/advanced/platform/rate-limits" %} +{% arrow_link href="/docs/advanced/security/rate-limits" %} Learn more about rate limits {% /arrow_link %} diff --git a/src/routes/docs/advanced/platform/api-keys/+page.markdoc b/src/routes/docs/advanced/security/api-keys/+page.markdoc similarity index 99% rename from src/routes/docs/advanced/platform/api-keys/+page.markdoc rename to src/routes/docs/advanced/security/api-keys/+page.markdoc index 544159552ef..f3ff9924f88 100644 --- a/src/routes/docs/advanced/platform/api-keys/+page.markdoc +++ b/src/routes/docs/advanced/security/api-keys/+page.markdoc @@ -14,7 +14,7 @@ API keys should be treated as a secret. Never share the API key and keep API key # API keys vs Dev keys {% #api-keys-vs-dev-keys %} -API keys and [Dev keys](/docs/advanced/platform/dev-keys) are not the same and cannot be used interchangeably. +API keys and [Dev keys](/docs/advanced/security/dev-keys) are not the same and cannot be used interchangeably. API keys permit access to Appwrite services in production environments, with access controlled through scopes to ensure secure and controlled server-side operations. Dev keys, conversely, are specifically designed to help you avoid abuse limits and CORS errors in test and development environments. diff --git a/src/routes/docs/advanced/security/audit-logs/+page.markdoc b/src/routes/docs/advanced/security/audit-logs/+page.markdoc index 342758fddc4..4499f50f9a8 100644 --- a/src/routes/docs/advanced/security/audit-logs/+page.markdoc +++ b/src/routes/docs/advanced/security/audit-logs/+page.markdoc @@ -36,7 +36,7 @@ Each entry describes an event. - Name of the user that performed the event. --- - Event -- The name of the [event](/docs/advanced/platform/events). +- The name of the [event](/docs/apis/events). --- - Location - The physical of the user when they performed the action. diff --git a/src/routes/docs/advanced/platform/dev-keys/+page.markdoc b/src/routes/docs/advanced/security/dev-keys/+page.markdoc similarity index 93% rename from src/routes/docs/advanced/platform/dev-keys/+page.markdoc rename to src/routes/docs/advanced/security/dev-keys/+page.markdoc index b19590abb3b..5ebeec94b2a 100644 --- a/src/routes/docs/advanced/platform/dev-keys/+page.markdoc +++ b/src/routes/docs/advanced/security/dev-keys/+page.markdoc @@ -4,6 +4,10 @@ title: Dev keys description: Bypass Appwrite rate limits and CORS errors in your development environment with Appwrite Dev keys. --- +{% info title="Deprecation notice" %} +Dev keys are going to be deprecated on September 1, 2026. We recommend planning your migration away from dev keys ahead of time. +{% /info %} + Dev keys are secrets used by Appwrite [Client SDKs](/docs/sdks#client) to avoid abuse limits in testing. They are meant to be used specifically in development environments, where they hold several developer experience-related benefits: - Appwrite rate limits and CORS errors are bypassed @@ -17,7 +21,7 @@ Dev keys should never be used in production environments, only in development en # Dev keys vs API keys {% #dev-keys-vs-api-keys %} -Dev keys and [API keys](/docs/advanced/platform/api-keys) are not the same and cannot be used interchangeably. +Dev keys and [API keys](/docs/advanced/security/api-keys) are not the same and cannot be used interchangeably. Dev keys are specifically designed to help you avoid abuse limits and CORS errors in test environments, making them ideal for development and testing workflows. API keys, on the other hand, permit usage of Appwrite services in production environments with fine-grained scope control. diff --git a/src/routes/docs/advanced/platform/environment-variables/+page.markdoc b/src/routes/docs/advanced/security/environment-variables/+page.markdoc similarity index 99% rename from src/routes/docs/advanced/platform/environment-variables/+page.markdoc rename to src/routes/docs/advanced/security/environment-variables/+page.markdoc index c61134bc0cb..55542191a91 100644 --- a/src/routes/docs/advanced/platform/environment-variables/+page.markdoc +++ b/src/routes/docs/advanced/security/environment-variables/+page.markdoc @@ -52,7 +52,7 @@ You can create and manage project variables from the Appwrite Console. The Conso # Manage with a Server SDK {% #server-sdks %} -You can also manage project variables programmatically using a [Server SDK](/docs/sdks#server). Each call requires an [API key](/docs/advanced/platform/api-keys) with the `project.write` scope to create, update, or delete variables, or the `project.read` scope to list and read them. +You can also manage project variables programmatically using a [Server SDK](/docs/sdks#server). Each call requires an [API key](/docs/advanced/security/api-keys) with the `project.write` scope to create, update, or delete variables, or the `project.read` scope to list and read them. ## Create a variable {% #create-variable %} diff --git a/src/routes/docs/advanced/security/https/+page.markdoc b/src/routes/docs/advanced/security/https/+page.markdoc index e33da7b7669..44602ebcd37 100644 --- a/src/routes/docs/advanced/security/https/+page.markdoc +++ b/src/routes/docs/advanced/security/https/+page.markdoc @@ -25,7 +25,7 @@ man-in-the-middle attacks such as protocol downgrade attacks and cookie hijackin By enforcing HTTPS, Appwrite Cloud's endpoint will always be served over a secure connection, which helps protect users' data and privacy. # Custom domains {% #custom-domains %} -You can add a [custom domain](/docs/advanced/platform/custom-domains) to your Appwrite project so you can access Appwrite API endpoints +You can add a [custom domain](/docs/products/network/custom-domains) to your Appwrite project so you can access Appwrite API endpoints on your own domain. Appwrite will [generate TLS certificates](/docs/advanced/security/tls) for your domain and enforce HTTPS communication. # Function domains {% #function-domains %} diff --git a/src/routes/docs/advanced/security/mfa/+page.markdoc b/src/routes/docs/advanced/security/mfa/+page.markdoc index bda35532ff8..d9c4d450fc3 100644 --- a/src/routes/docs/advanced/security/mfa/+page.markdoc +++ b/src/routes/docs/advanced/security/mfa/+page.markdoc @@ -10,7 +10,7 @@ More factors of authentication will be added in the future. {% info title="Looking to add MFA to your app?" %} This page covers MFA for your Appwrite Console account. -If you're looking to add MFA to your app, follow the [Multi-factor authentication journey](/docs/products/auth/mfa). +If you're looking to add MFA to your app, follow the [Multi-factor authentication guide](/docs/products/auth/mfa). {% /info %} # Enable MFA {% #enable-mfa %} diff --git a/src/routes/docs/advanced/platform/permissions/+page.markdoc b/src/routes/docs/advanced/security/permissions/+page.markdoc similarity index 99% rename from src/routes/docs/advanced/platform/permissions/+page.markdoc rename to src/routes/docs/advanced/security/permissions/+page.markdoc index e0b2d1c12f1..c6b289345ab 100644 --- a/src/routes/docs/advanced/platform/permissions/+page.markdoc +++ b/src/routes/docs/advanced/security/permissions/+page.markdoc @@ -26,7 +26,7 @@ If you create a resource using a Server SDK or the Appwrite Console without expl # Server integration {% #server-integration %} -Server integrations can be used for increased flexibility. When using a Server SDK in combination with the proper [API key scopes](/docs/advanced/platform/api-keys#scopes), you can have any type of access to any of your project resources regardless of their permissions. +Server integrations can be used for increased flexibility. When using a Server SDK in combination with the proper [API key scopes](/docs/advanced/security/api-keys#scopes), you can have any type of access to any of your project resources regardless of their permissions. Using the server integration flexibility, you can change resource permissions, share resources between different users and teams, or edit and delete them without any limitations. diff --git a/src/routes/docs/advanced/platform/rate-limits/+page.markdoc b/src/routes/docs/advanced/security/rate-limits/+page.markdoc similarity index 98% rename from src/routes/docs/advanced/platform/rate-limits/+page.markdoc rename to src/routes/docs/advanced/security/rate-limits/+page.markdoc index 256e0529dad..337fc15c82f 100644 --- a/src/routes/docs/advanced/platform/rate-limits/+page.markdoc +++ b/src/routes/docs/advanced/security/rate-limits/+page.markdoc @@ -52,7 +52,7 @@ X-RateLimit-Reset: 1377013266 # Dev keys {% #dev-keys %} -Rate limits are necessary to protect your apps and users from abuse; however, they can sometimes add unwanted friction when a developer is trying to repeatedly consume certain Appwrite APIs to test their application in a short period. [Dev keys](/docs/advanced/platform/dev-keys) are a type of secret used by client apps to bypass these rate limits in development environments. +Rate limits are necessary to protect your apps and users from abuse; however, they can sometimes add unwanted friction when a developer is trying to repeatedly consume certain Appwrite APIs to test their application in a short period. [Dev keys](/docs/advanced/security/dev-keys) are a type of secret used by client apps to bypass these rate limits in development environments. To use dev keys, client apps add a header `X-Appwrite-Dev-Key` containing the secret to all HTTP requests sent to the Appwrite API. Appwrite recognizes this header, verifies the secret, and if valid, allows the request to bypass the rate limit. diff --git a/src/routes/docs/advanced/platform/roles/+page.markdoc b/src/routes/docs/advanced/security/roles/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/roles/+page.markdoc rename to src/routes/docs/advanced/security/roles/+page.markdoc diff --git a/src/routes/docs/advanced/security/tls/+page.markdoc b/src/routes/docs/advanced/security/tls/+page.markdoc index b0c21bdee10..31eeee2347a 100644 --- a/src/routes/docs/advanced/security/tls/+page.markdoc +++ b/src/routes/docs/advanced/security/tls/+page.markdoc @@ -11,7 +11,7 @@ Appwrite generates TLS certificates to ensure your API traffic is appropriately TLS certificates are generated for all of the following. - Appwrite products and endpoints, like Databases, Storage, Authentication, Functions, Messaging, and all other endpoints. -- [Custom domains](/docs/advanced/platform/custom-domains) that you configure for your Appwrite projects. +- [Custom domains](/docs/products/network/custom-domains) that you configure for your Appwrite projects. - [Domains for Appwrite Functions](/docs/products/functions/domains), generated or user provided. - [Domains for Appwrite Sites](/docs/products/sites/domains), generated or user provided. diff --git a/src/routes/docs/advanced/self-hosting/configuration/databases/+page.markdoc b/src/routes/docs/advanced/self-hosting/configuration/databases/+page.markdoc index 0b727908090..0ed79387d0a 100644 --- a/src/routes/docs/advanced/self-hosting/configuration/databases/+page.markdoc +++ b/src/routes/docs/advanced/self-hosting/configuration/databases/+page.markdoc @@ -23,7 +23,7 @@ docker run -it --rm \ --volume /var/run/docker.sock:/var/run/docker.sock \ --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ --entrypoint="install" \ - appwrite/appwrite:1.9.0 \ + appwrite/appwrite:1.9.5 \ --database=mongodb ``` {% /tabsitem %} @@ -34,7 +34,7 @@ docker run -it --rm ^ --volume //var/run/docker.sock:/var/run/docker.sock ^ --volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^ --entrypoint="install" ^ - appwrite/appwrite:1.9.0 ^ + appwrite/appwrite:1.9.5 ^ --database=mongodb ``` {% /tabsitem %} @@ -45,7 +45,7 @@ docker run -it --rm ` --volume /var/run/docker.sock:/var/run/docker.sock ` --volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ` --entrypoint="install" ` - appwrite/appwrite:1.9.0 ` + appwrite/appwrite:1.9.5 ` --database=mongodb ``` {% /tabsitem %} diff --git a/src/routes/docs/advanced/self-hosting/installation/+page.markdoc b/src/routes/docs/advanced/self-hosting/installation/+page.markdoc index 0d2ea67dfa7..c3327f8c4ba 100644 --- a/src/routes/docs/advanced/self-hosting/installation/+page.markdoc +++ b/src/routes/docs/advanced/self-hosting/installation/+page.markdoc @@ -38,7 +38,7 @@ docker run -it --rm \ --volume /var/run/docker.sock:/var/run/docker.sock \ --volume "$(pwd)"/appwrite:/usr/src/code/appwrite:rw \ --entrypoint="install" \ - appwrite/appwrite:1.9.0 + appwrite/appwrite:1.9.5 ``` {% /tabsitem %} @@ -49,7 +49,7 @@ docker run -it --rm ^ --volume //var/run/docker.sock:/var/run/docker.sock ^ --volume "%cd%"/appwrite:/usr/src/code/appwrite:rw ^ --entrypoint="install" ^ - appwrite/appwrite:1.9.0 + appwrite/appwrite:1.9.5 ``` {% /tabsitem %} @@ -60,7 +60,7 @@ docker run -it --rm ` --volume /var/run/docker.sock:/var/run/docker.sock ` --volume ${pwd}/appwrite:/usr/src/code/appwrite:rw ` --entrypoint="install" ` - appwrite/appwrite:1.9.0 + appwrite/appwrite:1.9.5 ``` {% /tabsitem %} {% /tabs %} @@ -156,7 +156,7 @@ On non-Linux hosts, the server might take a few minutes to start after installat ## SDK version compatibility {% #sdk-version-compatibility %} -The tables below map each released self-hosted Appwrite version to the SDK versions that were current at the time of that release. Use this to pin your SDK to a version known to work with your server. The latest stable self-hosted Appwrite release is 1.9.0. +The tables below map each released self-hosted Appwrite version to the SDK versions that were current at the time of that release. Use this to pin your SDK to a version known to work with your server. The latest stable self-hosted Appwrite release is 1.9.5. ### Client SDKs {% #client-compatibility %} @@ -216,6 +216,13 @@ The tables below map each released self-hosted Appwrite version to the SDK versi * 0.27.1 * 16.0.0 * 14.1.0 +--- +* 1.9.5 +* 26.1.0 +* 25.2.0 +* 0.33.0 +* 18.2.0 +* 25.2.0 {% /table %} ### Server SDKs {% #server-compatibility %} @@ -316,6 +323,18 @@ The tables below map each released self-hosted Appwrite version to the SDK versi * 16.0.0 * 15.0.0 * 17.4.0 +--- +* 1.9.5 +* 26.2.0 +* 21.0.0 +* 26.1.0 +* 25.1.0 +* 25.1.0 +* 5.1.0 +* v5.1.0 +* 19.1.0 +* 18.1.0 +* 22.3.0 {% /table %} # Managing your installation {% #managing-installation %} diff --git a/src/routes/docs/advanced/self-hosting/production/debugging/+page.markdoc b/src/routes/docs/advanced/self-hosting/production/debugging/+page.markdoc index e846a71384c..aedbf6005c3 100644 --- a/src/routes/docs/advanced/self-hosting/production/debugging/+page.markdoc +++ b/src/routes/docs/advanced/self-hosting/production/debugging/+page.markdoc @@ -34,7 +34,7 @@ docker logs [CONTAINER-ID] Appwrite uses conventional HTTP response codes to indicate the success or failure of an API request. In general: Codes in the 2xx range indicate success. Codes in the 4xx range indicate an error that failed given the information provided (e.g., a required parameter was omitted, invalid input, etc.). Codes in the 5xx range indicate an error with the Appwrite server, but these are rare. -{% arrow_link href="/docs/advanced/platform/response-codes" %} +{% arrow_link href="/docs/apis/response-codes" %} Learn more about Appwrite status codes {% /arrow_link %} diff --git a/src/routes/docs/advanced/self-hosting/production/rate-limits/+page.markdoc b/src/routes/docs/advanced/self-hosting/production/rate-limits/+page.markdoc index 97fc1aa4358..9a33e9c3054 100644 --- a/src/routes/docs/advanced/self-hosting/production/rate-limits/+page.markdoc +++ b/src/routes/docs/advanced/self-hosting/production/rate-limits/+page.markdoc @@ -15,7 +15,7 @@ Rate limits in self-hosted Appwrite apply differently depending on how you're ac - **Client SDKs**: Rate limits apply to all requests from client applications - **Server SDKs with API keys**: Rate limits do not apply when using API keys -{% arrow_link href="/docs/advanced/platform/rate-limits" %} +{% arrow_link href="/docs/advanced/security/rate-limits" %} Learn more about how rate limits work {% /arrow_link %} diff --git a/src/routes/docs/apis/(overview)/+layout.svelte b/src/routes/docs/apis/(overview)/+layout.svelte new file mode 100644 index 00000000000..2416c16742b --- /dev/null +++ b/src/routes/docs/apis/(overview)/+layout.svelte @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/routes/docs/apis/(overview)/+page.markdoc b/src/routes/docs/apis/(overview)/+page.markdoc new file mode 100644 index 00000000000..ac618796e2d --- /dev/null +++ b/src/routes/docs/apis/(overview)/+page.markdoc @@ -0,0 +1,48 @@ +--- +layout: article +title: APIs +description: Explore the ways to talk to Appwrite. Access every service through the REST and GraphQL APIs, subscribe to changes in Realtime, and react to events with webhooks. +--- + +Every Appwrite service is available through a consistent set of APIs. You can call them directly over [REST](/docs/apis/rest) or [GraphQL](/docs/apis/graphql), subscribe to changes in [Realtime](/docs/apis/realtime), or react to changes using [events](/docs/apis/events) and [webhooks](/docs/apis/webhooks). + +Most applications don't call these APIs by hand. Instead, use one of the official [SDKs](/docs/sdks), which wrap every endpoint for your language and platform, and browse the [API reference](/docs/references) for the full list of services and methods. The pages below describe the underlying protocols and conventions for when you need to integrate directly. + +# Protocols {% #protocols %} + +Choose the protocol that fits your use case. REST and GraphQL cover the same endpoints, while Realtime delivers updates as they happen. + +{% cards %} +{% cards_item href="/docs/apis/rest" title="REST" %} +Access every Appwrite endpoint over HTTP without an SDK, including authentication, file uploads, queries, and permissions. +{% /cards_item %} +{% cards_item href="/docs/apis/graphql" title="GraphQL" %} +Query and mutate your data through a single GraphQL endpoint. +{% /cards_item %} +{% cards_item href="/docs/apis/realtime" title="Realtime" %} +Subscribe to channels and receive updates over WebSockets the moment your data changes. +{% /cards_item %} +{% /cards %} + +# Event-driven workflows {% #event-driven-workflows %} + +React to project changes with events emitted by Appwrite and webhooks delivered to your own endpoints. + +{% cards %} +{% cards_item href="/docs/apis/events" title="Events" %} +The full list of events Appwrite emits so you can react to changes across your project. +{% /cards_item %} +{% cards_item href="/docs/apis/webhooks" title="Webhooks" %} +Trigger external workflows by delivering events to your own HTTP endpoints. +{% /cards_item %} +{% /cards %} + +# API responses {% #api-responses %} + +Understand the responses Appwrite returns and handle errors so your application can recover gracefully. + +{% cards %} +{% cards_item href="/docs/apis/response-codes" title="Response codes" %} +HTTP status codes, error types, and patterns for handling errors gracefully in your application. +{% /cards_item %} +{% /cards %} diff --git a/src/routes/docs/apis/Sidebar.svelte b/src/routes/docs/apis/Sidebar.svelte new file mode 100644 index 00000000000..ff13fb2fa77 --- /dev/null +++ b/src/routes/docs/apis/Sidebar.svelte @@ -0,0 +1,66 @@ + + + diff --git a/src/routes/docs/apis/events/+layout.svelte b/src/routes/docs/apis/events/+layout.svelte new file mode 100644 index 00000000000..2416c16742b --- /dev/null +++ b/src/routes/docs/apis/events/+layout.svelte @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/routes/docs/advanced/platform/events/+page.markdoc b/src/routes/docs/apis/events/+page.markdoc similarity index 98% rename from src/routes/docs/advanced/platform/events/+page.markdoc rename to src/routes/docs/apis/events/+page.markdoc index 6adfccac4e2..a4604f5847f 100644 --- a/src/routes/docs/advanced/platform/events/+page.markdoc +++ b/src/routes/docs/apis/events/+page.markdoc @@ -6,7 +6,7 @@ description: Harness the power of events in Appwrite. Explore event-driven archi Appwrite provides a variety of events that allows your application to react to changes as they happen. An event will fire when a change occurs in your Appwrite project, like when a new user registers or a new file is uploaded to Appwrite. -You can subscribe to these events with Appwrite [Functions](/docs/products/functions), [Realtime](/docs/apis/realtime), or [Webhooks](/docs/advanced/platform/webhooks). +You can subscribe to these events with Appwrite [Functions](/docs/products/functions), [Realtime](/docs/apis/realtime), or [Webhooks](/docs/apis/webhooks). You can subscribe to events for specific resources using their ID or subscribe to changes of all resources of the same type by using a wildcard character * instead of an ID. You can also filter for events of specific actions like create, update, upsert, or delete. diff --git a/src/routes/docs/apis/graphql/+layout.svelte b/src/routes/docs/apis/graphql/+layout.svelte index 93e22c8cebf..2416c16742b 100644 --- a/src/routes/docs/apis/graphql/+layout.svelte +++ b/src/routes/docs/apis/graphql/+layout.svelte @@ -1,6 +1,6 @@ diff --git a/src/routes/docs/apis/realtime/+layout.svelte b/src/routes/docs/apis/realtime/+layout.svelte index 31a59557e7e..28c8c64edfb 100644 --- a/src/routes/docs/apis/realtime/+layout.svelte +++ b/src/routes/docs/apis/realtime/+layout.svelte @@ -4,7 +4,7 @@ import { isNewUntil } from '$lib/utils/date'; const parent: NavParent = { - href: '/docs', + href: '/docs/apis', label: 'Realtime' }; diff --git a/src/routes/docs/apis/realtime/+page.markdoc b/src/routes/docs/apis/realtime/+page.markdoc index 00539e3010f..f57020ef502 100644 --- a/src/routes/docs/apis/realtime/+page.markdoc +++ b/src/routes/docs/apis/realtime/+page.markdoc @@ -116,10 +116,10 @@ To subscribe to updates from different Appwrite resources, you need to specify o If you subscribe to a channel, you will receive callbacks for a variety of events related to the channel. The events column in the callback can be used to filter and respond to specific events in a channel. -[View a list of all available events](/docs/advanced/platform/events). +[View a list of all available events](/docs/apis/events). {% info title="Permissions" %} -All subscriptions are secured by the [permissions system](/docs/advanced/platform/permissions) offered by Appwrite, meaning a user will only receive updates to resources they have permission to access. +All subscriptions are secured by the [permissions system](/docs/advanced/security/permissions) offered by Appwrite, meaning a user will only receive updates to resources they have permission to access. Using `Role.any()` on read permissions will allow any client to receive updates. {% /info %} diff --git a/src/routes/docs/apis/realtime/authentication/+page.markdoc b/src/routes/docs/apis/realtime/authentication/+page.markdoc index 15bf09155ad..7e1fcbe0506 100644 --- a/src/routes/docs/apis/realtime/authentication/+page.markdoc +++ b/src/routes/docs/apis/realtime/authentication/+page.markdoc @@ -9,7 +9,7 @@ Realtime authenticates using an existing user session. If you authenticate **aft More information and examples of authenticating users can be found in the dedicated [authentication docs](/docs/products/auth). {% info title="Permissions" %} -All subscriptions are secured by the [permissions system](/docs/advanced/platform/permissions) offered by Appwrite, meaning a user will only receive updates to resources they have permission to access. +All subscriptions are secured by the [permissions system](/docs/advanced/security/permissions) offered by Appwrite, meaning a user will only receive updates to resources they have permission to access. Using `Role.any()` on read permissions will allow any client to receive updates. {% /info %} diff --git a/src/routes/docs/apis/realtime/payload/+page.markdoc b/src/routes/docs/apis/realtime/payload/+page.markdoc index 37489cdc7b1..72d37f463cf 100644 --- a/src/routes/docs/apis/realtime/payload/+page.markdoc +++ b/src/routes/docs/apis/realtime/payload/+page.markdoc @@ -17,7 +17,7 @@ The payload from the subscription will contain the following properties: --- * events * string[] -* The [Appwrite events](/docs/advanced/platform/events) that triggered this update. +* The [Appwrite events](/docs/apis/events) that triggered this update. --- * channels * string[] diff --git a/src/routes/docs/apis/realtime/presences/+page.markdoc b/src/routes/docs/apis/realtime/presences/+page.markdoc index 1b5153a64d9..94915ef15ed 100644 --- a/src/routes/docs/apis/realtime/presences/+page.markdoc +++ b/src/routes/docs/apis/realtime/presences/+page.markdoc @@ -115,7 +115,7 @@ The SDK remembers the latest payload and re-sends it after a reconnect, so a bri # Upsert a presence {% #upsert-a-presence %} -`upsert` creates a presence or updates the existing record with the same `presenceId`. Call it on every page navigation, focus change, or heartbeat without worrying about duplicates. From a client session, `userId` is inferred from the signed-in user; from a server SDK with an API key, pass `userId` explicitly. Server SDKs need an [API key](/docs/advanced/platform/api-keys) with the `presences.write` scope. +`upsert` creates a presence or updates the existing record with the same `presenceId`. Call it on every page navigation, focus change, or heartbeat without worrying about duplicates. From a client session, `userId` is inferred from the signed-in user; from a server SDK with an API key, pass `userId` explicitly. Server SDKs need an [API key](/docs/advanced/security/api-keys) with the `presences.write` scope. {% multicode %} ```client-web @@ -1578,7 +1578,7 @@ async fn main() -> Result<(), Box> { # Subscribe to presence updates {% #subscribe-to-presence-updates %} -Presence is most useful when other clients can react to it live. Use the `Channel.presences()` helper to subscribe to the global presences channel, or `Channel.presence('')` to follow a single record. All Realtime subscriptions are gated by the [permissions system](/docs/advanced/platform/permissions), so a client will only receive updates for presences it has permission to read. +Presence is most useful when other clients can react to it live. Use the `Channel.presences()` helper to subscribe to the global presences channel, or `Channel.presence('')` to follow a single record. All Realtime subscriptions are gated by the [permissions system](/docs/advanced/security/permissions), so a client will only receive updates for presences it has permission to read. {% multicode %} ```client-web @@ -1781,7 +1781,7 @@ To remove a presence immediately, for example on sign out or when the user close # Permissions and scopes {% #permissions-and-scopes %} -Presences use the standard Appwrite [permissions system](/docs/advanced/platform/permissions). Set read permissions on a presence to control who can subscribe to it: +Presences use the standard Appwrite [permissions system](/docs/advanced/security/permissions). Set read permissions on a presence to control who can subscribe to it: - `Role.any()` makes the presence visible to anyone, including unauthenticated visitors. - `Role.users()` restricts visibility to signed-in users. diff --git a/src/routes/docs/apis/release-policy/+layout.svelte b/src/routes/docs/apis/release-policy/+layout.svelte new file mode 100644 index 00000000000..2416c16742b --- /dev/null +++ b/src/routes/docs/apis/release-policy/+layout.svelte @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/routes/docs/advanced/platform/release-policy/+page.markdoc b/src/routes/docs/apis/release-policy/+page.markdoc similarity index 99% rename from src/routes/docs/advanced/platform/release-policy/+page.markdoc rename to src/routes/docs/apis/release-policy/+page.markdoc index 3c1c9efbbe2..c39ac872fa6 100644 --- a/src/routes/docs/advanced/platform/release-policy/+page.markdoc +++ b/src/routes/docs/apis/release-policy/+page.markdoc @@ -79,7 +79,7 @@ Self-hosted versions of Appwrite will receive continued support for the latest m If you need **extended support** for older versions of Appwrite, [contact us](/contact-us) for more information. -# SDK versioning {% #sdk-verversioningsions %} +# SDK versioning {% #sdk-versioning %} For our different SDKs, we follow the Semantic Versioning (semver) protocol to assign versions to our releases. This means that we assign version numbers using a three-part system: major, minor, and patch. The major version changes when we make significant changes to our API or product, which may require significant changes to developers' code. The minor version changes when we add new features or functionality that do not significantly impact developers' systems. Finally, the patch version changes when we make bug fixes or minor improvements. diff --git a/src/routes/docs/apis/response-codes/+layout.svelte b/src/routes/docs/apis/response-codes/+layout.svelte new file mode 100644 index 00000000000..2416c16742b --- /dev/null +++ b/src/routes/docs/apis/response-codes/+layout.svelte @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/routes/docs/advanced/platform/response-codes/+page.markdoc b/src/routes/docs/apis/response-codes/+page.markdoc similarity index 91% rename from src/routes/docs/advanced/platform/response-codes/+page.markdoc rename to src/routes/docs/apis/response-codes/+page.markdoc index e46772d8faf..0626c12f269 100644 --- a/src/routes/docs/advanced/platform/response-codes/+page.markdoc +++ b/src/routes/docs/apis/response-codes/+page.markdoc @@ -1,7 +1,7 @@ --- layout: article title: Response codes -description: Understand Appwrite platform response codes for effective error handling. Learn how to interpret and handle response codes to enhance your application's reliability. +description: Understand Appwrite platform response codes and error handling. Learn to interpret HTTP status codes, error types, and implement best practices for handling errors gracefully. --- Appwrite uses conventional HTTP response codes to indicate the success or failure of an API request. @@ -26,7 +26,7 @@ Appwrite uses conventional HTTP response codes to indicate the success or failur | 409 | Conflict | This response is sent when a request conflicts with the current state of the server. This status code will usually appear when you're trying to create an already existing resource. | | 413 | Payload Too Large | This indicates that the request entity is larger than limits defined by server. This status code will usually appear happen when uploading a file or function that is too large | | 416 | Invalid Range | Invalid value in the range or content-range headers. Usually returned while uploading or downloading files using the range header but the provided range value is not valid. | -| 429 | Too Many Requests | Returned in when a request cannot be served due to the application's rate limit having been exhausted for the resource. See [Rate Limits](/docs/advanced/platform/rate-limits). | +| 429 | Too Many Requests | Returned in when a request cannot be served due to the application's rate limit having been exhausted for the resource. See [Rate Limits](/docs/advanced/security/rate-limits). | | 500 | Internal Server Error | Something is broken. Contact our [team](/support), or raise a [GitHub issue](https://github.com/appwrite/appwrite/issues/new). | | 501 | Not Implemented | The feature is not implemented. Usually returned when the project owner has disabled an auth method or an entire service. | | 503 | Service Unavailable | The Appwrite servers are up but overloaded with requests. Try again later. | @@ -226,4 +226,29 @@ Errors from the Appwrite GraphQL API. | Code | Type | Description | | ---- | ---- | ----------- | | 400 | graphql_no_query | Param "query" is not optional. | -| 400 | graphql_too_many_queries | Too many queries. | \ No newline at end of file +| 400 | graphql_too_many_queries | Too many queries. | + +# Error handling {% #error-handling %} + +The response codes and [error types](#error-types) above are the building blocks for handling errors. The practices below help you turn them into a recoverable, user-friendly experience. + +## Return user-friendly messages {% #user-friendly-messages %} + +Avoid surfacing Appwrite's raw error messages directly to your users. They're written for developers and can expose implementation details or confuse non-technical users. Instead, catch the error, inspect its `type`, and map it to a message that fits your application. + +The `type` field is more specific than the HTTP status code, so it lets you respond precisely: a `400` can mean many things, but `user_invalid_credentials` means exactly one. Matching on `type` also lets you treat a transient error like `general_rate_limit_exceeded` differently from a permanent one. + +| Error type | User-friendly message | +|------------|----------------------| +| `user_invalid_credentials` | "The email or password you entered is incorrect. Please try again." | +| `user_blocked` | "Your account has been temporarily suspended. Please contact support." | +| `general_rate_limit_exceeded` | "Please wait a moment before trying again." | +| `storage_file_not_found` | "The file you requested is not available." | +| `row_not_found` | "The information you're looking for could not be found." | + +## Recommended practices {% #recommended-practices %} + +- **Log the full error server-side** for debugging, while showing only the friendly message to users. +- **Handle common scenarios explicitly** and offer clear next steps, such as "Try resetting your password." +- **Retry transient errors** like rate limiting (`429`) or service unavailability (`503`), ideally with backoff. +- **Keep error messaging consistent** in tone and styling across your application. \ No newline at end of file diff --git a/src/routes/docs/apis/rest/+layout.svelte b/src/routes/docs/apis/rest/+layout.svelte index 93e22c8cebf..2416c16742b 100644 --- a/src/routes/docs/apis/rest/+layout.svelte +++ b/src/routes/docs/apis/rest/+layout.svelte @@ -1,6 +1,6 @@ diff --git a/src/routes/docs/apis/rest/+page.markdoc b/src/routes/docs/apis/rest/+page.markdoc index 89e38712406..bf5c8d0d2a3 100644 --- a/src/routes/docs/apis/rest/+page.markdoc +++ b/src/routes/docs/apis/rest/+page.markdoc @@ -113,7 +113,7 @@ X-Appwrite-Project: Server integrations use API keys to authenticate and are typically used for backend applications. -Server APIs are authenticated with API keys instead of account sessions. Simply pass an [API key](/docs/advanced/platform/api-keys) in the `X-Appwrite-key: [API-KEY]` header with the appropriate scopes. +Server APIs are authenticated with API keys instead of account sessions. Simply pass an [API key](/docs/advanced/security/api-keys) in the `X-Appwrite-key: [API-KEY]` header with the appropriate scopes. ```json GET /v1/tablesdb/{databaseId}/tables/{tableId}/rows HTTP/1.1 @@ -464,7 +464,7 @@ In these cases, `column` is empty and `values` is an array of queries. Appwrite's REST APIs are protected by the same rate limit policies, just like when using an SDK. Each API has a different rate limit, which is documented in the References section of each service in the Appwrite documentation. -[Learn more about Rate Limits](/docs/advanced/platform/rate-limits). +[Learn more about Rate Limits](/docs/advanced/security/rate-limits). # Specifications {% #specifications %} diff --git a/src/routes/docs/apis/webhooks/+layout.svelte b/src/routes/docs/apis/webhooks/+layout.svelte new file mode 100644 index 00000000000..2416c16742b --- /dev/null +++ b/src/routes/docs/apis/webhooks/+layout.svelte @@ -0,0 +1,9 @@ + + + + + + diff --git a/src/routes/docs/advanced/platform/webhooks/+page.markdoc b/src/routes/docs/apis/webhooks/+page.markdoc similarity index 99% rename from src/routes/docs/advanced/platform/webhooks/+page.markdoc rename to src/routes/docs/apis/webhooks/+page.markdoc index 2294d47726e..bd9b1e2b992 100644 --- a/src/routes/docs/advanced/platform/webhooks/+page.markdoc +++ b/src/routes/docs/apis/webhooks/+page.markdoc @@ -27,7 +27,7 @@ To add a webhook from the Appwrite Console: # Manage webhooks with a Server SDK {% #manage-webhooks-with-a-server-sdk %} -You can also manage webhooks programmatically using a Server SDK. This requires an API key with the `webhooks.read` and `webhooks.write` [scopes](/docs/advanced/platform/api-keys#scopes). +You can also manage webhooks programmatically using a Server SDK. This requires an API key with the `webhooks.read` and `webhooks.write` [scopes](/docs/advanced/security/api-keys#scopes). ## Create a webhook {% #create-a-webhook %} @@ -1474,7 +1474,7 @@ async fn main() -> Result<(), Box> { # Payload {% #payload %} -Each event type has a specific payload format with the relevant event information. All event payloads mirror the payloads for the API payload which parallel to the [event types](/docs/advanced/platform/events). +Each event type has a specific payload format with the relevant event information. All event payloads mirror the payloads for the API payload which parallel to the [event types](/docs/apis/events). # Headers {% #headers %} @@ -1484,7 +1484,7 @@ HTTP requests made to your webhook's configured URL endpoint will contain severa |--------|-------------| | X-Appwrite-Webhook-Id | The ID of the Webhook who triggered the event. | | X-Appwrite-Webhook-Events | Names of the events that triggered this delivery. | -| X-Appwrite-Webhook-Name | Name of the webhook as specified in your app settings and [events list](/docs/advanced/platform/events). | +| X-Appwrite-Webhook-Name | Name of the webhook as specified in your app settings and [events list](/docs/apis/events). | | X-Appwrite-Webhook-User-Id | The user ID of the user who triggered the event. Returns an empty string if an API key triggered the event. Note that events like `account.create` or `account.sessions.create` are performed by guest users and will not return any user ID. If you still need the user ID for these events, you can find it in the event payload. | | X-Appwrite-Webhook-Project-Id | The ID of the project who owns the Webhook and API call. | | X-Appwrite-Webhook-Signature | The HMAC-SHA1 signature of the payload. This is used to verify the authenticity of the payload. | @@ -1704,4 +1704,4 @@ You can specify one or many events to subscribe to with webhooks. {% /accordion_item %} {% /accordion %} -[Learn more about events](/docs/advanced/platform/events) +[Learn more about events](/docs/apis/events) diff --git a/src/routes/docs/products/auth/+layout.svelte b/src/routes/docs/products/auth/+layout.svelte index 2e8370ca5f3..e651ad26125 100644 --- a/src/routes/docs/products/auth/+layout.svelte +++ b/src/routes/docs/products/auth/+layout.svelte @@ -59,6 +59,10 @@ href: '/docs/products/auth/email-policies', new: isNewUntil('30 June 2026') }, + { + label: 'Message templates', + href: '/docs/products/auth/message-templates' + }, { label: 'Tokens', href: '/docs/products/auth/tokens' @@ -75,7 +79,7 @@ ] }, { - label: 'Journeys', + label: 'Guides', items: [ { label: 'Email and password login', @@ -109,6 +113,11 @@ label: 'SSR login', href: '/docs/products/auth/server-side-rendering' }, + { + label: 'React library', + href: '/docs/products/auth/react', + new: isNewUntil('30 June 2026') + }, { label: 'Custom token login', href: '/docs/products/auth/custom-token' diff --git a/src/routes/docs/products/auth/accounts/+page.markdoc b/src/routes/docs/products/auth/accounts/+page.markdoc index 4964d1240fb..93e231c6d99 100644 --- a/src/routes/docs/products/auth/accounts/+page.markdoc +++ b/src/routes/docs/products/auth/accounts/+page.markdoc @@ -33,7 +33,7 @@ individual users using the `Role.user(, )` role. | Unverified user | `Role.user(, 'unverified')` | -{% arrow_link href="/docs/advanced/platform/permissions" %} +{% arrow_link href="/docs/advanced/security/permissions" %} Learn more about permissions {% /arrow_link %} diff --git a/src/routes/docs/products/auth/jwt/+page.markdoc b/src/routes/docs/products/auth/jwt/+page.markdoc index 87fb0e8d12d..5dee26b3549 100644 --- a/src/routes/docs/products/auth/jwt/+page.markdoc +++ b/src/routes/docs/products/auth/jwt/+page.markdoc @@ -10,7 +10,7 @@ If you are already authenticated on your client-side app and need your backend a # Proof of Identity {% #proof-of-identity %} -Before making requests to your backend APIs, your client application needs to first create a session **directly with Appwrite** using the account service. This session will act like an ID card for the user and can be used to access resources in Appwrite. The client will **only receive information accessible to the user** based on the resources' [permissions](/docs/advanced/platform/permissions). +Before making requests to your backend APIs, your client application needs to first create a session **directly with Appwrite** using the account service. This session will act like an ID card for the user and can be used to access resources in Appwrite. The client will **only receive information accessible to the user** based on the resources' [permissions](/docs/advanced/security/permissions). When you build backend APIs to extend Appwrite's functionality, these APIs should still **respect access permissions** to keep user data secure. Appwrite's backend SDKs allow you to securely act on behalf of a user with the same permissions by using JWT authentication. @@ -173,7 +173,7 @@ var client = new Client() JWT auth is useful when you need your backend app's Server SDK to be restricted by the same set of permissions. -If your backend app's Server SDK is using an [API key](/docs/advanced/platform/api-keys), it will fetch **all resources** regardless of permissions. This means the Server SDK might fetch files and rows your user should not be able to see, which is not helpful when you need to act on behalf of a user. +If your backend app's Server SDK is using an [API key](/docs/advanced/security/api-keys), it will fetch **all resources** regardless of permissions. This means the Server SDK might fetch files and rows your user should not be able to see, which is not helpful when you need to act on behalf of a user. If your backend app's Server SDK is using a **JWT**, it will only fetch resources your user has permissions to access. diff --git a/src/routes/docs/products/auth/labels/+page.markdoc b/src/routes/docs/products/auth/labels/+page.markdoc index 1a209b272a1..25832378b2b 100644 --- a/src/routes/docs/products/auth/labels/+page.markdoc +++ b/src/routes/docs/products/auth/labels/+page.markdoc @@ -206,6 +206,6 @@ This would correspond with the permissions below. | Delete | `Permissions.delete(Role.label('subscriber'))` | | Create | `Permissions.create(Role.label('subscriber'))` | -{% arrow_link href="/docs/advanced/platform/permissions" %} +{% arrow_link href="/docs/advanced/security/permissions" %} Learn more about permissions {% /arrow_link %} \ No newline at end of file diff --git a/src/routes/docs/advanced/platform/message-templates/+page.markdoc b/src/routes/docs/products/auth/message-templates/+page.markdoc similarity index 99% rename from src/routes/docs/advanced/platform/message-templates/+page.markdoc rename to src/routes/docs/products/auth/message-templates/+page.markdoc index aca728a99a1..f4aa1f30951 100644 --- a/src/routes/docs/advanced/platform/message-templates/+page.markdoc +++ b/src/routes/docs/products/auth/message-templates/+page.markdoc @@ -62,7 +62,7 @@ Variables can be used in email templates to dynamically construct unique emails | `{{user}}` | The name of the user receiving the email. This variable is not available in the Magic URL template, as there might not be a user yet. | | `{{redirect}}` | The URL for the user to complete the email template's action. | -## Email template syntax {% #email-template-examples %} +## Email template examples {% #email-template-examples %} Here's an example of using these variables in a template. diff --git a/src/routes/docs/products/auth/phone-sms/+page.markdoc b/src/routes/docs/products/auth/phone-sms/+page.markdoc index 16661555d05..6681eb38dd3 100644 --- a/src/routes/docs/products/auth/phone-sms/+page.markdoc +++ b/src/routes/docs/products/auth/phone-sms/+page.markdoc @@ -5,7 +5,7 @@ description: Enhance security with SMS and phone authentication in Appwrite. Add --- {% info title="Note" %} -OTPs are billed per message, with rates varying by country. See the [phone OTP rates](/docs/advanced/platform/phone-otp#rates) for more information. +OTPs are billed per message, with rates varying by country. See the [phone OTP rates](/docs/advanced/billing/phone-otp#rates) for more information. {% /info %} Phone authentication lets users create accounts using their phone numbers and log in through SMS messages. diff --git a/src/routes/docs/products/auth/presences/+page.markdoc b/src/routes/docs/products/auth/presences/+page.markdoc index 63ef05d2f6e..e41639c9ab8 100644 --- a/src/routes/docs/products/auth/presences/+page.markdoc +++ b/src/routes/docs/products/auth/presences/+page.markdoc @@ -6,7 +6,7 @@ description: Track which signed-in users are active right now and broadcast thei Authentication tells you **who a user is**. Presences tell you **whether they are around right now**. The Appwrite **Presences API** records a live status for each signed-in user and broadcasts every change over [Realtime](/docs/apis/realtime), so your app can render online indicators, "viewing this page" cues, typing signals, and collaboration banners without writing any socket plumbing. -A presence is a short-lived record attached to a user. It carries a `userId`, a `status` string, an optional `metadata` JSON object for richer context, and an `expiresAt` timestamp that controls automatic cleanup. Presences are written by either the user's own session or a server SDK, and read by any client with the right [permissions](/docs/advanced/platform/permissions). +A presence is a short-lived record attached to a user. It carries a `userId`, a `status` string, an optional `metadata` JSON object for richer context, and an `expiresAt` timestamp that controls automatic cleanup. Presences are written by either the user's own session or a server SDK, and read by any client with the right [permissions](/docs/advanced/security/permissions). # Set the user's presence {% #set-the-users-presence %} @@ -125,7 +125,7 @@ There is no fixed heartbeat interval enforced by the server, so pick whichever c # Show other users' presence {% #show-other-users-presence %} -List the presences the current user can read to paint the initial "online now" view, a list of viewers on a page, or a typing dot in a chat. The list call honors the same [permissions](/docs/advanced/platform/permissions) you set on each record, so each client only sees the statuses it is allowed to render. +List the presences the current user can read to paint the initial "online now" view, a list of viewers on a page, or a typing dot in a chat. The list call honors the same [permissions](/docs/advanced/security/permissions) you set on each record, so each client only sees the statuses it is allowed to render. {% multicode %} ```client-web @@ -313,7 +313,7 @@ If a user closes the browser tab or loses connection without signing out, the re # Scoping who can see a presence {% #scoping-who-can-see-a-presence %} -Presences use the standard Appwrite [permissions system](/docs/advanced/platform/permissions). Set read permissions on each record to match how your app already groups users: +Presences use the standard Appwrite [permissions system](/docs/advanced/security/permissions). Set read permissions on each record to match how your app already groups users: - `Role.users()` for any signed-in user, useful for a global "X users online" counter. - `Role.team('')` for collaboration features that should only show statuses to teammates. @@ -407,4 +407,4 @@ If you do not pass a `permissions` array when upserting a presence, Appwrite def - [Realtime: Presences](/docs/apis/realtime/presences). The full concept reference, including channel patterns, expiry behaviour, and server-side usage. - [Realtime channels](/docs/apis/realtime/channels). See how `presences` fits alongside `account`, `teams`, and `rows`. -- [Permissions](/docs/advanced/platform/permissions). Refresher on how `Role.team()` and `Role.user()` work. +- [Permissions](/docs/advanced/security/permissions). Refresher on how `Role.team()` and `Role.user()` work. diff --git a/src/routes/docs/products/auth/react/+page.markdoc b/src/routes/docs/products/auth/react/+page.markdoc new file mode 100644 index 00000000000..ec59e54bc29 --- /dev/null +++ b/src/routes/docs/products/auth/react/+page.markdoc @@ -0,0 +1,406 @@ +--- +layout: article +title: React library +description: Add authentication to React apps with Appwrite's official React library. Supports client-side React, Next.js, and TanStack Start with a single provider and a small set of hooks. +--- + +The Appwrite React library is a thin layer over the [Web SDK](/docs/sdks) that exposes a provider and a small set of hooks for authentication operations and current user state. It works in both client-rendered React apps and server-rendered apps on Next.js and TanStack Start. + +# Why use it {% #why %} + +- **SSR auth without boilerplate.** Drop in one handler route per framework and skip the days normally spent writing cookie logic, session sync, and server/client hydration. +- **Consistent user state across server and client.** Server components, loaders, and client hooks return the same authenticated user, removing the need to reconcile auth state across the render boundary. +- **Server-side access when you need it.** Read the current user, create per-request session clients, or reach for an admin client without hand-wiring the Node SDK on every route. + +# Install {% #install %} + +Install the library along with the **Appwrite Web SDK** and **TanStack Query** packages. + +```sh +npm install @appwrite.io/react appwrite @tanstack/react-query +``` + +For SSR apps on Next.js or TanStack Start, also install `node-appwrite`. The SSR handlers create sessions with a server API key. + +```sh +npm install @appwrite.io/react appwrite node-appwrite @tanstack/react-query +``` + +# Pick your framework {% #frameworks %} + +{% cards %} +{% cards_item href="/docs/quick-starts/react" title="Client-side React" %} +For Vite and other client-rendered React apps. +{% /cards_item %} +{% cards_item href="/docs/quick-starts/nextjs" title="Next.js" %} +For server-rendered apps on the Next.js App Router. +{% /cards_item %} +{% cards_item href="/docs/quick-starts/tanstack-start" title="TanStack Start" %} +For server-rendered apps on TanStack Start. +{% /cards_item %} +{% /cards %} + +# The provider {% #provider %} + +Every app starts with an `AppwriteProvider`. In a CSR app, only `endpoint` and `projectId` are required. + +```tsx +import { AppwriteProvider } from "@appwrite.io/react"; + + + +; +``` + +In an SSR app, pass an `ssr` prop with the session secret read from the server-side cookie and the path your handlers are mounted at. + +```tsx + + {children} + +``` + +When `ssr` is set, sign-in, sign-up, and sign-out mutations route through your handler. The underlying Web SDK is hydrated with the session secret on first render, so authenticated reads do not need a round trip. + +# Hooks {% #hooks %} + +The library exports one combined hook and four focused mutation hooks. All hooks share the same TanStack Query cache, so updating user state from any of them reflects everywhere. + +## useAuth {% #use-auth %} + +The primary hook for most apps. It bundles the current user, loading and error state, and handles for sign-in, sign-up, and sign-out into a single return value. + +```tsx +import { useAuth } from "@appwrite.io/react"; + +const { user, isLoading, error, refresh, signIn, signUp, signOut } = useAuth(); +``` + +| Field | Type | Description | +| --- | --- | --- | +| `user` | `Models.User \| null \| undefined` | The current user, or `null` if signed out. `undefined` while loading. | +| `isLoading` | `boolean` | True while the initial user fetch is in flight. | +| `error` | `Error \| null` | First error from the user query or any mutation. | +| `refresh` | `() => Promise` | Refetch the current user and return the resolved value. | +| `signIn` | `ReturnType` | Sign-in mutation handle. | +| `signUp` | `ReturnType` | Sign-up mutation handle. | +| `signOut` | `ReturnType` | Sign-out mutation handle. | + +## useUser {% #use-user %} + +Read-only access to the current authenticated user. Use it in components that only need to display user state and do not trigger auth mutations. + +```tsx +import { useUser } from "@appwrite.io/react"; + +const { user, isLoading, error, refresh } = useUser(); +``` + +| Field | Type | Description | +| --- | --- | --- | +| `user` | `Models.User \| null \| undefined` | The current user, or `null` if signed out. `undefined` while loading. | +| `isLoading` | `boolean` | True while the user is being fetched. | +| `error` | `Error \| null` | Error from the fetch, if one occurred. | +| `refresh` | `() => Promise` | Refetch the current user and return the resolved value. | + +## useSignIn {% #use-sign-in %} + +Email and password and OAuth sign-in, with pending and error state scoped to the email and password flow. + +```tsx +const { emailPassword, oAuth, isPending, error } = useSignIn(); +``` + +| Field | Type | Description | +| --- | --- | --- | +| `emailPassword` | `function` | Trigger an email and password sign-in. | +| `oAuth` | `function` | Trigger an OAuth sign-in. | +| `isPending` | `boolean` | True while an email and password sign-in is in flight. | +| `error` | `Error \| null` | Error from the last email and password sign-in attempt. | + +{% tabs %} +{% tabsitem #use-sign-in-email-password title="Email and password" %} +```tsx +emailPassword({ email, password, onSuccess, onError }); +``` + +| Parameter | Required | Description | +| --- | --- | --- | +| `email` | Yes | User's email address. | +| `password` | Yes | User's password. | +| `onSuccess` | No | Callback invoked with the signed-in user. | +| `onError` | No | Callback invoked with the thrown error. | +{% /tabsitem %} + +{% tabsitem #use-sign-in-oauth title="OAuth" %} +```tsx +oAuth({ provider: OAuthProvider.Google, successUrl, failureUrl, scopes }); +``` + +| Parameter | Required | Description | +| --- | --- | --- | +| `provider` | Yes | An `OAuthProvider` value re-exported by the library. | +| `successUrl` | No | URL to redirect to after successful login (CSR only). | +| `failureUrl` | No | URL to redirect to after a failed attempt. | +| `scopes` | No | Provider-specific OAuth scopes to request. | +| `onError` | No | Callback invoked if the request fails before redirect. | + +In SSR mode, the success URL is fixed to the handler callback. The final redirect after that callback is controlled by the `redirects.success` config on the handler. +{% /tabsitem %} +{% /tabs %} + +## useSignUp {% #use-sign-up %} + +Create an account and start a session in one call. The hook also surfaces pending and error state for the in-flight request. + +```tsx +const { emailPassword, isPending, error } = useSignUp(); +``` + +| Field | Type | Description | +| --- | --- | --- | +| `emailPassword` | `function` | Create an account with email and password, then sign the user in. | +| `isPending` | `boolean` | True while the sign-up is in flight. | +| `error` | `Error \| null` | Error from the last sign-up attempt. | + +### Email and password {% #use-sign-up-email-password %} + +```tsx +emailPassword({ email, password, name, userId, onSuccess, onError }); +``` + +| Parameter | Required | Description | +| --- | --- | --- | +| `email` | Yes | New user's email address. | +| `password` | Yes | New user's password. | +| `name` | No | Display name for the user. | +| `userId` | No | Custom user ID. Defaults to `ID.unique()`. | +| `onSuccess` | No | Callback invoked with the created user. | +| `onError` | No | Callback invoked with the thrown error. | + +## useSignOut {% #use-sign-out %} + +End the current session, drop cached auth queries, and reset the local Web SDK client. + +```tsx +const { signOut, isPending, error } = useSignOut(); +``` + +| Field | Type | Description | +| --- | --- | --- | +| `signOut` | `function` | End the current user's session. | +| `isPending` | `boolean` | True while the sign-out is in flight. | +| `error` | `Error \| null` | Error from the last sign-out attempt. | + +### Sign out {% #use-sign-out-method %} + +```tsx +signOut({ onSuccess, onError }); +``` + +| Parameter | Required | Description | +| --- | --- | --- | +| `onSuccess` | No | Callback invoked after the session is destroyed. | +| `onError` | No | Callback invoked with the thrown error. | + +After a successful sign-out, all cached auth queries are dropped and the local Web SDK client is reset. On Next.js, call `router.refresh()` from `onSuccess` to re-render server components with the cleared cookie. On TanStack Start, call `router.invalidate()`. + +## useAppwrite {% #use-appwrite %} + +Escape hatch to the underlying provider context. Use it when you need direct access to a Web SDK service the higher-level hooks do not wrap (`tablesDB`, `storage`, `messaging`, `realtime`, and so on). + +```tsx +import { useAppwrite } from "@appwrite.io/react"; + +const { client, account, tablesDB, storage, teams, ssr } = useAppwrite(); +``` + +| Field | Type | Description | +| --- | --- | --- | +| `client` | `Client` | The Appwrite Web SDK `Client` configured by the provider. | +| `account` | `Account` | Web SDK `Account` service. | +| `avatars` | `Avatars` | Web SDK `Avatars` service. | +| `functions` | `Functions` | Web SDK `Functions` service. | +| `graphql` | `Graphql` | Web SDK `Graphql` service. | +| `locale` | `Locale` | Web SDK `Locale` service. | +| `messaging` | `Messaging` | Web SDK `Messaging` service. | +| `presences` | `Presences` | Web SDK `Presences` service. | +| `realtime` | `Realtime` | Web SDK `Realtime` service. | +| `storage` | `Storage` | Web SDK `Storage` service. | +| `tablesDB` | `TablesDB` | Web SDK `TablesDB` service. | +| `teams` | `Teams` | Web SDK `Teams` service. | +| `authenticated` | `boolean` | Whether the provider currently considers a user signed in. | +| `setAuthenticated` | `Dispatch>` | Update the authenticated flag manually. | +| `ssr.enabled` | `boolean` | Whether the provider was mounted with the `ssr` prop. | +| `ssr.basePath` | `string` | Mount path of the handler routes. | +| `ssr.session` | `string \| null` | Session secret read from the server cookie. | + +Throws if called outside an `AppwriteProvider`. + +# Server helpers {% #server-helpers %} + +The library ships server entrypoints scoped per framework. Each helper exposes the same surface, differing only in how it reads the request cookie. + +```ts +// Next.js (App Router) +import { createNextServerHelpers } from "@appwrite.io/react/server/next"; + +// TanStack Start +import { createTanStackServerHelpers } from "@appwrite.io/react/server/tanstack"; +``` + +Both return an object with: + +| Method | Returns | Use it for | +| --- | --- | --- | +| `readSessionCookie()` | `string \| undefined` (sync on TanStack, async on Next.js) | The session secret. Pass it into `AppwriteProvider`'s `ssr.session` prop. | +| `getLoggedInUser()` | `Models.User \| null` | The current user, fetched via the cookie. Returns `null` on 401. | +| `getSession()` | `Models.Session \| null` | The current session row. | +| `createSessionClient()` | `NodeSessionServer \| null` | A `node-appwrite` client authenticated as the cookie's user, or `null` if no cookie. | +| `createAdminClient()` | `AdminServer` | A `node-appwrite` admin client authenticated with the API key passed to the helper. Only available when `apiKey` is set in the helper config. | + +## Session client {% #session-client %} + +For per-request operations scoped to the current user (reading their data, calling APIs on their behalf), call `createSessionClient` from the framework helper. It returns a `node-appwrite` client already authenticated with the session cookie, ready to use in server components, loaders, and server functions. + +```ts +import { createNextServerHelpers } from "@appwrite.io/react/server/next"; + +const helpers = createNextServerHelpers({ + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, +}); + +const session = await helpers.createSessionClient(); + +if (session) { + const user = await session.account.get(); +} +``` + +## Admin client {% #admin-client %} + +For privileged operations (creating users, listing sessions, managing teams), call `createAdminClient` on the framework helper. Pass `apiKey` in the helper config to enable it, then call the method anywhere on the server. The returned object exposes every `node-appwrite` service: `account`, `users`, `tablesDB`, `storage`, `teams`, `functions`, `messaging`, and more. + +```ts +import { createNextServerHelpers } from "@appwrite.io/react/server/next"; + +const helpers = createNextServerHelpers({ + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, + apiKey: process.env.APPWRITE_API_KEY!, +}); + +const admin = helpers.createAdminClient(); +const users = await admin.users.list(); +``` + +If you would rather not pass the API key into the helper, the library also exports a standalone `createAdminClient` from `@appwrite.io/react/server` that takes the key directly. + +```ts +import { createAdminClient } from "@appwrite.io/react/server"; + +const admin = createAdminClient({ + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, + apiKey: process.env.APPWRITE_API_KEY!, +}); + +const users = await admin.users.list(); +``` + +Never import any `@appwrite.io/react/server/*` module from client code: the entrypoints are marked `server-only` and will throw if bundled into the browser. + +# Handler routes {% #handlers %} + +The SSR mutations (`sign-in`, `sign-up`, `sign-out`, `oauth/callback`, `oauth/failure`) live behind a handler route you mount once per app. The handler reads the request, talks to Appwrite with the server API key, and writes the session cookie back. + +{% tabs %} +{% tabsitem #handler-next title="Next.js" %} +```ts +// app/api/appwrite/[...appwrite]/route.ts +import { createAppwriteHandlers } from "@appwrite.io/react/handlers/next"; + +export const { GET, POST } = createAppwriteHandlers({ + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, + apiKey: process.env.APPWRITE_API_KEY!, + basePath: "/api/appwrite", +}); +``` +{% /tabsitem %} + +{% tabsitem #handler-tanstack title="TanStack Start" %} +```ts +// src/routes/api/appwrite/$.ts +import { createFileRoute } from "@tanstack/react-router"; +import { createAppwriteHandlers } from "@appwrite.io/react/handlers/tanstack"; + +export const Route = createFileRoute("/api/appwrite/$")({ + server: { + handlers: createAppwriteHandlers({ + endpoint: import.meta.env.VITE_APPWRITE_ENDPOINT, + projectId: import.meta.env.VITE_APPWRITE_PROJECT_ID, + apiKey: process.env.APPWRITE_API_KEY!, + basePath: "/api/appwrite", + }), + }, +}); +``` +{% /tabsitem %} +{% /tabs %} + +## Cookie and redirect options {% #handler-options %} + +Customize how sessions persist in the browser and where users land after an OAuth round trip. + +```ts +createAppwriteHandlers({ + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, + apiKey: process.env.APPWRITE_API_KEY!, + basePath: "/api/appwrite", + cookieName: "my-app-session", + cookieOptions: { + sameSite: "strict", + domain: ".example.com", + }, + redirects: { + success: "/dashboard", + failure: "/login?error=oauth", + }, +}); +``` + +| Option | Default | Description | +| --- | --- | --- | +| `cookieName` | `appwrite-session-` | Name of the HTTP-only session cookie. | +| `cookieOptions.secure` | `true` | Set the `Secure` flag on the cookie. Modern browsers accept this on `localhost` over HTTP. | +| `cookieOptions.sameSite` | `"lax"` | SameSite policy. | +| `cookieOptions.httpOnly` | `true` | HttpOnly flag. | +| `cookieOptions.path` | `"/"` | Cookie path. | +| `cookieOptions.domain` | unset | Restrict cookie to a domain. | +| `redirects.success` | `"/"` | URL to redirect to after a successful OAuth login. | +| `redirects.failure` | `"/"` | URL to redirect to after a failed OAuth attempt. | + +# Required scopes {% #scopes %} + +Your server API key needs three scopes for the SSR handler to function: + +- `users.write` (sign-up creates a user) +- `users.read` (sign-up confirms the created user) +- `sessions.write` (sign-in, sign-out, and OAuth callbacks create or delete sessions) + +# Next steps {% #next-steps %} + +- [Start with React](/docs/quick-starts/react) +- [Start with Next.js](/docs/quick-starts/nextjs) +- [Start with TanStack Start](/docs/quick-starts/tanstack-start) +- [Account API reference](/docs/references/cloud/client-web/account) diff --git a/src/routes/docs/products/auth/server-side-rendering/+page.markdoc b/src/routes/docs/products/auth/server-side-rendering/+page.markdoc index a77e9bec0e7..2cf2f21fbeb 100644 --- a/src/routes/docs/products/auth/server-side-rendering/+page.markdoc +++ b/src/routes/docs/products/auth/server-side-rendering/+page.markdoc @@ -46,7 +46,7 @@ Admin clients should only be used if you need to perform admin actions that bypa or [unauthenticated requests that bypass rate limits](#rate-limits). {% /info %} -To initialize the admin client, we'll need to first [generate an API key](/docs/advanced/platform/api-keys#create-api-key). +To initialize the admin client, we'll need to first [generate an API key](/docs/advanced/security/api-keys#create-api-key). The API key should have the following scope in order to perform authentication: | Category {% width=120 %} | Required scopes | Purpose | @@ -94,7 +94,7 @@ let admin_client = Client::new() ``` {% /multicode %} -It is important to use an API key, as this will allow your server requests to bypass [rate limits](/docs/advanced/platform/rate-limits). If you don't use an API key, your server will be rate limited as if it were a client from a single IP address. +It is important to use an API key, as this will allow your server requests to bypass [rate limits](/docs/advanced/security/rate-limits). If you don't use an API key, your server will be rate limited as if it were a client from a single IP address. ## Session client {% #session-client %} @@ -103,7 +103,7 @@ It will be initialized with the session, usually stored within a cookie. You should create a new client for each request and **never** share the client between requests. -Use `a_session_` as the [cookie name](/docs/apis/rest#client-integration) and a [custom domain](/docs/advanced/platform/custom-domains) for your Appwrite endpoint if you want the session to work client-side as well. +Use `a_session_` as the [cookie name](/docs/apis/rest#client-integration) and a [custom domain](/docs/products/network/custom-domains) for your Appwrite endpoint if you want the session to work client-side as well. {% multicode %} ```server-nodejs @@ -406,7 +406,7 @@ let user = account.get().await?; {% /multicode %} # Rate limits {% #rate-limits %} -Unauthenticated requests are subject to [rate limits](/docs/advanced/platform/rate-limits). +Unauthenticated requests are subject to [rate limits](/docs/advanced/security/rate-limits). Normally, rate limits are applied by an abuse key, which is usually a combination of IP and another factor like user ID. When you make unauthenticated requests from your server, however, all requests originate from the same IP and no user ID is provided. This means that all unauthenticated requests from your server will be **subject to the same rate limits**. diff --git a/src/routes/docs/products/auth/team-invites/+page.markdoc b/src/routes/docs/products/auth/team-invites/+page.markdoc index c16614d1f34..1da1e5b5a8a 100644 --- a/src/routes/docs/products/auth/team-invites/+page.markdoc +++ b/src/routes/docs/products/auth/team-invites/+page.markdoc @@ -792,7 +792,7 @@ val isAdmin = membership?.roles?.contains("admin") ?: false ``` {% /multicode %} -See how to grant row and file access to team roles in the [permissions](/docs/advanced/platform/permissions#example-2-team-roles) guide. +See how to grant row and file access to team roles in the [permissions](/docs/advanced/security/permissions#example-2-team-roles) guide. {% arrow_link href="/docs/products/auth/teams" %} Learn more about team management diff --git a/src/routes/docs/products/auth/teams/+page.markdoc b/src/routes/docs/products/auth/teams/+page.markdoc index 7df0d562003..3303c653e8a 100644 --- a/src/routes/docs/products/auth/teams/+page.markdoc +++ b/src/routes/docs/products/auth/teams/+page.markdoc @@ -217,7 +217,7 @@ individual roles in the team using the `Role.team(, [, | Select roles | `Role.team(, [, , ...])`| -{% arrow_link href="/docs/advanced/platform/permissions" %} +{% arrow_link href="/docs/advanced/security/permissions" %} Learn more about permissions {% /arrow_link %} diff --git a/src/routes/docs/products/databases/+layout.svelte b/src/routes/docs/products/databases/+layout.svelte index 87f1ffb5a32..6c1f5158d47 100644 --- a/src/routes/docs/products/databases/+layout.svelte +++ b/src/routes/docs/products/databases/+layout.svelte @@ -76,7 +76,7 @@ ] }, { - label: 'Journeys', + label: 'Guides', items: [ { label: 'Pagination', diff --git a/src/routes/docs/products/databases/databases/+page.markdoc b/src/routes/docs/products/databases/databases/+page.markdoc index cc3147838b7..ea3dd1347c5 100644 --- a/src/routes/docs/products/databases/databases/+page.markdoc +++ b/src/routes/docs/products/databases/databases/+page.markdoc @@ -14,7 +14,7 @@ You can create a database by navigating to the **Databases** page and clicking * # Create using Server SDKs {% #create-using-server-sdks %} -You can programmatically create databases using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/platform/api-keys). +You can programmatically create databases using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/security/api-keys). {% multicode %} ```server-nodejs diff --git a/src/routes/docs/products/databases/legacy/collections/+page.markdoc b/src/routes/docs/products/databases/legacy/collections/+page.markdoc index 11bb32ee430..8f8ac951985 100644 --- a/src/routes/docs/products/databases/legacy/collections/+page.markdoc +++ b/src/routes/docs/products/databases/legacy/collections/+page.markdoc @@ -18,7 +18,7 @@ You can create a collection by heading to the **Databases** page, navigate to a {% /tabsitem %} {% tabsitem #server-sdk title="Server SDK" %} -You can also create collections programmatically using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/platform/api-keys). +You can also create collections programmatically using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/security/api-keys). {% multicode %} diff --git a/src/routes/docs/products/databases/legacy/databases/+page.markdoc b/src/routes/docs/products/databases/legacy/databases/+page.markdoc index 084d49064b5..38a11396dc6 100644 --- a/src/routes/docs/products/databases/legacy/databases/+page.markdoc +++ b/src/routes/docs/products/databases/legacy/databases/+page.markdoc @@ -14,7 +14,7 @@ You can create a database by navigating to the **Databases** page and clicking * # Create using Server SDKs {% #create-using-server-sdks %} -You can programmatically create databases using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/platform/api-keys). +You can programmatically create databases using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/security/api-keys). {% multicode %} ```server-nodejs diff --git a/src/routes/docs/products/databases/legacy/permissions/+page.markdoc b/src/routes/docs/products/databases/legacy/permissions/+page.markdoc index 5354078450d..94247a34ec5 100644 --- a/src/routes/docs/products/databases/legacy/permissions/+page.markdoc +++ b/src/routes/docs/products/databases/legacy/permissions/+page.markdoc @@ -17,7 +17,7 @@ If a user has read, create, update, or delete permissions at the collection leve Configure collection level permissions by navigating to **Your collection** > **Settings** > **Permissions**. -[Learn more about permissions and roles](/docs/advanced/platform/permissions) +[Learn more about permissions and roles](/docs/advanced/security/permissions) # Document level {% #document-level %} Document level permissions grant access to individual documents. @@ -28,10 +28,10 @@ Enable document level permissions by navigating to **Your collection** > **Setti Document level permissions are configured in individual documents. -[Learn more about permissions and roles](/docs/advanced/platform/permissions) +[Learn more about permissions and roles](/docs/advanced/security/permissions) # Common use cases {% #common-use-cases %} -For examples of how to implement common permission patterns, including creating private documents that are only accessible to their creators, see the [permissions examples](/docs/advanced/platform/permissions#examples) in our platform documentation. +For examples of how to implement common permission patterns, including creating private documents that are only accessible to their creators, see the [permissions examples](/docs/advanced/security/permissions#examples) in our platform documentation. diff --git a/src/routes/docs/products/databases/permissions/+page.markdoc b/src/routes/docs/products/databases/permissions/+page.markdoc index e6b9ee22b09..4f8901c55a0 100644 --- a/src/routes/docs/products/databases/permissions/+page.markdoc +++ b/src/routes/docs/products/databases/permissions/+page.markdoc @@ -17,7 +17,7 @@ If a user has read, create, update, or delete permissions at the table level, th Configure table level permissions by navigating to **Your table** > **Settings** > **Permissions**. -[Learn more about permissions and roles](/docs/advanced/platform/permissions) +[Learn more about permissions and roles](/docs/advanced/security/permissions) # Row level {% #row-level %} Row level permissions grant access to individual rows. @@ -28,10 +28,10 @@ Enable row level permissions by navigating to **Your table** > **Settings** > ** Row level permissions are configured in individual rows. -[Learn more about permissions and roles](/docs/advanced/platform/permissions) +[Learn more about permissions and roles](/docs/advanced/security/permissions) # Common use cases {% #common-use-cases %} -For examples of how to implement common permission patterns, including creating private rows that are only accessible to their creators, see the [permissions examples](/docs/advanced/platform/permissions#examples) in our platform documentation. +For examples of how to implement common permission patterns, including creating private rows that are only accessible to their creators, see the [permissions examples](/docs/advanced/security/permissions#examples) in our platform documentation. diff --git a/src/routes/docs/products/databases/tables/+page.markdoc b/src/routes/docs/products/databases/tables/+page.markdoc index 1fcff68a5b3..3e6b2fee4df 100644 --- a/src/routes/docs/products/databases/tables/+page.markdoc +++ b/src/routes/docs/products/databases/tables/+page.markdoc @@ -18,7 +18,7 @@ You can create a table by heading to the **Databases** page, navigate to a [data {% /tabsitem %} {% tabsitem #server-sdk title="Server SDK" %} -You can also create tables programmatically using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/platform/api-keys). +You can also create tables programmatically using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/security/api-keys). {% multicode %} diff --git a/src/routes/docs/products/functions/+layout.svelte b/src/routes/docs/products/functions/+layout.svelte index a6ae8dfceeb..738aa5db765 100644 --- a/src/routes/docs/products/functions/+layout.svelte +++ b/src/routes/docs/products/functions/+layout.svelte @@ -51,7 +51,7 @@ ] }, { - label: 'Journeys', + label: 'Guides', items: [ { label: 'Templates', diff --git a/src/routes/docs/products/functions/deployments/+page.markdoc b/src/routes/docs/products/functions/deployments/+page.markdoc index 8265c6d193e..cda73fa0f16 100644 --- a/src/routes/docs/products/functions/deployments/+page.markdoc +++ b/src/routes/docs/products/functions/deployments/+page.markdoc @@ -57,8 +57,8 @@ Redeployment behavior varies depending on how the initial deployment was created Users subscribed to the Appwrite Pro plan or above receive certain special benefits: - [Express builds](/changelog/entry/2024-08-10) for quicker deployments, resulting in reduced wait times and smoother workflows -- Longer [build timeouts](/docs/advanced/platform/compute#build-timeouts) (45 minutes vs 15 minutes on Free; Enterprise is custom) -- Customizable [build and runtime specifications](/docs/advanced/platform/compute) for CPU and memory on each function +- Longer [build timeouts](/docs/advanced/billing/compute#build-timeouts) (45 minutes vs 15 minutes on Free; Enterprise is custom) +- Customizable [build and runtime specifications](/docs/advanced/billing/compute) for CPU and memory on each function {% /info %} # Deployment retention {% #deployment-retention %} diff --git a/src/routes/docs/products/functions/develop/+page.markdoc b/src/routes/docs/products/functions/develop/+page.markdoc index 83427b0d894..4c43dfaff88 100644 --- a/src/routes/docs/products/functions/develop/+page.markdoc +++ b/src/routes/docs/products/functions/develop/+page.markdoc @@ -1549,7 +1549,7 @@ Appwrite can be used in your functions by adding the relevant SDK to your functi Authenticating with Appwrite is done via a dynamic API key or a JWT token. ## Dynamic API key {% #dynamic-api-key %} -Dynamic API keys are the same as [API keys](/docs/advanced/platform/api-keys) but are automatically generated. +Dynamic API keys are the same as [API keys](/docs/advanced/security/api-keys) but are automatically generated. They are generated in your functions per execution. However, you can only use dynamic API keys inside Appwrite functions. diff --git a/src/routes/docs/products/functions/environment-variables/+page.markdoc b/src/routes/docs/products/functions/environment-variables/+page.markdoc index e9531515a60..63b7f9fb059 100644 --- a/src/routes/docs/products/functions/environment-variables/+page.markdoc +++ b/src/routes/docs/products/functions/environment-variables/+page.markdoc @@ -8,7 +8,7 @@ Appwrite Functions can read environment variables at build and runtime. Use them A function reads from three sources, in this order of precedence: -1. **Project variables** are shared across every function and site in your project. Set them once and every function inherits them automatically. See [project variables](/docs/advanced/platform/environment-variables) for the platform-wide reference. +1. **Project variables** are shared across every function and site in your project. Set them once and every function inherits them automatically. See [project variables](/docs/advanced/security/environment-variables) for the full reference. 2. **Function variables** are scoped to a single function. Override a project variable for one function by setting the same key on the function itself. 3. **Appwrite-injected variables** are set by Appwrite at execution time (for example, `APPWRITE_FUNCTION_PROJECT_ID`). These take final precedence and cannot be overridden. @@ -31,11 +31,11 @@ Variable changes only take effect on the next deployment. Redeploy your function ![Function environment variables](/images/docs/functions/env-variables.avif) {% /only_light %} -You can also configure global variables that apply to all your functions from your project's **Settings** page. See [project variables](/docs/advanced/platform/environment-variables) for details. +You can also configure global variables that apply to all your functions from your project's **Settings** page. See [project variables](/docs/advanced/security/environment-variables) for details. # Manage with a Server SDK {% #server-sdks %} -You can also manage function variables programmatically using a [Server SDK](/docs/sdks#server). Each call requires an [API key](/docs/advanced/platform/api-keys) with the `functions.write` scope to create, update, or delete variables, or the `functions.read` scope to list and read them. +You can also manage function variables programmatically using a [Server SDK](/docs/sdks#server). Each call requires an [API key](/docs/advanced/security/api-keys) with the `functions.write` scope to create, update, or delete variables, or the `functions.read` scope to list and read them. ## Create a variable {% #create-variable %} diff --git a/src/routes/docs/products/functions/execute/+page.markdoc b/src/routes/docs/products/functions/execute/+page.markdoc index 3a41e6adbb4..326c5be60c3 100644 --- a/src/routes/docs/products/functions/execute/+page.markdoc +++ b/src/routes/docs/products/functions/execute/+page.markdoc @@ -34,7 +34,7 @@ Asynchronous executions are added to a queue and processed by the function worke Asynchronous executions are created via: - The [Create execution](/docs/references/cloud/client-web/functions#createExecution) endpoint where the `async` parameter is `true` -- Event triggers (when functions are triggered by [platform events](/docs/advanced/platform/events)) +- Event triggers (when functions are triggered by [platform events](/docs/apis/events)) - Scheduled executions (cron jobs or delayed executions) Asynchronous executions: @@ -524,7 +524,7 @@ Changes in Appwrite emit events. You can configure Functions to be executed in r 5. Be careful to avoid selecting events that can be caused by the function itself. This can cause the function to trigger its own execution, resulting in infinite recursions. In these executions, the event that triggered the function will be passed as the header `x-appwrite-event` to the function. -The `request.body` parameter will contain the event data. [Learn more about events](/docs/advanced/platform/events). +The `request.body` parameter will contain the event data. [Learn more about events](/docs/apis/events). You can use one of the following events. {% accordion %} @@ -1055,6 +1055,6 @@ async fn main() -> Result<(), Box> { # Permissions {% #permission %} -Appwrite Functions can be executed using Client or Server SDKs. Client SDKs must be authenticated with an account that has been granted execution [permissions](/docs/advanced/platform/permissions) on the function's settings page. Server SDKs require an API key with the correct scopes. +Appwrite Functions can be executed using Client or Server SDKs. Client SDKs must be authenticated with an account that has been granted execution [permissions](/docs/advanced/security/permissions) on the function's settings page. Server SDKs require an API key with the correct scopes. If your function has a generated or custom domain, executions are not authenticated. Anyone visiting the configured domains will be considered a guest, so make sure to give `Any` execute permission in order for domain executions to work. If you need to enforce permissions for functions with a domain, use authentication methods like JWT. diff --git a/src/routes/docs/products/functions/executions/+page.markdoc b/src/routes/docs/products/functions/executions/+page.markdoc index e9b0a6e4852..f3a1e2c000b 100644 --- a/src/routes/docs/products/functions/executions/+page.markdoc +++ b/src/routes/docs/products/functions/executions/+page.markdoc @@ -27,7 +27,7 @@ Here's the information shown on this table. - Timestamp of when the execution was created --- - Trigger -- The [platform event](/docs/advanced/platform/events) that triggered the execution +- The [platform event](/docs/apis/events) that triggered the execution --- - Method - The HTTP method used to create the execution diff --git a/src/routes/docs/products/functions/functions/+page.markdoc b/src/routes/docs/products/functions/functions/+page.markdoc index b2b5de9c388..d8bdced0bb9 100644 --- a/src/routes/docs/products/functions/functions/+page.markdoc +++ b/src/routes/docs/products/functions/functions/+page.markdoc @@ -107,11 +107,11 @@ These are terminal commands that will be executed in the runtime containers in t Under **Settings** - **Resource limits**, you can set **build** and **runtime** specifications independently. The build spec applies while your deployment is being built and packaged; the runtime spec applies to each function execution. Both use the same CPU and memory tiers on Cloud. This lets you align compute with heavy dependency installs or compilation without over-provisioning every invocation. -On Appwrite Cloud, customizing specifications requires the **Pro** plan. See [Compute](/docs/advanced/platform/compute) for tiers, GB-hours, and pricing. +On Appwrite Cloud, customizing specifications requires the **Pro** plan. See [Compute](/docs/advanced/billing/compute) for tiers, GB-hours, and pricing. ## Build timeout {% #build-timeout %} -On Appwrite Cloud, the **build** phase of each deployment must complete within your plan’s **maximum build duration** (for example, 15 minutes on Free and 45 minutes on Pro and Scale). See [Build timeouts](/docs/advanced/platform/compute#build-timeouts) and the [pricing page](/pricing). +On Appwrite Cloud, the **build** phase of each deployment must complete within your plan’s **maximum build duration** (for example, 15 minutes on Free and 45 minutes on Pro and Scale). See [Build timeouts](/docs/advanced/billing/compute#build-timeouts) and the [pricing page](/pricing). ## Git integration {% #git-integration %} You can update the entrypoint file and build settings of your function by navigating to your function > **Settings** > **Configuration**. @@ -133,13 +133,13 @@ In production environments, you can choose to disable execution logs to protect ## Execute access {% #execution-access %} You can control who can execute your functions by navigating to your function > **Settings** > **Execute access** -and granting access to select [permission roles](/docs/advanced/platform/permissions#permission-roles). +and granting access to select [permission roles](/docs/advanced/security/permissions#permission-roles). If this is left empty, no user can execute your function. Server SDKs, scheduled executions, and event function triggers don't require permissions to execute a function. ## Events{% #events %} -Functions can be triggered by [platform events](/docs/advanced/platform/events) which reflect changes +Functions can be triggered by [platform events](/docs/apis/events) which reflect changes that occur in your Appwrite project. You can configure events triggers by navigating to your function > **Settings** > **Events**. @@ -168,6 +168,6 @@ There is a system wide maximum timeout of 900 seconds (15 minutes). You can configure the permission scopes for the function [dynamic API key](/docs/products/functions/develop#dynamic-api-key). The dynamic API key is automatically generated to access your project resources like users and buckets but can only be used inside of Appwrite functions. Navigate to your function > **Settings** > **Scopes** to configure your dynamic API key permission scopes. -{% arrow_link href="/docs/advanced/platform/api-keys#scopes" %} +{% arrow_link href="/docs/advanced/security/api-keys#scopes" %} Learn more about scopes {% /arrow_link %} \ No newline at end of file diff --git a/src/routes/docs/products/messaging/+layout.svelte b/src/routes/docs/products/messaging/+layout.svelte index 224bbb4a65c..ed4257acc7d 100644 --- a/src/routes/docs/products/messaging/+layout.svelte +++ b/src/routes/docs/products/messaging/+layout.svelte @@ -84,7 +84,7 @@ ] }, { - label: 'Journeys', + label: 'Guides', items: [ { label: 'Send push notifications', diff --git a/src/routes/docs/products/messaging/fcm/+page.markdoc b/src/routes/docs/products/messaging/fcm/+page.markdoc index b674fcdbb16..d769eeee1fe 100644 --- a/src/routes/docs/products/messaging/fcm/+page.markdoc +++ b/src/routes/docs/products/messaging/fcm/+page.markdoc @@ -57,7 +57,7 @@ Some additional configuration is required to enable push notifications in your m 1. Add `google-services.json` at the root of your project. 1. Add Google Services class path to your app-level Gradle dependencies block `"com.google.gms:google-services:4.4.0"`. 1. Add Google Services plugin to your app-level Gradle in the plugins block as `"com.google.gms.google-services"`. -1. Add notification handler service to `AndroidManifest.xml` inside the application tag, alongside other activities. Find an example of this service in the [Send push notification](/docs/products/messaging/send-push-notifications#add-targets) journey. +1. Add notification handler service to `AndroidManifest.xml` inside the application tag, alongside other activities. Find an example of this service in the [Send push notification](/docs/products/messaging/send-push-notifications#add-targets) guide. ```xml diff --git a/src/routes/docs/products/messaging/mailgun/+page.markdoc b/src/routes/docs/products/messaging/mailgun/+page.markdoc index 2b63a570aed..597b5e91867 100644 --- a/src/routes/docs/products/messaging/mailgun/+page.markdoc +++ b/src/routes/docs/products/messaging/mailgun/+page.markdoc @@ -319,7 +319,7 @@ async fn main() -> Result<(), Box> { {% /tabsitem %} {% /tabs %} -You can follow the [Send email messages](/docs/products/messaging/send-push-notifications) journey to send your first push notification and test your provider. +You can follow the [Send email messages](/docs/products/messaging/send-push-notifications) guide to send your first push notification and test your provider. {% /section %} {% section #manage-provider step=4 title="Manage provider" %} diff --git a/src/routes/docs/products/messaging/msg91/+page.markdoc b/src/routes/docs/products/messaging/msg91/+page.markdoc index 0ea24698aec..62e4cd076ab 100644 --- a/src/routes/docs/products/messaging/msg91/+page.markdoc +++ b/src/routes/docs/products/messaging/msg91/+page.markdoc @@ -353,7 +353,7 @@ async fn main() -> Result<(), Box> { {% /tabsitem %} {% /tabs %} -You can follow the [Send email messages](/docs/products/messaging/send-sms-messages) journey to send your first push notification and test your provider. +You can follow the [Send email messages](/docs/products/messaging/send-sms-messages) guide to send your first push notification and test your provider. {% /section %} diff --git a/src/routes/docs/products/messaging/sendgrid/+page.markdoc b/src/routes/docs/products/messaging/sendgrid/+page.markdoc index 37ade828b70..0ce661d1afb 100644 --- a/src/routes/docs/products/messaging/sendgrid/+page.markdoc +++ b/src/routes/docs/products/messaging/sendgrid/+page.markdoc @@ -312,7 +312,7 @@ async fn main() -> Result<(), Box> { {% /tabsitem %} {% /tabs %} -You can follow the [Send email messages](/docs/products/messaging/send-email-messages) journey to send your first push notification and test your provider. +You can follow the [Send email messages](/docs/products/messaging/send-email-messages) guide to send your first push notification and test your provider. {% /section %} {% section #manage-provider step=4 title="Manage provider" %} diff --git a/src/routes/docs/products/messaging/smtp/+page.markdoc b/src/routes/docs/products/messaging/smtp/+page.markdoc index 52e7fd580ab..055fdad50b9 100644 --- a/src/routes/docs/products/messaging/smtp/+page.markdoc +++ b/src/routes/docs/products/messaging/smtp/+page.markdoc @@ -321,7 +321,7 @@ async fn main() -> Result<(), Box> { {% /tabsitem %} {% /tabs %} -You can follow the [Send email messages](/docs/products/messaging/send-push-notifications) journey to send your first push notification and test your provider. +You can follow the [Send email messages](/docs/products/messaging/send-push-notifications) guide to send your first push notification and test your provider. {% /section %} {% section #manage-provider step=4 title="Manage provider" %} diff --git a/src/routes/docs/products/messaging/targets/+page.markdoc b/src/routes/docs/products/messaging/targets/+page.markdoc index 26c8bf9d1fa..2b6a9344c64 100644 --- a/src/routes/docs/products/messaging/targets/+page.markdoc +++ b/src/routes/docs/products/messaging/targets/+page.markdoc @@ -71,7 +71,7 @@ Push notifications require configuration on both the Appwrite platform and your 1. Add `google-services.json` at the root of your project. 1. Add Google Services class path to your app-level Gradle dependencies block `"com.google.gms:google-services:4.4.0"`. 1. Add Google Services plugin to your app-level Gradle in the plugins block as `"com.google.gms.google-services"`. -1. Add notification handler service to `AndroidManifest.xml` inside the application tag, alongside other activities. Find an example of this service in the [Send push notification](/docs/products/messaging/send-push-notifications#add-targets) journey. +1. Add notification handler service to `AndroidManifest.xml` inside the application tag, alongside other activities. Find an example of this service in the [Send push notification](/docs/products/messaging/send-push-notifications#add-targets) guide. ```xml diff --git a/src/routes/docs/products/messaging/telesign/+page.markdoc b/src/routes/docs/products/messaging/telesign/+page.markdoc index 3b8292fd328..db63679d533 100644 --- a/src/routes/docs/products/messaging/telesign/+page.markdoc +++ b/src/routes/docs/products/messaging/telesign/+page.markdoc @@ -352,7 +352,7 @@ async fn main() -> Result<(), Box> { {% /tabsitem %} {% /tabs %} -You can follow the [Send SMS messages](/docs/products/messaging/send-sms-messages) journey to send your first push notification and test your provider. +You can follow the [Send SMS messages](/docs/products/messaging/send-sms-messages) guide to send your first push notification and test your provider. {% /section %} {% section #manage-provider step=4 title="Manage provider" %} diff --git a/src/routes/docs/products/messaging/textmagic/+page.markdoc b/src/routes/docs/products/messaging/textmagic/+page.markdoc index 76d09c143e0..bd9e5869ddf 100644 --- a/src/routes/docs/products/messaging/textmagic/+page.markdoc +++ b/src/routes/docs/products/messaging/textmagic/+page.markdoc @@ -352,7 +352,7 @@ async fn main() -> Result<(), Box> { {% /tabsitem %} {% /tabs %} -You can follow the [Send SMS messages](/docs/products/messaging/send-sms-messages) journey to send your first push notification and test your provider. +You can follow the [Send SMS messages](/docs/products/messaging/send-sms-messages) guide to send your first push notification and test your provider. {% /section %} {% section #manage-provider step=4 title="Manage provider" %} diff --git a/src/routes/docs/products/messaging/topics/+page.markdoc b/src/routes/docs/products/messaging/topics/+page.markdoc index bb31eee9fd8..33f783ebb7c 100644 --- a/src/routes/docs/products/messaging/topics/+page.markdoc +++ b/src/routes/docs/products/messaging/topics/+page.markdoc @@ -322,7 +322,7 @@ Learn more about the CLI topics commands Before you can subscribe to a topic, a user needs the appropriate permission. You can set permission by navigating to **Messaging** > **Topics** > select a topic to configure > **Subscription access**. -{% arrow_link href="/docs/advanced/platform/permissions#permission-roles" %} +{% arrow_link href="/docs/advanced/security/permissions#permission-roles" %} Learn more about permission roles {% /arrow_link %} diff --git a/src/routes/docs/products/messaging/vonage/+page.markdoc b/src/routes/docs/products/messaging/vonage/+page.markdoc index 0d57869a326..e3ff2728dfe 100644 --- a/src/routes/docs/products/messaging/vonage/+page.markdoc +++ b/src/routes/docs/products/messaging/vonage/+page.markdoc @@ -354,7 +354,7 @@ async fn main() -> Result<(), Box> { {% /tabsitem %} {% /tabs %} -You can follow the [Send SMS messages](/docs/products/messaging/send-sms-messages) journey to send your first push notification and test your provider. +You can follow the [Send SMS messages](/docs/products/messaging/send-sms-messages) guide to send your first push notification and test your provider. {% /section %} {% section #manage-provider step=4 title="Manage provider" %} diff --git a/src/routes/docs/products/network/+layout.svelte b/src/routes/docs/products/network/+layout.svelte index fe7304d018f..3e18199798b 100644 --- a/src/routes/docs/products/network/+layout.svelte +++ b/src/routes/docs/products/network/+layout.svelte @@ -41,6 +41,10 @@ { label: 'Features', items: [ + { + label: 'Custom domains', + href: '/docs/products/network/custom-domains' + }, { label: 'DNS', href: '/docs/products/network/dns' diff --git a/src/routes/docs/products/network/caa-records/+page.markdoc b/src/routes/docs/products/network/caa-records/+page.markdoc index d59532fa143..35b9d92f41f 100644 --- a/src/routes/docs/products/network/caa-records/+page.markdoc +++ b/src/routes/docs/products/network/caa-records/+page.markdoc @@ -6,7 +6,7 @@ description: Learn what DNS Certification Authority Authorization (CAA) records A Certification Authority Authorization (CAA) record is a DNS record that specifies which certificate authorities (CAs) are allowed to issue TLS certificates for your domain. CAA records help prevent unauthorized certificate issuance and are defined in [RFC 8659](https://datatracker.ietf.org/doc/html/rfc8659). -When Appwrite issues a TLS certificate for a [custom domain](/docs/advanced/platform/custom-domains), an [Appwrite Sites domain](/docs/products/sites/domains), or a [Function domain](/docs/products/functions/domains), the certificate authority used by Appwrite checks your domain's CAA records before issuing. If your domain has no CAA records at all, any CA, including Appwrite's, is allowed to issue and no action is needed from you. If your domain already has CAA records and none of them authorize the CA that Appwrite uses, issuance fails and your domain stays unverified until you add the required record. +When Appwrite issues a TLS certificate for a [custom domain](/docs/products/network/custom-domains), an [Appwrite Sites domain](/docs/products/sites/domains), or a [Function domain](/docs/products/functions/domains), the certificate authority used by Appwrite checks your domain's CAA records before issuing. If your domain has no CAA records at all, any CA, including Appwrite's, is allowed to issue and no action is needed from you. If your domain already has CAA records and none of them authorize the CA that Appwrite uses, issuance fails and your domain stays unverified until you add the required record. {% info title="CAA records are additive, not exclusive" %} Adding a CAA record for Appwrite does **not** replace your existing CAA records, override certificates issued by other CAs, or invalidate certificates already in use elsewhere. CAA only controls **future** certificate issuance. You can safely keep every CAA record you already have and add Appwrite's alongside them. See [Setting multiple CAA records](#multiple). diff --git a/src/routes/docs/advanced/platform/custom-domains/+page.markdoc b/src/routes/docs/products/network/custom-domains/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/custom-domains/+page.markdoc rename to src/routes/docs/products/network/custom-domains/+page.markdoc diff --git a/src/routes/docs/products/sites/+layout.svelte b/src/routes/docs/products/sites/+layout.svelte index 36454587f7d..62c76a92ce8 100644 --- a/src/routes/docs/products/sites/+layout.svelte +++ b/src/routes/docs/products/sites/+layout.svelte @@ -59,7 +59,7 @@ ] }, { - label: 'Journeys', + label: 'Guides', items: [ { label: 'Templates', diff --git a/src/routes/docs/products/sites/deployments/+page.markdoc b/src/routes/docs/products/sites/deployments/+page.markdoc index 428d12a4c97..441e97ccbcb 100644 --- a/src/routes/docs/products/sites/deployments/+page.markdoc +++ b/src/routes/docs/products/sites/deployments/+page.markdoc @@ -81,8 +81,8 @@ Redeployment behavior varies depending on how the initial deployment was created Users subscribed to the Appwrite Pro plan or above receive certain special benefits: - [Express builds](/changelog/entry/2024-08-10) for quicker deployments, resulting in reduced wait times and smoother workflows -- Longer [build timeouts](/docs/advanced/platform/compute#build-timeouts) (45 minutes vs 15 minutes on Free; Enterprise is custom) -- Customizable [build and runtime specifications](/docs/advanced/platform/compute) for CPU and memory on each site +- Longer [build timeouts](/docs/advanced/billing/compute#build-timeouts) (45 minutes vs 15 minutes on Free; Enterprise is custom) +- Customizable [build and runtime specifications](/docs/advanced/billing/compute) for CPU and memory on each site {% /info %} # Deployment retention {% #deployment-retention %} diff --git a/src/routes/docs/products/sites/develop/+page.markdoc b/src/routes/docs/products/sites/develop/+page.markdoc index ff9bd7bd93a..fba0eb17a10 100644 --- a/src/routes/docs/products/sites/develop/+page.markdoc +++ b/src/routes/docs/products/sites/develop/+page.markdoc @@ -49,11 +49,11 @@ The default timeout is set at `15 seconds` and the maximum value possible is `30 Under **Settings** - **Resource limits**, you can set **build** and **runtime** specifications independently. The build spec applies while dependencies are installed and your site is built for deployment; the runtime spec applies when your site serves traffic, including server-side rendering (SSR). Both use the same CPU and memory tiers on Cloud. -On Appwrite Cloud, customizing specifications requires the **Pro** plan. See [Compute](/docs/advanced/platform/compute) for tiers, GB-hours, and pricing. +On Appwrite Cloud, customizing specifications requires the **Pro** plan. See [Compute](/docs/advanced/billing/compute) for tiers, GB-hours, and pricing. ## Build timeouts {% #build-timeouts %} -On Appwrite Cloud, the **build** phase of each deployment must complete within your plan’s **maximum build duration** (for example, 15 minutes on Free and 45 minutes on Pro and Scale). See [Build timeouts](/docs/advanced/platform/compute#build-timeouts) and the [pricing page](/pricing). +On Appwrite Cloud, the **build** phase of each deployment must complete within your plan’s **maximum build duration** (for example, 15 minutes on Free and 45 minutes on Pro and Scale). See [Build timeouts](/docs/advanced/billing/compute#build-timeouts) and the [pricing page](/pricing). # Project dependencies diff --git a/src/routes/docs/products/sites/environment-variables/+page.markdoc b/src/routes/docs/products/sites/environment-variables/+page.markdoc index e504120b862..c10d6a825f5 100644 --- a/src/routes/docs/products/sites/environment-variables/+page.markdoc +++ b/src/routes/docs/products/sites/environment-variables/+page.markdoc @@ -8,7 +8,7 @@ Appwrite Sites can read environment variables at build and runtime. Use them to A site reads from three sources, in this order of precedence: -1. **Project variables** are shared across every function and site in your project. Set them once and every site inherits them automatically. See [project variables](/docs/advanced/platform/environment-variables) for the platform-wide reference. +1. **Project variables** are shared across every function and site in your project. Set them once and every site inherits them automatically. See [project variables](/docs/advanced/security/environment-variables) for the full reference. 2. **Site variables** are scoped to a single site. Override a project variable for one site by setting the same key on the site itself. 3. **Appwrite-injected variables** are set by Appwrite at deployment time (for example, `APPWRITE_SITE_PROJECT_ID`). These take final precedence and cannot be overridden. @@ -31,11 +31,11 @@ Variable changes only take effect on the next deployment. Redeploy your site aft ![Site environment variables](/images/docs/sites/env-variables.avif) {% /only_light %} -You can also configure global variables that apply to all your sites from your project's **Settings** page. See [project variables](/docs/advanced/platform/environment-variables) for details. +You can also configure global variables that apply to all your sites from your project's **Settings** page. See [project variables](/docs/advanced/security/environment-variables) for details. # Manage with a Server SDK {% #server-sdks %} -You can also manage site variables programmatically using a [Server SDK](/docs/sdks#server). Each call requires an [API key](/docs/advanced/platform/api-keys) with the `sites.write` scope to create, update, or delete variables, or the `sites.read` scope to list and read them. +You can also manage site variables programmatically using a [Server SDK](/docs/sdks#server). Each call requires an [API key](/docs/advanced/security/api-keys) with the `sites.write` scope to create, update, or delete variables, or the `sites.read` scope to list and read them. ## Create a variable {% #create-variable %} diff --git a/src/routes/docs/products/storage/+layout.svelte b/src/routes/docs/products/storage/+layout.svelte index 358647ae855..122404835c6 100644 --- a/src/routes/docs/products/storage/+layout.svelte +++ b/src/routes/docs/products/storage/+layout.svelte @@ -39,7 +39,7 @@ ] }, { - label: 'Journeys', + label: 'Guides', items: [ { label: 'Upload and download', diff --git a/src/routes/docs/products/storage/buckets/+page.markdoc b/src/routes/docs/products/storage/buckets/+page.markdoc index 2609ca305b3..fb5f76e4947 100644 --- a/src/routes/docs/products/storage/buckets/+page.markdoc +++ b/src/routes/docs/products/storage/buckets/+page.markdoc @@ -23,7 +23,7 @@ You can create a bucket by heading to the **Storage** page and clicking **Create {% /tabsitem %} {% tabsitem #server-sdk title="Server SDK" %} -You can also create tables programmatically using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/platform/api-keys). +You can also create tables programmatically using a [Server SDK](/docs/sdks#server). Appwrite [Server SDKs](/docs/sdks#server) require an [API key](/docs/advanced/security/api-keys). {% multicode %} diff --git a/src/routes/docs/products/storage/file-tokens/+page.markdoc b/src/routes/docs/products/storage/file-tokens/+page.markdoc index 852c0b41ace..1c08c572d3b 100644 --- a/src/routes/docs/products/storage/file-tokens/+page.markdoc +++ b/src/routes/docs/products/storage/file-tokens/+page.markdoc @@ -41,7 +41,7 @@ You can then click on the three-dots menu, click on **Copy URL** and get the tok {% tabsitem #server-sdk title="Server SDK" %} -You can create file tokens programmatically using a [Server SDK](/docs/references/cloud/server-nodejs/tokens#createFileToken). Appwrite's Server SDKs require an [API key](/docs/advanced/platform/api-keys) with the `tokens.write` scope enabled. +You can create file tokens programmatically using a [Server SDK](/docs/references/cloud/server-nodejs/tokens#createFileToken). Appwrite's Server SDKs require an [API key](/docs/advanced/security/api-keys) with the `tokens.write` scope enabled. {% multicode %} ```server-nodejs @@ -345,7 +345,7 @@ Head to the **Storage** page, open a file inside a bucket, and scroll down to th {% tabsitem #server-sdk title="Server SDK" %} -You can list all file tokens programmatically using a [Server SDK](/docs/references/cloud/server-nodejs/tokens#list). Appwrite's Server SDKs require an [API key](/docs/advanced/platform/api-keys) with the `tokens.read` scope enabled. +You can list all file tokens programmatically using a [Server SDK](/docs/references/cloud/server-nodejs/tokens#list). Appwrite's Server SDKs require an [API key](/docs/advanced/security/api-keys) with the `tokens.read` scope enabled. {% multicode %} ```server-nodejs @@ -724,7 +724,7 @@ Head to the **Storage** page, open a file inside a bucket, and scroll down to th {% tabsitem #server-sdk title="Server SDK" %} -You can update file token expiry programmatically using a [Server SDK](/docs/references/cloud/server-nodejs/tokens#update). Appwrite's Server SDKs require an [API key](/docs/advanced/platform/api-keys) with the `tokens.write` scope enabled. +You can update file token expiry programmatically using a [Server SDK](/docs/references/cloud/server-nodejs/tokens#update). Appwrite's Server SDKs require an [API key](/docs/advanced/security/api-keys) with the `tokens.write` scope enabled. {% multicode %} ```server-nodejs @@ -1014,7 +1014,7 @@ Head to the **Storage** page, open a file inside a bucket, and scroll down to th {% tabsitem #server-sdk title="Server SDK" %} -You can delete a file token programmatically using a [Server SDK](/docs/references/cloud/server-nodejs/tokens#delete). Appwrite's Server SDKs require an [API key](/docs/advanced/platform/api-keys) with the `tokens.write` scope enabled. +You can delete a file token programmatically using a [Server SDK](/docs/references/cloud/server-nodejs/tokens#delete). Appwrite's Server SDKs require an [API key](/docs/advanced/security/api-keys) with the `tokens.write` scope enabled. {% multicode %} ```server-nodejs diff --git a/src/routes/docs/products/storage/permissions/+page.markdoc b/src/routes/docs/products/storage/permissions/+page.markdoc index e948c54267c..8a84d80fd53 100644 --- a/src/routes/docs/products/storage/permissions/+page.markdoc +++ b/src/routes/docs/products/storage/permissions/+page.markdoc @@ -17,7 +17,7 @@ If a user has read, create, update, or delete permissions at the bucket level, t Configure bucket level permissions by navigating to **Your bucket** > **Settings** > **Permissions**. -[Learn more about permissions and roles](/docs/advanced/platform/permissions) +[Learn more about permissions and roles](/docs/advanced/security/permissions) # File level {% #file-level %} File level permissions grant access to individual files. @@ -28,6 +28,6 @@ Enable file level permissions by navigating to **Your bucket** > **Settings** > File level permissions are configured in individual [files](/docs/products/storage/permissions#file-level). -[Learn more about permissions and roles](/docs/advanced/platform/permissions) +[Learn more about permissions and roles](/docs/advanced/security/permissions) diff --git a/src/routes/docs/quick-starts/flutter/+page.markdoc b/src/routes/docs/quick-starts/flutter/+page.markdoc index a85051b34cb..2f193925940 100644 --- a/src/routes/docs/quick-starts/flutter/+page.markdoc +++ b/src/routes/docs/quick-starts/flutter/+page.markdoc @@ -56,7 +56,7 @@ The callbackUrlScheme parameter in the authenticate() method isn't applicable wh {% info title="Flutter web cross-domain communication & cookies" %} While running Flutter Web, make sure your Appwrite project and your Flutter client use the same top-level domain and protocol (HTTP or HTTPS) to communicate. When communicating between different domains or protocols, you may receive HTTP status error 401 because some modern browsers block cross-site or insecure cookies for enhanced privacy. -In production, Appwrite allows you to set multiple [custom-domains](/docs/advanced/platform/custom-domains) for each project. +In production, Appwrite allows you to set multiple [custom-domains](/docs/products/network/custom-domains) for each project. {% /info %} {% /tabsitem %} diff --git a/src/routes/docs/quick-starts/nextjs/+page.markdoc b/src/routes/docs/quick-starts/nextjs/+page.markdoc index 3487e84f12f..cad7ea61b8c 100644 --- a/src/routes/docs/quick-starts/nextjs/+page.markdoc +++ b/src/routes/docs/quick-starts/nextjs/+page.markdoc @@ -1,12 +1,14 @@ --- layout: article title: Start with Next.js -description: Learn how to use Appwrite to add authentication, user management, file storage, and more to your Next.js apps. +description: Build Next.js apps with the Appwrite React library. Add server-rendered authentication, sign-in, sign-up, and user state without writing the SSR plumbing yourself. difficulty: beginner -readtime: 3 +readtime: 7 back: /docs/quick-starts --- -Learn how to setup your first Next.js project powered by Appwrite. + +Learn how to set up your first Next.js project with the [Appwrite React library](/docs/products/auth/react). The library ships SSR auth handlers, server helpers, and the same React hooks you use on the client. + {% section #step-1 step=1 title="Create project" %} Head to the [Appwrite Console](https://cloud.appwrite.io/console). @@ -33,99 +35,178 @@ Then, under **Add a platform**, add a **Web app**. The **Hostname** should be `l You can skip optional steps. {% /section %} -{% section #step-2 step=2 title="Create Next.js project" %} -Create a Next.js project by running the following command: + +{% section #step-2 step=2 title="Create an API key" %} + +In your project, go to **Overview** > **Integrations** > **API keys** and create a new key with the scopes `users.read`, `users.write`, and `sessions.write`. Copy the key secret. The SSR handler uses this to create sessions on behalf of users; never expose it to the browser. + +{% /section %} + +{% section #step-3 step=3 title="Create Next.js project" %} + +Create a Next.js project with TypeScript and the App Router. ```sh -npx create-next-app@latest && cd my-app +npx create-next-app@latest my-app --ts --app && cd my-app ``` -When prompted, configure your project with these recommended settings: -- **Would you like to use TypeScript?** → No -- **Would you like to use ESLint?** → Yes -- **Would you like to use Tailwind CSS?** → No (unless you plan to use it) -- **Would you like to use `src/` directory?** → Yes/No (either works for this tutorial) -- **Would you like to use App Router?** → Yes -- **Would you like to customize the default import alias?** → No +Accept the defaults for the remaining prompts. -These settings will create a minimal Next.js setup that's perfect for getting started with Appwrite. {% /section %} -{% section #step-3 step=3 title="Install Appwrite SDK" %} -Install the JavaScript Appwrite SDK. +{% section #step-4 step=4 title="Install the React library" %} + +Install the React library along with the Appwrite Web SDK, Appwrite Node SDK, and `@tanstack/react-query` packages. ```sh -npm install appwrite +npm install @appwrite.io/react appwrite node-appwrite @tanstack/react-query ``` + {% /section %} -{% section #step-4 step=4 title="Define Appwrite service" %} -Find your project's ID in the **Settings** page. -{% only_dark %} -![Project settings screen](/images/docs/quick-starts/dark/project-id.avif) -{% /only_dark %} -{% only_light %} -![Project settings screen](/images/docs/quick-starts/project-id.avif) -{% /only_light %} +{% section #step-5 step=5 title="Configure environment variables" %} + +Create a `.env.local` file at the project root. Replace ``, ``, and `` with your own values. + +```sh +NEXT_PUBLIC_APPWRITE_ENDPOINT=https://.cloud.appwrite.io/v1 +NEXT_PUBLIC_APPWRITE_PROJECT_ID= +APPWRITE_API_KEY= +``` + +`NEXT_PUBLIC_*` values are shipped to the browser. `APPWRITE_API_KEY` stays server-only. + +{% /section %} + +{% section #step-6 step=6 title="Mount the auth handler route" %} + +Create `app/api/appwrite/[...appwrite]/route.ts`. The handler exposes the `sign-in`, `sign-up`, `sign-out`, and `oauth/callback` endpoints that the React hooks POST to in SSR mode. + +```ts +import { createAppwriteHandlers } from "@appwrite.io/react/handlers/next"; + +export const { GET, POST } = createAppwriteHandlers({ + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, + apiKey: process.env.APPWRITE_API_KEY!, + basePath: "/api/appwrite", +}); +``` + +{% /section %} + +{% section #step-7 step=7 title="Wrap your app with AppwriteProvider" %} + +Create `app/providers.tsx`. The provider runs in client components and accepts the SSR session secret as a prop so the underlying Web SDK can hydrate authenticated. + +```tsx +"use client"; + +import { AppwriteProvider } from "@appwrite.io/react"; + +export function Providers({ + session, + children, +}: { + session?: string | null; + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} +``` -Create a new file `app/appwrite.js` and add the following code to it, replace `` with your project ID. +Replace `app/layout.tsx` with the following. It reads the session cookie on the server and passes it into the provider. -```client-web -import { Client, Account } from 'appwrite'; +```tsx +import { createNextServerHelpers } from "@appwrite.io/react/server/next"; +import { Providers } from "./providers"; -export const client = new Client(); +const appwrite = { + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, +}; -client - .setEndpoint('https://.cloud.appwrite.io/v1') - .setProject(''); // Replace with your project ID +export default async function RootLayout({ + children, +}: Readonly<{ children: React.ReactNode }>) { + const helpers = createNextServerHelpers(appwrite); + const session = await helpers.readSessionCookie(); -export const account = new Account(client); -export { ID } from 'appwrite'; + return ( + + + {children} + + + ); +} +``` + +{% /section %} + +{% section #step-8 step=8 title="Read the user on the server" %} + +Replace `app/page.tsx`. `getLoggedInUser()` calls the Appwrite API server-side with the session cookie, so the user is rendered with the first byte. + +```tsx +import { createNextServerHelpers } from "@appwrite.io/react/server/next"; +import { AuthPanel } from "./auth-panel"; + +const appwrite = { + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, +}; + +export default async function Page() { + const helpers = createNextServerHelpers(appwrite); + const user = await helpers.getLoggedInUser(); + + return ( +
+

Appwrite React library on Next.js

+

SSR user: {user?.email ?? "signed out"}

+ +
+ ); +} ``` + {% /section %} -{% section #step-5 step=5 title="Create a login page" %} -Create or update `app/page.js` file and add the following code to it. -```js +{% section #step-9 step=9 title="Add the client auth panel" %} + +Create `app/auth-panel.tsx`. The hooks POST to the handler route, the server sets a cookie, and `router.refresh()` re-runs the server component so the SSR user updates. + +```tsx "use client"; + import { useState } from "react"; -import { account, ID } from "./appwrite"; +import { useAuth } from "@appwrite.io/react"; +import { useRouter } from "next/navigation"; -const LoginPage = () => { - const [loggedInUser, setLoggedInUser] = useState(null); +export function AuthPanel() { + const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); + const router = useRouter(); const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); const [name, setName] = useState(""); - const login = async (email, password) => { - const session = await account.createEmailPasswordSession({ - email, - password - }); - setLoggedInUser(await account.get()); - }; - - const register = async () => { - await account.create({ - userId: ID.unique(), - email, - password, - name - }); - login(email, password); - }; - - const logout = async () => { - await account.deleteSession({ sessionId: 'current' }); - setLoggedInUser(null); - }; - - if (loggedInUser) { + if (isLoading) return

Loading...

; + + if (user) { return (
-

Logged in as {loggedInUser.name}

-
); @@ -133,43 +214,57 @@ const LoginPage = () => { return (
-

Not logged in

-
- setEmail(e.target.value)} - /> - setPassword(e.target.value)} - /> - setName(e.target.value)} - /> - - -
+ setName(e.target.value)} /> + setEmail(e.target.value)} /> + setPassword(e.target.value)} + /> + + + {error &&

{error.message}

}
); -}; - -export default LoginPage; +} ``` + {% /section %} -{% section #step-6 step=6 title="All set" %} -Run your project with `npm run dev` and open [Localhost on Port 3000](http://localhost:3000) in your browser. +{% section #step-10 step=10 title="Run your app" %} + +```sh +npm run dev +``` + +Open [localhost on port 3000](http://localhost:3000). Sign up, sign out, and sign back in to verify the cookie-based SSR flow. -Don't forget to add some CSS to suit your style. {% /section %} + +# Next steps {% #next-steps %} + +For server-side admin operations, per-request session clients, OAuth callbacks, and the full hook reference, see the [React library docs](/docs/products/auth/react). diff --git a/src/routes/docs/quick-starts/nextjs/prompt.md b/src/routes/docs/quick-starts/nextjs/prompt.md index 2e159d12260..689a894c855 100644 --- a/src/routes/docs/quick-starts/nextjs/prompt.md +++ b/src/routes/docs/quick-starts/nextjs/prompt.md @@ -1,80 +1,213 @@ ## Add Appwrite Auth to a New Next.js App -Add Appwrite auth to a new Next.js app (**App Router**), with a working login/register/logout page. +Add Appwrite auth to a new Next.js app (**App Router**) using the official Appwrite React library, with a working sign-up, sign-in, and sign-out flow backed by SSR session cookies. - Do exactly these steps in order. Confirm each step succeeds before continuing. If any command fails, show the error and fix it automatically. - Respect the user's package manager at all times. Do not use NPM if the user uses something else. -## Step 1: Create or Use Existing Next.js App +## Step 1: Create or use existing Next.js app - First, check if the current working directory contains files that appear unrelated to a development workspace (e.g., personal files, downloads, random documents, media files). If so, ask the user: "This directory contains files that don't look like a development project. Would you like to proceed here anyway, or create a subdirectory with a specific folder name?" - If the directory is empty OR contains an existing project (`package.json`, source code, config files, etc.), proceed with integration without asking. - Create the project in the current working directory (`.`) - do NOT use `cd` to switch directories. - If you already have a Next.js project open, stay in it and integrate Appwrite into it (**App Router** required). -- Otherwise, run: `npx create-next-app@latest . --eslint` -- When prompted: **TypeScript** = No, **ESLint** = Yes, **Tailwind** = No, **src dir** = your choice, **App Router** = Yes, **Import alias** = No. +- Otherwise, run: `npx create-next-app@latest . --ts --app` +- Accept the defaults for the remaining prompts. -## Step 2: Install Appwrite SDK +## Step 2: Install the Appwrite React library -- Run: `npm install appwrite` +- Run: `npm install @appwrite.io/react appwrite node-appwrite @tanstack/react-query` -## Step 3: Create Appwrite Client Module +## Step 3: Configure environment variables _Ask the user for details; never assume._ - Ask the user for: - **Appwrite Cloud Region** (e.g. `fra`, `nyc`) - **Project ID** (from Console -> Settings) -- If the user doesn't know, guide them to the **Appwrite Console** to copy these. Do not attempt to infer or access their project. -- Hardcode the endpoint and project ID in the file `app/appwrite.js` (or `app/appwrite.ts` if TS) if provided, else leave a placeholder and ask the user to provide them. -- Create file `app/appwrite.js` (or `app/appwrite.ts` if TS) with key snippet: - -```js -import { Client, Account } from 'appwrite'; -const endpoint = ''; -const projectId = ''; -if (!endpoint || !projectId) throw new Error('Missing Appwrite endpoint and project ID'); -export const client = new Client().setEndpoint(endpoint).setProject(projectId); -export const account = new Account(client); -export { ID } from 'appwrite'; + - **API key** with scopes `users.read`, `users.write`, `sessions.write` (Console -> Overview -> Integrations -> API keys) +- Create a `.env.local` file at the project root: + +```sh +NEXT_PUBLIC_APPWRITE_ENDPOINT=https://.cloud.appwrite.io/v1 +NEXT_PUBLIC_APPWRITE_PROJECT_ID= +APPWRITE_API_KEY= +``` + +- The `APPWRITE_API_KEY` is server-only. Never expose it to the browser. + +## Step 4: Mount the auth handler route + +- Create `app/api/appwrite/[...appwrite]/route.ts` so the library's sign-in, sign-up, sign-out, and OAuth callback endpoints are reachable: + +```ts +import { createAppwriteHandlers } from '@appwrite.io/react/handlers/next'; + +export const { GET, POST } = createAppwriteHandlers({ + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID!, + apiKey: process.env.APPWRITE_API_KEY!, + basePath: '/api/appwrite' +}); +``` + +## Step 5: Wrap the app with AppwriteProvider + +- Create `app/providers.tsx`: + +```tsx +'use client'; + +import { AppwriteProvider } from '@appwrite.io/react'; + +export function Providers({ + session, + children +}: { + session?: string | null; + children: React.ReactNode; +}) { + return ( + + {children} + + ); +} +``` + +- Replace `app/layout.tsx` to read the session cookie server-side and pass it into the provider: + +```tsx +import { createNextServerHelpers } from '@appwrite.io/react/server/next'; +import { Providers } from './providers'; + +const appwrite = { + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID! +}; + +export default async function RootLayout({ children }: Readonly<{ children: React.ReactNode }>) { + const helpers = createNextServerHelpers(appwrite); + const session = await helpers.readSessionCookie(); + + return ( + + + {children} + + + ); +} ``` -## Step 4: Build the Login Page (Client Component) +## Step 6: Build the auth page + +- If this is a fresh project you just created, replace `app/page.tsx` to read the user server-side and render the auth panel. If you are working in an existing project, create a new route (e.g. `app/auth/page.tsx`) instead of overriding the default route. + +```tsx +import { createNextServerHelpers } from '@appwrite.io/react/server/next'; +import { AuthPanel } from './auth-panel'; + +const appwrite = { + endpoint: process.env.NEXT_PUBLIC_APPWRITE_ENDPOINT!, + projectId: process.env.NEXT_PUBLIC_APPWRITE_PROJECT_ID! +}; + +export default async function Page() { + const helpers = createNextServerHelpers(appwrite); + const user = await helpers.getLoggedInUser(); -- If this is a fresh project you just created above, you may replace `app/page.js` with this component using `"use client"`. -- If you are working in an existing project, create a new route `app/auth/page.js` (or `.tsx`) instead of overriding the default route. -- It must render: - - Email/password inputs - - Name input for registration - - Buttons: **Login**, **Register**, **Logout** - - Shows "Logged in as \" when a session exists -- Implement functions: - - `login(email, password)`: `account.createEmailPasswordSession({ email, password })` then set user via `account.get()` - - `register()`: `account.create({ userId: ID.unique(), email, password, name })` then call `login` - - `logout()`: `account.deleteSession({ sessionId: 'current' })` then clear user state + return ( +
+

SSR user: {user?.email ?? 'signed out'}

+ +
+ ); +} +``` + +- Create `app/auth-panel.tsx` for the client-side hook usage: + +```tsx +'use client'; + +import { useState } from 'react'; +import { useAuth } from '@appwrite.io/react'; +import { useRouter } from 'next/navigation'; + +export function AuthPanel() { + const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); + const router = useRouter(); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [name, setName] = useState(''); + + if (isLoading) return

Loading...

; + + if (user) { + return ( + + ); + } + + return ( +
+ setName(e.target.value)} /> + setEmail(e.target.value)} /> + setPassword(e.target.value)} + /> + + + {error &&

{error.message}

} +
+ ); +} +``` -## Step 5: Verify Environment +## Step 7: Verify environment _Ask the user to confirm._ -- Confirm with the user that the endpoint and project ID are hardcoded in the file `app/appwrite.js` (or `app/appwrite.ts` if TS). +- Confirm `.env.local` has the endpoint, project ID, and API key set. - Ensure the **Web** app platform exists in **Appwrite Console** with **Hostname** = `localhost`. If missing, guide the user to add it. -## Step 6: Run and Test +## Step 8: Run and test - Run: `npm run dev` - Open: `http://localhost:3000` - Test flows: - - Register a new user and auto login works - - Logout then login again -- Surface any Appwrite errors (invalid project, endpoint, CORS/hostname) and fix by guiding updates to `appwrite.js` and **Console** settings. - -## Step 7: Optional Hardening - -- If the user wants TypeScript, create `app/appwrite.ts` and `app/page.tsx` with proper types. -- Add minimal styling if requested; functionality first. + - Sign up a new user, confirm the SSR-rendered user reflects the change after `router.refresh()` + - Sign out, then sign in again +- Surface any Appwrite errors (invalid project, endpoint, CORS/hostname, missing key scopes) and fix by guiding updates to `.env.local` and Console settings. ## Deliverables -- A running Next.js app with working Appwrite auth (register/login/logout) -- Files created/updated: `package.json` (deps), `app/appwrite.js`, `app/page.js` +- A running Next.js app with working Appwrite auth using `@appwrite.io/react` +- Files created/updated: `package.json` (deps), `.env.local`, `app/api/appwrite/[...appwrite]/route.ts`, `app/providers.tsx`, `app/layout.tsx`, `app/page.tsx`, `app/auth-panel.tsx` diff --git a/src/routes/docs/quick-starts/react/+page.markdoc b/src/routes/docs/quick-starts/react/+page.markdoc index f416f6981a5..da8e8fd8eec 100644 --- a/src/routes/docs/quick-starts/react/+page.markdoc +++ b/src/routes/docs/quick-starts/react/+page.markdoc @@ -1,13 +1,14 @@ --- layout: article title: Start with React -description: Build React apps with Appwrite and learn how to use our powerful backend to add authentication, user management, file storage, and more. +description: Build React apps with the Appwrite React library and add authentication, sign-in, sign-up, and user state in a few lines. difficulty: beginner -readtime: 3 +readtime: 5 back: /docs/quick-starts --- -Learn how to setup your first React project powered by Appwrite. +Learn how to set up your first React project with the [Appwrite React library](/docs/products/auth/react). + {% section #step-1 step=1 title="Create project" %} Head to the [Appwrite Console](https://cloud.appwrite.io/console). @@ -34,22 +35,26 @@ Then, under **Add a platform**, add a **Web app**. The **Hostname** should be `l You can skip optional steps. {% /section %} + {% section #step-2 step=2 title="Create React project" %} Create a Vite project. ```sh -npm create vite@latest my-app -- --template react && cd my-app +npm create vite@latest my-app -- --template react-ts && cd my-app +npm install ``` {% /section %} -{% section #step-3 step=3 title="Install Appwrite" %} -Install the JavaScript Appwrite SDK. +{% section #step-3 step=3 title="Install the React library" %} + +Install the Appwrite React library along with the `appwrite` Web SDK and `@tanstack/react-query` peer dependency. ```sh -npm install appwrite +npm install @appwrite.io/react appwrite @tanstack/react-query ``` {% /section %} -{% section #step-4 step=4 title="Import Appwrite" %} + +{% section #step-4 step=4 title="Configure environment variables" %} Find your project's ID in the **Settings** page. {% only_dark %} @@ -58,92 +63,109 @@ Find your project's ID in the **Settings** page. {% only_light %} ![Project settings screen](/images/docs/quick-starts/project-id.avif) {% /only_light %} -Create a new file `src/lib/appwrite.js` and add the following code to it, replace `` with your project ID. - -```client-web -import { Client, Account} from 'appwrite'; -export const client = new Client(); +Create a `.env` file at the project root and add your endpoint and project ID. Replace `` and `` with your own values. -client - .setEndpoint('https://.cloud.appwrite.io/v1') - .setProject(''); // Replace with your project ID +```sh +VITE_APPWRITE_ENDPOINT=https://.cloud.appwrite.io/v1 +VITE_APPWRITE_PROJECT_ID= +``` +{% /section %} -export const account = new Account(client); -export { ID } from 'appwrite'; +{% section #step-5 step=5 title="Wrap your app with AppwriteProvider" %} + +Replace the contents of `src/main.tsx` with the following. + +```tsx +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; +import { AppwriteProvider } from "@appwrite.io/react"; +import App from "./App"; +import "./index.css"; + +createRoot(document.getElementById("root")!).render( + + + + + , +); ``` + +`AppwriteProvider` sets up the Appwrite Web SDK client and a per-instance TanStack Query cache so all hooks share the same auth state. + {% /section %} -{% section #step-5 step=5 title="Create a login page" %} -Add the following code to `src/App.jsx`. - -```js -import React, { useState } from 'react'; -import { account, ID } from './lib/appwrite'; - -const App = () => { - const [loggedInUser, setLoggedInUser] = useState(null); - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [name, setName] = useState(''); - - async function login(email, password) { - await account.createEmailPasswordSession({ - email, - password - }); - setLoggedInUser(await account.get()); + +{% section #step-6 step=6 title="Add sign-up, sign-in, and sign-out" %} + +Replace the contents of `src/App.tsx` with the following. + +```tsx +import { useState } from "react"; +import { useAuth } from "@appwrite.io/react"; + +export default function App() { + const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [name, setName] = useState(""); + + if (isLoading) return

Loading...

; + + if (user) { + return ( +
+

Welcome, {user.name || user.email}

+ +
+ ); } return ( -
-

- {loggedInUser ? `Logged in as ${loggedInUser.name}` : 'Not logged in'} -

- -
- setEmail(e.target.value)} /> - setPassword(e.target.value)} /> - setName(e.target.value)} /> - - - - - - -
-
+
+ setName(e.target.value)} /> + setEmail(e.target.value)} /> + setPassword(e.target.value)} + /> + + + {error &&

{error.message}

} +
); -}; +} +``` + +`useAuth` returns the current user, loading state, and the `signIn`, `signUp`, and `signOut` mutations. The user state is cached by TanStack Query and stays in sync across components automatically. -export default App; +{% /section %} + +{% section #step-7 step=7 title="Run your app" %} +Run your project. + +```sh +npm run dev ``` + +Open [localhost on port 5173](http://localhost:5173) in your browser. Sign up, sign out, and sign back in to verify the flow. {% /section %} -{% section #step-6 step=6 title="All set" %} -Run your project with `npm run dev -- --open --port 3000` and open [Localhost on Port 3000](http://localhost:3000) in your browser. -{% /section %} \ No newline at end of file +# Next steps {% #next-steps %} + +For Next.js or TanStack Start integration, server-side rendering, and the full hook reference, see the [React library docs](/docs/products/auth/react). diff --git a/src/routes/docs/quick-starts/react/prompt.md b/src/routes/docs/quick-starts/react/prompt.md index c2f180be592..99798ab284c 100644 --- a/src/routes/docs/quick-starts/react/prompt.md +++ b/src/routes/docs/quick-starts/react/prompt.md @@ -1,6 +1,6 @@ ## Add Appwrite Auth to a New React (Vite) App -Goal: Add Appwrite auth to a new React (Vite) app with a working login/register/logout page. +Goal: Add Appwrite auth to a new React (Vite) app using the official Appwrite React library, with a working sign-up, sign-in, and sign-out flow. Do exactly these steps in order. Confirm each step succeeds before continuing. If any command fails, show the error and fix it automatically. @@ -11,60 +11,112 @@ Respect user's package manager at all time. Don't use NPM if the user uses somet - First, check if the current working directory contains files that appear unrelated to a development workspace (e.g., personal files, downloads, random documents, media files). - If unrelated files are detected, ask the user: 'The current directory appears to contain personal or non-project files. Would you like to: (1) proceed here anyway, or (2) create the project in a subdirectory with a specific folder name?' and proceed based on their choice. - If the directory is empty OR contains an existing project (`package.json`, source files, config files, etc.), proceed without asking - integrate Appwrite into whatever is there. -- For a new project, run: `npm create vite@latest . -- --template react` +- For a new project, run: `npm create vite@latest . -- --template react-ts` - Create the project in the current directory (`.`). Do NOT use `cd` to switch directories. -## Step 2: Install Appwrite SDK +## Step 2: Install the Appwrite React library -- Run: `npm install appwrite` +- Run: `npm install @appwrite.io/react appwrite @tanstack/react-query` -## Step 3: Create Appwrite Client Module (Ask User for Details; Never Assume) +## Step 3: Configure environment variables (Ask User for Details; Never Assume) - Ask the user for: - Appwrite Cloud Region (e.g. `fra`, `nyc`) - **Project ID** (from Console -> Settings) -- Hardcode the endpoint and project ID in the file: `src/lib/appwrite.js` (or `.ts`) if provided, else leave placeholder and ask the user to provide them. -- Create file: `src/lib/appwrite.js` (or `.ts`) with key snippet: - -```js -import { Client, Account, ID } from 'appwrite'; -const endpoint = 'https://.cloud.appwrite.io/v1'; -const projectId = ''; -if (!endpoint || !projectId) throw new Error('Missing Appwrite endpoint and project ID'); -const client = new Client().setEndpoint(endpoint).setProject(projectId); -export const account = new Account(client); -export { ID }; +- Create a `.env` file at the project root with the values provided. If either is missing, leave a placeholder and ask the user to fill it in: + +```sh +VITE_APPWRITE_ENDPOINT=https://.cloud.appwrite.io/v1 +VITE_APPWRITE_PROJECT_ID= ``` -## Step 4: Build the Login Page +## Step 4: Mount AppwriteProvider + +- Replace `src/main.tsx` (or `.jsx`) so the entire app is wrapped with `AppwriteProvider`: + +```tsx +import { StrictMode } from 'react'; +import { createRoot } from 'react-dom/client'; +import { AppwriteProvider } from '@appwrite.io/react'; +import App from './App'; +import './index.css'; + +createRoot(document.getElementById('root')!).render( + + + + + +); +``` -- If this is a fresh project, you may replace `src/App.jsx` (or `.tsx`) with a component that renders the auth UI. -- If you are working in an existing project, add a new route/page instead of overriding the default route. If routing is not set up, install `react-router-dom` and add a `/auth` route that renders this component. -- The component should render: - - Email/password inputs - - Name input for registration - - Buttons: **Login**, **Register**, **Logout** - - Shows "Logged in as \" when a session exists -- Implement functions: - - `login(email, password)`: `account.createEmailPasswordSession({ email, password })` then set user via `account.get()` - - `register()`: `account.create({ userId: ID.unique(), email, password, name })` then call `login` - - `logout()`: `account.deleteSession({ sessionId: 'current' })` then clear user state +## Step 5: Build the auth page + +- If this is a fresh project, you may replace `src/App.tsx` (or `.jsx`) with a component that renders the auth UI. +- If you are working in an existing project, add a new route/page instead of overriding the default route. If routing is not set up, install `react-router-dom` and add an `/auth` route that renders this component. +- The component must render: + - Email, password, and name inputs + - Buttons: **Sign up**, **Sign in**, **Sign out** + - Shows "Welcome, \" when a session exists +- Use the `useAuth` hook from `@appwrite.io/react`: + +```tsx +import { useState } from 'react'; +import { useAuth } from '@appwrite.io/react'; + +export default function App() { + const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); + const [email, setEmail] = useState(''); + const [password, setPassword] = useState(''); + const [name, setName] = useState(''); + + if (isLoading) return

Loading...

; + + if (user) { + return ( +
+

Welcome, {user.name || user.email}

+ +
+ ); + } + + return ( +
+ setName(e.target.value)} /> + setEmail(e.target.value)} /> + setPassword(e.target.value)} + /> + + + {error &&

{error.message}

} +
+ ); +} +``` -## Step 5: Verify Environment (Ask User to Confirm) +## Step 6: Verify environment (Ask User to Confirm) -- Confirm endpoint and project ID are set in `src/lib/appwrite.js`. +- Confirm the `.env` file contains the correct endpoint and project ID. - Ensure the Web app platform exists in Appwrite Console with **Hostname** = `localhost`. If missing, guide the user to add it. -## Step 6: Run and Test +## Step 7: Run and test -- Run: `npm run dev -- --open --port 3000` -- Open: `http://localhost:3000` +- Run: `npm run dev` +- Open: `http://localhost:5173` - Test flows: - - Register a new user and auto login works - - Logout then login again -- Surface any Appwrite errors (invalid project, endpoint, CORS/hostname) and fix by guiding updates to `appwrite.js` and Console settings. + - Sign up a new user and confirm the page shows the welcome state + - Sign out, then sign in again +- Surface any Appwrite errors (invalid project, endpoint, CORS/hostname) and fix by guiding updates to `.env` and Console settings. ## Deliverables -- A running React app with working Appwrite auth (register/login/logout) -- Files created/updated: `package.json` (deps), `src/lib/appwrite.js`, `src/App.jsx` +- A running React app with working Appwrite auth using `@appwrite.io/react` +- Files created/updated: `package.json` (deps), `.env`, `src/main.tsx`, `src/App.tsx` diff --git a/src/routes/docs/quick-starts/tanstack-start/+page.markdoc b/src/routes/docs/quick-starts/tanstack-start/+page.markdoc index 780ec427580..46f284a7907 100644 --- a/src/routes/docs/quick-starts/tanstack-start/+page.markdoc +++ b/src/routes/docs/quick-starts/tanstack-start/+page.markdoc @@ -1,12 +1,14 @@ --- layout: article title: Start with TanStack Start -description: Learn how to use Appwrite to add authentication, user management, file storage, and more to your TanStack Start apps. +description: Build TanStack Start apps with the Appwrite React library. Add server-rendered authentication via file-route handlers and server functions. difficulty: beginner -readtime: 3 +readtime: 7 back: /docs/quick-starts --- -Learn how to setup your first TanStack Start project powered by Appwrite. + +Learn how to set up your first TanStack Start project with the [Appwrite React library](/docs/products/auth/react). The library exposes a TanStack file-route handler, server helpers, and the same React hooks you use on the client. + {% section #step-1 step=1 title="Create project" %} Head to the [Appwrite Console](https://cloud.appwrite.io/console). @@ -33,133 +35,193 @@ Then, under **Add a platform**, add a **Web app**. The **Hostname** should be `l You can skip optional steps. {% /section %} -{% section #step-2 step=2 title="Create TanStack Start project" %} + +{% section #step-2 step=2 title="Create an API key" %} + +In your project, go to **Overview** > **Integrations** > **API keys** and create a new key with the scopes `users.read`, `users.write`, and `sessions.write`. Copy the key secret. The SSR handler uses this to create sessions on behalf of users; never expose it to the browser. + +{% /section %} + +{% section #step-3 step=3 title="Create TanStack Start project" %} + Create a TanStack Start project. ```sh -npm create @tanstack/start@latest my-app && cd my-app +npx @tanstack/cli create my-app --framework react && cd my-app ``` + {% /section %} -{% section #step-3 step=3 title="Install Appwrite" %} -Install the JavaScript Appwrite SDK. +{% section #step-4 step=4 title="Install the React library" %} + +Install the React library along with the Appwrite Web SDK, Appwrite Node SDK, and `@tanstack/react-query` packages. ```sh -npm install appwrite +npm install @appwrite.io/react appwrite node-appwrite @tanstack/react-query ``` + {% /section %} -{% section #step-4 step=4 title="Import Appwrite" %} -Find your project's ID in the **Settings** page. -{% only_dark %} -![Project settings screen](/images/docs/quick-starts/dark/project-id.avif) -{% /only_dark %} -{% only_light %} -![Project settings screen](/images/docs/quick-starts/project-id.avif) -{% /only_light %} -Create a new file `src/utils/appwrite.ts` and add the following code to it, replace `` with your project ID. +{% section #step-5 step=5 title="Configure environment variables" %} + +Create a `.env` file at the project root. Replace ``, ``, and `` with your own values. + +```sh +VITE_APPWRITE_ENDPOINT=https://.cloud.appwrite.io/v1 +VITE_APPWRITE_PROJECT_ID= +APPWRITE_API_KEY= +``` + +`VITE_*` values are shipped to the browser. `APPWRITE_API_KEY` stays server-only. + +{% /section %} -```client-web -import { Client, Account, ID, Models } from 'appwrite'; +{% section #step-6 step=6 title="Mount the auth handler route" %} -export const client = new Client(); +Create `src/routes/api/appwrite/$.ts`. The TanStack file route exposes the library's `sign-in`, `sign-up`, `sign-out`, and `oauth/callback` endpoints under `/api/appwrite/*`. -client - .setEndpoint('https://.cloud.appwrite.io/v1') - .setProject(''); // Replace with your project ID +```ts +import { createFileRoute } from "@tanstack/react-router"; +import { createAppwriteHandlers } from "@appwrite.io/react/handlers/tanstack"; -export const account = new Account(client); -export { ID }; -export type { Models }; +export const Route = createFileRoute("/api/appwrite/$")({ + server: { + handlers: createAppwriteHandlers({ + endpoint: import.meta.env.VITE_APPWRITE_ENDPOINT, + projectId: import.meta.env.VITE_APPWRITE_PROJECT_ID, + apiKey: process.env.APPWRITE_API_KEY!, + basePath: "/api/appwrite", + }), + }, +}); ``` + {% /section %} -{% section #step-5 step=5 title="Create a login page" %} -Create or update `src/routes/index.tsx` with the following code. + +{% section #step-7 step=7 title="Read auth state in a server function" %} + +Replace `src/routes/index.tsx` with the following. A `createServerFn` loader reads the session cookie server-side; the page receives the result via `Route.useLoaderData()` and passes it into `AppwriteProvider`. ```tsx -import { useState } from 'react'; -import { createFileRoute } from '@tanstack/react-router'; -import { account, ID, type Models } from '../utils/appwrite'; +import { useState } from "react"; +import { createFileRoute, useRouter } from "@tanstack/react-router"; +import { createServerFn } from "@tanstack/react-start"; +import { AppwriteProvider, useAuth } from "@appwrite.io/react"; +import { createTanStackServerHelpers } from "@appwrite.io/react/server/tanstack"; + +const getAuthSnapshot = createServerFn({ method: "GET" }).handler(async () => { + const helpers = createTanStackServerHelpers({ + endpoint: import.meta.env.VITE_APPWRITE_ENDPOINT, + projectId: import.meta.env.VITE_APPWRITE_PROJECT_ID, + }); + return { + session: helpers.readSessionCookie() ?? null, + user: await helpers.getLoggedInUser(), + }; +}); -export const Route = createFileRoute('/')({ - component: Index, +export const Route = createFileRoute("/")({ + loader: () => getAuthSnapshot(), + component: Page, }); -function Index() { - const [loggedInUser, setLoggedInUser] = useState | null>(null); - const [email, setEmail] = useState(''); - const [password, setPassword] = useState(''); - const [name, setName] = useState(''); +function Page() { + const { session, user } = Route.useLoaderData(); + + return ( + +
+

Appwrite React library on TanStack Start

+

SSR user: {user?.email ?? "signed out"}

+ +
+
+ ); +} - async function login(email: string, password: string) { - await account.createEmailPasswordSession({ - email, - password, - }); - setLoggedInUser(await account.get()); - } +function AuthPanel() { + const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); + const router = useRouter(); + const [email, setEmail] = useState(""); + const [password, setPassword] = useState(""); + const [name, setName] = useState(""); - async function register() { - await account.create({ - userId: ID.unique(), - email, - password, - name, - }); - await login(email, password); - } - - async function logout() { - await account.deleteSession({ sessionId: 'current' }); - setLoggedInUser(null); - } - - if (loggedInUser) { - return ( -
-

Logged in as {loggedInUser.name}

- -
- ); - } + if (isLoading) return

Loading...

; + if (user) { return ( -
-

Not logged in

-
- setEmail(e.target.value)} - /> - setPassword(e.target.value)} - /> - setName(e.target.value)} - /> - - -
-
+
+

Welcome, {user.name || user.email}

+ +
); + } + + return ( +
+ setName(e.target.value)} /> + setEmail(e.target.value)} /> + setPassword(e.target.value)} + /> + + + {error &&

{error.message}

} +
+ ); } ``` + +After every auth mutation, `router.invalidate()` re-runs the loader so the SSR user reflects the new session cookie. + +{% info title="Multi-route apps" %} +In a multi-route TanStack Start app, move `AppwriteProvider` (and the auth loader) into `src/routes/__root.tsx` so the TanStack Query cache and auth state persist across navigations. Mounting the provider in a single route works for this quickstart, but resets the cache every time the route changes. +{% /info %} + {% /section %} -{% section #step-6 step=6 title="All set" %} -Run your project with `npm run dev` and open [localhost on port 3000](http://localhost:3000) in your browser. +{% section #step-8 step=8 title="Run your app" %} + +```sh +npm run dev +``` + +Open [localhost on port 3000](http://localhost:3000). Sign up, sign out, and sign back in to verify the cookie-based SSR flow. + {% /section %} + +# Next steps {% #next-steps %} + +For server-side admin operations, per-request session clients, OAuth callbacks, and the full hook reference, see the [React library docs](/docs/products/auth/react). diff --git a/src/routes/docs/quick-starts/tanstack-start/prompt.md b/src/routes/docs/quick-starts/tanstack-start/prompt.md index 1292b29b194..557807504be 100644 --- a/src/routes/docs/quick-starts/tanstack-start/prompt.md +++ b/src/routes/docs/quick-starts/tanstack-start/prompt.md @@ -1,4 +1,6 @@ -## Add Appwrite auth to a TanStack Start app with a working login/register/logout page +## Add Appwrite Auth to a TanStack Start app + +Add Appwrite auth to a new TanStack Start app using the official Appwrite React library, with a working sign-up, sign-in, and sign-out flow backed by SSR session cookies. Do exactly these steps in order. Confirm each step succeeds before continuing. If any command fails, show the error and fix it automatically. @@ -9,126 +11,162 @@ Respect the user's package manager at all times. Don't use NPM if the user uses - First, check what files exist in the current working directory. - If the directory contains files that appear unrelated to a development workspace (e.g., personal documents, downloads, photos, random files that don't belong in a code project), ask the user: "The current directory contains files that don't appear to be part of a development project. Would you like to proceed here anyway, or create a subdirectory with a specific folder name?" - If the directory is empty OR contains an existing project (`package.json`, config files, `src` folder, etc.), proceed with integration without asking - just work with what's there. -- To scaffold a new TanStack Start project, run: `npm create @tanstack/start@latest .` (use `.` to create in the current directory - do NOT use `cd` to switch directories) +- To scaffold a new TanStack Start project, run: `npx @tanstack/cli create . --framework react` (use `.` to create in the current directory - do NOT use `cd` to switch directories) + +## Step 2: Install the Appwrite React library -## Step 2: Install Appwrite SDK +- Run: `npm install @appwrite.io/react appwrite node-appwrite @tanstack/react-query` -- Run: `npm install appwrite` +## Step 3: Configure environment variables -## Step 3: Create Appwrite client module (ask user for details; never assume) +_Ask the user for details; never assume._ - Ask the user for: - **Appwrite Cloud Region** (e.g. `fra`, `nyc`) - **Project ID** (from Console → Settings) -- Hardcode the endpoint and project ID in the file `src/utils/appwrite.ts` (or `.js`) if provided, else leave placeholder and ask the user to provide them. -- Create file `src/utils/appwrite.ts` (or `.js`) with key snippet: + - **API key** with scopes `users.read`, `users.write`, `sessions.write` (Console → Overview → Integrations → API keys) +- Create a `.env` file at the project root: + +```sh +VITE_APPWRITE_ENDPOINT=https://.cloud.appwrite.io/v1 +VITE_APPWRITE_PROJECT_ID= +APPWRITE_API_KEY= +``` + +- The `APPWRITE_API_KEY` is server-only. Never expose it to the browser. + +## Step 4: Mount the auth handler route + +- Create `src/routes/api/appwrite/$.ts`: ```ts -import { Client, Account, ID, type Models } from 'appwrite'; -const endpoint = 'https://.cloud.appwrite.io/v1'; -const projectId = ''; -if (!endpoint || !projectId) throw new Error('Missing Appwrite endpoint and project ID'); -const client = new Client().setEndpoint(endpoint).setProject(projectId); -export const account = new Account(client); -export { ID }; -export type { Models }; +import { createFileRoute } from '@tanstack/react-router'; +import { createAppwriteHandlers } from '@appwrite.io/react/handlers/tanstack'; + +export const Route = createFileRoute('/api/appwrite/$')({ + server: { + handlers: createAppwriteHandlers({ + endpoint: import.meta.env.VITE_APPWRITE_ENDPOINT, + projectId: import.meta.env.VITE_APPWRITE_PROJECT_ID, + apiKey: process.env.APPWRITE_API_KEY!, + basePath: '/api/appwrite' + }) + } +}); ``` -## Step 4: Build the login route +## Step 5: Build the auth route -- If this is a fresh project, you may replace `src/routes/index.tsx` with an auth UI route. -- If you are working in an existing project, create a new route (e.g., `src/routes/auth.tsx`) instead of overriding the default route. -- The route should render: - - Email/password inputs - - Name input for registration - - Buttons: **Login**, **Register**, **Logout** - - Shows "Logged in as \" when a session exists -- Route scaffold example: +- If this is a fresh project, you may replace `src/routes/index.tsx` with the auth UI route. If you are working in an existing project, create a new route (e.g., `src/routes/auth.tsx`) instead of overriding the default route. +- The route reads SSR auth state via a server function and passes the session into `AppwriteProvider`: ```tsx import { useState } from 'react'; -import { createFileRoute } from '@tanstack/react-router'; -import { account, ID, type Models } from '../utils/appwrite'; +import { createFileRoute, useRouter } from '@tanstack/react-router'; +import { createServerFn } from '@tanstack/react-start'; +import { AppwriteProvider, useAuth } from '@appwrite.io/react'; +import { createTanStackServerHelpers } from '@appwrite.io/react/server/tanstack'; + +const getAuthSnapshot = createServerFn({ method: 'GET' }).handler(async () => { + const helpers = createTanStackServerHelpers({ + endpoint: import.meta.env.VITE_APPWRITE_ENDPOINT, + projectId: import.meta.env.VITE_APPWRITE_PROJECT_ID + }); + return { + session: helpers.readSessionCookie() ?? null, + user: await helpers.getLoggedInUser() + }; +}); export const Route = createFileRoute('/')({ - component: Index + loader: () => getAuthSnapshot(), + component: Page }); -function Index() { - const [user, setUser] = useState | null>(null); +function Page() { + const { session, user } = Route.useLoaderData(); + + return ( + +
+

SSR user: {user?.email ?? 'signed out'}

+ +
+
+ ); +} + +function AuthPanel() { + const { user, isLoading, signIn, signUp, signOut, error } = useAuth(); + const router = useRouter(); const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [name, setName] = useState(''); - async function login(e: string, p: string) { - await account.createEmailPasswordSession({ email: e, password: p }); - setUser(await account.get()); - } - - async function register() { - await account.create({ userId: ID.unique(), email, password, name }); - await login(email, password); - } + if (isLoading) return

Loading...

; - async function logout() { - await account.deleteSession({ sessionId: 'current' }); - setUser(null); + if (user) { + return ( + + ); } return (
-

{user ? `Logged in as ${user.name}` : 'Not logged in'}

-
- setEmail(e.target.value)} - /> - setPassword(e.target.value)} - /> - setName(e.target.value)} - /> - - - {user && ( - - )} -
+ setName(e.target.value)} /> + setEmail(e.target.value)} /> + setPassword(e.target.value)} + /> + + + {error &&

{error.message}

}
); } ``` -## Step 5: Verify environment (ask user to confirm) +## Step 6: Verify environment (ask user to confirm) -- Confirm endpoint and project ID are set in `src/utils/appwrite.ts`. +- Confirm `.env` has the endpoint, project ID, and API key set. - Ensure the Web app platform exists in Appwrite Console with **Hostname** = `localhost`. If missing, guide the user to add it. -## Step 6: Run and test +## Step 7: Run and test - Run: `npm run dev` - Open: `http://localhost:3000` - Test flows: - - Register a new user and auto login works - - Logout then login again -- Surface any Appwrite errors (invalid project, endpoint, CORS/hostname) and fix by guiding updates to `appwrite.ts` and Console settings. + - Sign up a new user, confirm the SSR-rendered user reflects the change after `router.invalidate()` + - Sign out, then sign in again +- Surface any Appwrite errors (invalid project, endpoint, CORS/hostname, missing key scopes) and fix by guiding updates to `.env` and Console settings. ## Deliverables -- A TanStack Start app with working Appwrite auth (register/login/logout) -- Files created/updated: `package.json` (deps), `src/utils/appwrite.ts`, auth route file +- A TanStack Start app with working Appwrite auth using `@appwrite.io/react` +- Files created/updated: `package.json` (deps), `.env`, `src/routes/api/appwrite/$.ts`, auth route file diff --git a/src/routes/docs/references/+page.markdoc b/src/routes/docs/references/+page.markdoc index 2af04b21bc6..c5a6c7c8924 100644 --- a/src/routes/docs/references/+page.markdoc +++ b/src/routes/docs/references/+page.markdoc @@ -8,15 +8,15 @@ Appwrite lets you build integrations on web, mobile, native, and server platform ## Client vs Server APIs {% #client-vs-server %} Client APIs and SDKs are for integrating with Appwrite to build client-based applications and websites. -Client APIs only give access to resources if users have been [granted permissions](/docs/advanced/platform/permissions). +Client APIs only give access to resources if users have been [granted permissions](/docs/advanced/security/permissions). Server API and SDKs are for integrating with Appwrite to build backend or server applications. -Server APIs are constrained by an [API key's](/docs/advanced/platform/api-keys) scope, ignoring user permissions. +Server APIs are constrained by an [API key's](/docs/advanced/security/api-keys) scope, ignoring user permissions. ## APIs {% #api %} Before using the Appwrite APIs, in the **Settings** of your Appwrite project, obtain your **API endpoint** and **Project ID**. Client APIs require an active session, created from [signing up and logging in](/docs/products/auth/accounts#signup-login). -Server APIs require [API keys](/docs/advanced/platform/api-keys). +Server APIs require [API keys](/docs/advanced/security/api-keys). {% only_dark %} @@ -70,4 +70,4 @@ Track which signed-in users are active right now and broadcast their status in r ## Error handling {% #error-handling %} -When building with Appwrite, implement proper error handling to provide user-friendly messages instead of exposing raw error responses. For implementation details and best practices, refer to our [Error handling guide](/docs/advanced/platform/error-handling) and [Response codes](/docs/advanced/platform/response-codes#error-types) documentation. +When building with Appwrite, implement proper error handling to provide user-friendly messages instead of exposing raw error responses. For implementation details and best practices, refer to our [Error handling guide](/docs/apis/response-codes#error-handling) and [Response codes](/docs/apis/response-codes) documentation. diff --git a/src/routes/docs/references/[version]/[platform]/[service]/(components)/RateLimits.svelte b/src/routes/docs/references/[version]/[platform]/[service]/(components)/RateLimits.svelte index 240ce2af461..b21f6135974 100644 --- a/src/routes/docs/references/[version]/[platform]/[service]/(components)/RateLimits.svelte +++ b/src/routes/docs/references/[version]/[platform]/[service]/(components)/RateLimits.svelte @@ -106,7 +106,7 @@
trackEvent(`docs-rate_limits_learn_more-click`)} > diff --git a/src/routes/docs/references/[version]/[platform]/[service]/descriptions/presences.md b/src/routes/docs/references/[version]/[platform]/[service]/descriptions/presences.md index b0d19728eab..fca575713c8 100644 --- a/src/routes/docs/references/[version]/[platform]/[service]/descriptions/presences.md +++ b/src/routes/docs/references/[version]/[platform]/[service]/descriptions/presences.md @@ -1,5 +1,5 @@ The Presences service records a short-lived status for each signed-in user and broadcasts every change over [Realtime](/docs/apis/realtime), so you can render online indicators, "viewing this page" cues, typing signals, and collaboration banners without writing any socket plumbing. -Each presence is attached to a user and carries a `status` string, an optional `metadata` JSON object for richer context, and an `expiresAt` timestamp that controls automatic cleanup. Presences are written by the user's own session or a server SDK, and read by any client with the right [permissions](/docs/advanced/platform/permissions). +Each presence is attached to a user and carries a `status` string, an optional `metadata` JSON object for richer context, and an `expiresAt` timestamp that controls automatic cleanup. Presences are written by the user's own session or a server SDK, and read by any client with the right [permissions](/docs/advanced/security/permissions). You can find guides and examples on using the Presences API in the [Presences product pages](/docs/products/auth/presences). diff --git a/src/routes/docs/references/[version]/[platform]/[service]/descriptions/storage.md b/src/routes/docs/references/[version]/[platform]/[service]/descriptions/storage.md index 18bf27abff1..322c3e032d3 100644 --- a/src/routes/docs/references/[version]/[platform]/[service]/descriptions/storage.md +++ b/src/routes/docs/references/[version]/[platform]/[service]/descriptions/storage.md @@ -4,6 +4,6 @@ Large files are uploaded in 5MB chunks. Appwrite SDKs handle chunking for you an Files are managed using buckets. Storage buckets are similar to Tables we have in our [Databases](/docs/products/databases) service. The difference is, buckets also provide more power to decide what kinds of files, what sizes you want to allow in that bucket, whether or not to encrypt the files, scan with antivirus and more. -Using Appwrite permissions architecture, you can assign read or write access to each bucket or file in your project for either a specific user, team, user role, or even grant it with public access (`any`). You can learn more about [how Appwrite handles permissions and access control](/docs/advanced/platform/permissions). +Using Appwrite permissions architecture, you can assign read or write access to each bucket or file in your project for either a specific user, team, user role, or even grant it with public access (`any`). You can learn more about [how Appwrite handles permissions and access control](/docs/advanced/security/permissions). The preview endpoint allows you to generate preview images for your files. Using the preview endpoint, you can also manipulate the resulting image so that it will fit perfectly inside your app in terms of dimensions, file size, and style. The preview endpoint also allows you to change the resulting image file format for better compression or image quality for better delivery over the network. diff --git a/src/routes/docs/references/[version]/[platform]/[service]/descriptions/teams.md b/src/routes/docs/references/[version]/[platform]/[service]/descriptions/teams.md index a0262fc5ff0..996933c2a55 100644 --- a/src/routes/docs/references/[version]/[platform]/[service]/descriptions/teams.md +++ b/src/routes/docs/references/[version]/[platform]/[service]/descriptions/teams.md @@ -1,3 +1,3 @@ -The Teams service allows you to group users of your project and share [read and write](/docs/advanced/platform/permissions) access to resources like database rows or storage files. +The Teams service allows you to group users of your project and share [read and write](/docs/advanced/security/permissions) access to resources like database rows or storage files. Each user who creates a team becomes the team owner and can delegate the ownership role by inviting a new team member. Only team owners can invite new users to their team. diff --git a/src/routes/docs/references/quick-start/+page.markdoc b/src/routes/docs/references/quick-start/+page.markdoc index d30febc15b9..080b067fd65 100644 --- a/src/routes/docs/references/quick-start/+page.markdoc +++ b/src/routes/docs/references/quick-start/+page.markdoc @@ -260,7 +260,7 @@ Admin clients should only be used if you need to perform admin actions that bypa or [unauthenticated requests that bypass rate limits](/docs/products/auth/server-side-rendering#rate-limits). {% /info %} -To initialize the admin client, we'll need to first [generated an API key](/docs/advanced/platform/api-keys#create-api-key). +To initialize the admin client, we'll need to first [generated an API key](/docs/advanced/security/api-keys#create-api-key). The API key should have the following scope in order to perform authentication: | Category {% width=120 %} | Required scopes | Purpose | @@ -297,7 +297,7 @@ let admin_client = Client::new() ``` {% /multicode %} -It is important to use an API key, as this will allow your server requests to bypass [rate limits](/docs/advanced/platform/rate-limits). If you don't use an API key, your server will be rate limited as if it were a client from a single IP address. +It is important to use an API key, as this will allow your server requests to bypass [rate limits](/docs/advanced/security/rate-limits). If you don't use an API key, your server will be rate limited as if it were a client from a single IP address. ## Session client {% #session-client %} diff --git a/src/routes/docs/sdks/+page.markdoc b/src/routes/docs/sdks/+page.markdoc index 27b232c6881..7ab2e2e11db 100644 --- a/src/routes/docs/sdks/+page.markdoc +++ b/src/routes/docs/sdks/+page.markdoc @@ -32,6 +32,12 @@ Client libraries for integrating with Appwrite to build client-based application --- * {% only_dark %}{% icon_image src="/images/platforms/dark/react.svg" alt="React logo" size="m" /%}{% /only_dark %} {% only_light %}{% icon_image src="/images/platforms/light/react.svg" alt="React logo" size="m" /%}{% /only_light %} +* React library `0.1.0` +* [appwrite/sdk-for-react](https://github.com/appwrite/sdk-for-react) +* `beta` +--- +* {% only_dark %}{% icon_image src="/images/platforms/dark/react.svg" alt="React logo" size="m" /%}{% /only_dark %} +{% only_light %}{% icon_image src="/images/platforms/light/react.svg" alt="React logo" size="m" /%}{% /only_light %} * React Native SDK `0.25.0` * [appwrite/sdk-for-react-native](https://github.com/appwrite/sdk-for-react-native) * `beta` @@ -424,7 +430,7 @@ You can discover the available enums in each SDK at the source. ## Queries and permissions {% #queries-and-permissions %} Appwrite has utility classes for queries and permissions. -You can learn more about [query utility classes](/docs/products/databases/queries) and [permissions utility classes](/docs/advanced/platform/permissions) in their own pages. +You can learn more about [query utility classes](/docs/products/databases/queries) and [permissions utility classes](/docs/advanced/security/permissions) in their own pages. ## File I/O {% #file-io %} Depending on your platform, you will also need some helpers to interface with system I/O. diff --git a/src/routes/docs/tooling/ai/+layout.svelte b/src/routes/docs/tooling/ai/+layout.svelte index 163e7c56a25..69f0b369f76 100644 --- a/src/routes/docs/tooling/ai/+layout.svelte +++ b/src/routes/docs/tooling/ai/+layout.svelte @@ -105,7 +105,7 @@ ] }, { - label: 'Journeys', + label: 'Guides', items: [ { label: 'AI in Functions', diff --git a/src/routes/docs/tooling/ai/+page.markdoc b/src/routes/docs/tooling/ai/+page.markdoc index 4662f596bb3..97d9884c66b 100644 --- a/src/routes/docs/tooling/ai/+page.markdoc +++ b/src/routes/docs/tooling/ai/+page.markdoc @@ -135,7 +135,7 @@ Open-source benchmark evaluating how well AI models understand Appwrite's APIs a {% /cards_item %} {% /cards %} -# Journeys {% #journeys %} +# Guides {% #guides %} Guides for building AI-powered features on top of Appwrite, from running models in Functions to building full agent pipelines. diff --git a/src/routes/docs/tooling/ai/responsible-ai/+page.markdoc b/src/routes/docs/tooling/ai/responsible-ai/+page.markdoc index e8aeec7c1d6..d3fd94fb3b8 100644 --- a/src/routes/docs/tooling/ai/responsible-ai/+page.markdoc +++ b/src/routes/docs/tooling/ai/responsible-ai/+page.markdoc @@ -12,7 +12,7 @@ When sending data to AI providers like OpenAI, Anthropic, or others, be mindful - **Avoid sending personal data** to AI providers unless necessary for the feature. Strip personally identifiable information (PII) like names, emails, and addresses from prompts before sending them to an LLM. - **Review provider data policies** to understand how each AI provider handles the data you send. Some providers use input data for model training unless you opt out. -- **Use Appwrite permissions** to control which users and roles can trigger AI-powered features. Appwrite's [permission system](/docs/advanced/platform/permissions) lets you restrict access at the database, storage, and function level. +- **Use Appwrite permissions** to control which users and roles can trigger AI-powered features. Appwrite's [permission system](/docs/advanced/security/permissions) lets you restrict access at the database, storage, and function level. # Secure your API keys {% #secure-api-keys %} diff --git a/src/routes/docs/tooling/command-center/+layout.svelte b/src/routes/docs/tooling/command-center/+layout.svelte index 93e22c8cebf..928dc1300c8 100644 --- a/src/routes/docs/tooling/command-center/+layout.svelte +++ b/src/routes/docs/tooling/command-center/+layout.svelte @@ -1,9 +1,30 @@ - + diff --git a/src/routes/docs/advanced/platform/shortcuts/+page.markdoc b/src/routes/docs/tooling/command-center/shortcuts/+page.markdoc similarity index 100% rename from src/routes/docs/advanced/platform/shortcuts/+page.markdoc rename to src/routes/docs/tooling/command-center/shortcuts/+page.markdoc diff --git a/src/routes/docs/tooling/command-line/non-interactive/+page.markdoc b/src/routes/docs/tooling/command-line/non-interactive/+page.markdoc index cb11d9072dc..b5a6dc9ac5f 100644 --- a/src/routes/docs/tooling/command-line/non-interactive/+page.markdoc +++ b/src/routes/docs/tooling/command-line/non-interactive/+page.markdoc @@ -17,7 +17,7 @@ When you set the global configuration parameters using the `appwrite client` com In this mode, the CLI can only interact with one project at a time. # API Keys {% #api-keys %} -In non-interactive mode, the CLI uses an API key to authenticate. Your API key must have sufficient permissions to execute the commands you plan to use. [Learn more about API Keys](/docs/advanced/platform/api-keys). +In non-interactive mode, the CLI uses an API key to authenticate. Your API key must have sufficient permissions to execute the commands you plan to use. [Learn more about API Keys](/docs/advanced/security/api-keys). # Deployment {% #deployment %} Appwrite's `push` commands can also be executed in a non-interactive mode. This applies to the following resources: functions, tables, buckets, teams, and messaging topics. diff --git a/src/routes/docs/tooling/terraform/resources/webhooks/+page.markdoc b/src/routes/docs/tooling/terraform/resources/webhooks/+page.markdoc index d993301adb0..65dd1e2cda9 100644 --- a/src/routes/docs/tooling/terraform/resources/webhooks/+page.markdoc +++ b/src/routes/docs/tooling/terraform/resources/webhooks/+page.markdoc @@ -40,7 +40,7 @@ resource "appwrite_webhook" "authenticated" { } ``` -Use the read-only **`secret`** attribute when configuring **signature verification** for payloads Appwrite sends to your URL (see [Webhooks](/docs/advanced/platform/webhooks) in the platform docs). +Use the read-only **`secret`** attribute when configuring **signature verification** for payloads Appwrite sends to your URL (see [Webhooks](/docs/apis/webhooks) in the platform docs). # Data sources {% #data-sources %} @@ -61,4 +61,4 @@ See the [Terraform Registry](https://registry.terraform.io/providers/appwrite/ap # Related {% #related %} - [Configuration](/docs/tooling/terraform/provider): authentication and endpoints -- [Webhooks](/docs/advanced/platform/webhooks): event delivery, headers, and signatures +- [Webhooks](/docs/apis/webhooks): event delivery, headers, and signatures diff --git a/src/routes/docs/tutorials/subscriptions-with-stripe/step-5/+page.markdoc b/src/routes/docs/tutorials/subscriptions-with-stripe/step-5/+page.markdoc index 2136213889e..89437fd1b03 100644 --- a/src/routes/docs/tutorials/subscriptions-with-stripe/step-5/+page.markdoc +++ b/src/routes/docs/tutorials/subscriptions-with-stripe/step-5/+page.markdoc @@ -52,6 +52,6 @@ The label created will grant the user access to any resource with the following | Delete | `Permissions.delete(Role.label('subscriber'))` | | Create | `Permissions.create(Role.label('subscriber'))` | -{% arrow_link href="/docs/advanced/platform/permissions" %} +{% arrow_link href="/docs/advanced/security/permissions" %} Learn more about permissions {% /arrow_link %} \ No newline at end of file diff --git a/src/routes/integrations/push-fcm/+page.markdoc b/src/routes/integrations/push-fcm/+page.markdoc index 650ef32154a..c1c6bf3a7a6 100644 --- a/src/routes/integrations/push-fcm/+page.markdoc +++ b/src/routes/integrations/push-fcm/+page.markdoc @@ -59,7 +59,7 @@ To test the provider on mobile apps, there are some additional configuration ste 4. Add `google-services.json` at the root of your project. 5. Add Google Services class path to your app-level Gradle dependencies block `"com.google.gms:google-services:4.4.0"`. 6. Add the Google Services plugin to your app-level Gradle in the plugins block as `"com.google.gms.google-services"`. -7. Add notification handler service to `AndroidManifest.xml` inside the application tag, alongside other activities. Find an example of this service in the [Send push notification](https://appwrite.io/docs/products/messaging/send-push-notifications#add-targets) journey. +7. Add notification handler service to `AndroidManifest.xml` inside the application tag, alongside other activities. Find an example of this service in the [Send push notification](https://appwrite.io/docs/products/messaging/send-push-notifications#add-targets) guide. ```xml diff --git a/src/routes/llms-full.txt/+server.ts b/src/routes/llms-full.txt/+server.ts index 9e7c33134a9..0e291a0e858 100644 --- a/src/routes/llms-full.txt/+server.ts +++ b/src/routes/llms-full.txt/+server.ts @@ -124,7 +124,7 @@ ${page.fullContent} } // Skip stub pages with no useful content - if (href === '/docs/advanced/integration' || href === '/blog/category/integrations') { + if (href === '/blog/category/integrations') { continue; } diff --git a/src/routes/llms.txt/+server.ts b/src/routes/llms.txt/+server.ts index fab781cbfe5..a34272a8eeb 100644 --- a/src/routes/llms.txt/+server.ts +++ b/src/routes/llms.txt/+server.ts @@ -144,7 +144,7 @@ export const GET: RequestHandler = ({ request }) => { } // Skip stub pages with no useful content - if (href === '/docs/advanced/integration' || href === '/blog/category/integrations') { + if (href === '/blog/category/integrations') { continue; } diff --git a/src/routes/pricing/compare-plans.svelte b/src/routes/pricing/compare-plans.svelte index b5f09a09423..61d80712d7c 100644 --- a/src/routes/pricing/compare-plans.svelte +++ b/src/routes/pricing/compare-plans.svelte @@ -177,12 +177,12 @@ free: '-', pro: { text: 'View rates', - url: '/docs/advanced/platform/phone-otp#rates', + url: '/docs/advanced/billing/phone-otp#rates', event: 'pricing-pro-view_phone_otp_rates-click' }, scale: { text: 'View rates', - url: '/docs/advanced/platform/phone-otp#rates', + url: '/docs/advanced/billing/phone-otp#rates', event: 'pricing-scale-view_phone_otp_rates-click' }, enterprise: 'Custom' diff --git a/src/routes/pricing/faq.svelte b/src/routes/pricing/faq.svelte index 5adfc0b762b..5c9c03935c0 100644 --- a/src/routes/pricing/faq.svelte +++ b/src/routes/pricing/faq.svelte @@ -14,15 +14,15 @@ // }, { question: 'What payment methods does Appwrite support?', - answer: 'Appwrite currently supports credit and debit card payments. We are actively working on adding support for more methods. Please contact us in case this is an issue for you.' + answer: 'Appwrite currently supports credit and debit card payments. We are actively working on adding support for more methods. Please contact us in case this is an issue for you.' }, { question: 'What happens if I reach a resource limit in my Pro plan?', - answer: 'Your project will continue to run, and additional charges will apply. You can find the costs for additional resources in the pricing plans comparison. We will also send you email reminders when you hit 75% and 100% of your resource limits. To avoid unexpected payments, you can set up a budget cap on your organization. Learn more in our docs.' + answer: 'Your project will continue to run, and additional charges will apply. You can find the costs for additional resources in the pricing plans comparison. We will also send you email reminders when you hit 75% and 100% of your resource limits. To avoid unexpected payments, you can set up a budget cap on your organization. Learn more in our docs.' }, { question: 'What happens if I reach a resource limit in my Free plan?', - answer: 'Your project will freeze, and Appwrite Console will continue running in read-only mode. You need to upgrade to Pro, remove resources that exceed their limit, or wait for the next billing cycle, which resets usage limits. Learn more in our docs.' + answer: 'Your project will freeze, and Appwrite Console will continue running in read-only mode. You need to upgrade to Pro, remove resources that exceed their limit, or wait for the next billing cycle, which resets usage limits. Learn more in our docs.' }, { question: 'Why does Appwrite ask for payment verification for up to $150?', diff --git a/src/routes/products/auth/(components)/Access.svelte b/src/routes/products/auth/(components)/Access.svelte index 4700328a38f..1eb79bda7a8 100644 --- a/src/routes/products/auth/(components)/Access.svelte +++ b/src/routes/products/auth/(components)/Access.svelte @@ -35,7 +35,7 @@ Create custom roles and level of access to resources such as projects, files, etc.

mock phone numbers to test OTP functionality without incurring costs. Please refer to our rates page for a breakdown of the pricing, including rates by region and specific SMS costs.' + answer: 'OTP SMS messages are billed per message sent. You can use mock phone numbers to test OTP functionality without incurring costs. Please refer to our rates page for a breakdown of the pricing, including rates by region and specific SMS costs.' }, { question: 'What happens if we scale overnight?', diff --git a/src/routes/terms/+page.markdoc b/src/routes/terms/+page.markdoc index 5333d45d7ed..7d105587b8b 100644 --- a/src/routes/terms/+page.markdoc +++ b/src/routes/terms/+page.markdoc @@ -34,7 +34,7 @@ Your continued use of the Service after the Subscription fee change comes into e Certain refund requests for Subscriptions may be considered by Appwrite on a case-by-case basis and granted in the sole discretion of Appwrite. -For more details, refer to the [full refund policy](/docs/advanced/platform/refund-policy). +For more details, refer to the [full refund policy](/docs/advanced/billing/refund-policy). # Content diff --git a/static/images/blog/announcing-appwrite-react-library/cover.avif b/static/images/blog/announcing-appwrite-react-library/cover.avif new file mode 100644 index 00000000000..dbbd9b87a40 Binary files /dev/null and b/static/images/blog/announcing-appwrite-react-library/cover.avif differ diff --git a/static/images/blog/appwrite-1-9-5-self-hosted-release/cover.avif b/static/images/blog/appwrite-1-9-5-self-hosted-release/cover.avif new file mode 100644 index 00000000000..47412df1bf7 Binary files /dev/null and b/static/images/blog/appwrite-1-9-5-self-hosted-release/cover.avif differ diff --git a/static/images/blog/claude-fable-5-returns-with-stronger-jailbreak-safeguards/cover.avif b/static/images/blog/claude-fable-5-returns-with-stronger-jailbreak-safeguards/cover.avif new file mode 100644 index 00000000000..cca659c1627 Binary files /dev/null and b/static/images/blog/claude-fable-5-returns-with-stronger-jailbreak-safeguards/cover.avif differ diff --git a/static/images/blog/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/cover.avif b/static/images/blog/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/cover.avif new file mode 100644 index 00000000000..ec3880fb6f8 Binary files /dev/null and b/static/images/blog/claude-sonnet-5-is-anthropics-most-agentic-sonnet-yet/cover.avif differ diff --git a/static/images/blog/what-is-cicd-a-complete-guide-for-developers/cover.avif b/static/images/blog/what-is-cicd-a-complete-guide-for-developers/cover.avif new file mode 100644 index 00000000000..52b6f963b84 Binary files /dev/null and b/static/images/blog/what-is-cicd-a-complete-guide-for-developers/cover.avif differ diff --git a/static/images/blog/what-is-redis-a-complete-guide-for-developers/cover.avif b/static/images/blog/what-is-redis-a-complete-guide-for-developers/cover.avif new file mode 100644 index 00000000000..0aaf9bfd18b Binary files /dev/null and b/static/images/blog/what-is-redis-a-complete-guide-for-developers/cover.avif differ