From e176761c60d597280df5bbc7d8a74cdef9606b46 Mon Sep 17 00:00:00 2001 From: Samyazz <49154465+Samyazz@users.noreply.github.com> Date: Thu, 29 Oct 2026 11:05:16 +0100 Subject: [PATCH 1/2] Add Alchemy provider reference --- apps/docs/content/references/alchemy.mdx | 130 +++++++++++++++++++++++ apps/docs/sidebars.js | 9 ++ 2 files changed, 139 insertions(+) create mode 100644 apps/docs/content/references/alchemy.mdx diff --git a/apps/docs/content/references/alchemy.mdx b/apps/docs/content/references/alchemy.mdx new file mode 100644 index 00000000..7fa06ca0 --- /dev/null +++ b/apps/docs/content/references/alchemy.mdx @@ -0,0 +1,130 @@ +--- +title: Alchemy +description: Manage Zerops resources and deployments with Alchemy. +--- + +## Install + +```sh +npm i @zerops/alchemy alchemy@2.0.0-beta.84 effect +``` + +```sh +bun add @zerops/alchemy alchemy@2.0.0-beta.84 effect +``` + +## Auth + +```sh +export ZEROPS_TOKEN="YOUR_TOKEN" +``` + +- Create a token in [token management](https://app.zerops.io/settings/token-management). + +| Variable | Setting | +| --- | --- | +| `ZEROPS_TOKEN` | Bearer token. | +| `ZEROPS_ENDPOINT` | Optional API origin; default `https://api.app-prg1.zerops.io`. | +| `ZEROPS_ORGANIZATION_ID` | Optional organization API `clientId`; required with multiple memberships. | + +### Alchemy profile alternative + +```sh +bunx alchemy profile create zerops +bunx alchemy profile edit --profile zerops --add Zerops +bunx alchemy deploy --profile zerops +``` + +- Profile fields: `token`, optional `endpoint`, optional `organizationId`. + +## Minimal stack + +```ts title="alchemy.run.ts" +import * as Alchemy from "alchemy"; +import * as Effect from "effect/Effect"; +import * as Zerops from "@zerops/alchemy"; + +export default Alchemy.Stack("ZeropsApp", { + providers: Zerops.providers(), + state: Alchemy.localState(), +}, Effect.gen(function* () { + const project = yield* Zerops.Project("Project", { mode: "LIGHT" }); + const db = yield* Zerops.ManagedService("Database", { + project, hostname: "db", type: "postgresql:single@16", + }); + const api = yield* Zerops.Service("Api", { + project, hostname: "api", type: "nodejs@22", + source: { dir: "./api" }, + env: { DATABASE_URL: Zerops.ref(db, "connectionString") }, + subdomain: true, + }); + const route = yield* Zerops.HttpRoute("ApiRoute", { + project, domains: ["api.example.com"], ssl: false, + locations: [{ path: "/", service: api, port: 3000 }], + }); + return { subdomainUrls: api.subdomainUrls, routeId: route.routeId }; +})); +``` + +- `api/`: Node.js app with `package.json`, lockfile, and `npm start` listening on port 3000. +- `api/zerops.yml`: setup `api`, Node.js 22 build/run, HTTP port 3000; + see [zerops.yml specification](/zerops-yaml/specification). +- `Zerops.ref(db, "connectionString")` renders a server-side environment reference; + no database credentials fetched. +- Configure custom-domain DNS separately; certificate issuance is not awaited. + +```sh +bunx alchemy plan +bunx alchemy deploy +``` + +## Resource map + +| Alchemy resource | Zerops object | +| --- | --- | +| `Zerops.Project` | Project | +| `Zerops.Service` | Runtime service and source deployment; optional generated subdomain | +| `Zerops.ManagedService` | Managed service without application code | +| `Zerops.Postgres`, `Zerops.MariaDB`, `Zerops.Valkey` | Typed managed-service factories | +| `Zerops.ProjectVariable` | Project environment variable | +| `Zerops.ServiceVariable` | Service environment variable | +| `Zerops.ObjectStorage` | Object-storage service, quota, access policy | +| `Zerops.HttpRoute` | Custom-domain HTTP routing | +| `Zerops.PortRoute` | Public IPv6 TCP/UDP routing | + +## Deploy sources + +| Source | `Zerops.Service` props | +| --- | --- | +| Directory | `source: { dir: "./api" }` | +| Archive | `source: { archive: "./api.tar.gz" }`; `build: false` for prebuilt code | +| Git ref | `source: { git: { url: "https://github.com/owner/repo.git", ref: "v1.0.0" } }` | + +- Exactly one source mode per deployment. +- Root `zerops.yml` / `zerops.yaml`, or explicit `zeropsYaml`; `setup` defaults to the service hostname. +- Git branches and tags resolve to commits; tags and full 40-character SHAs are fetched provider-side, not branch-HEAD builds on Zerops. +- Private HTTP(S) Git: `git.auth` accepts an Effect `Redacted` token; no credentials in URLs. +- Directory/Git sources exclude `.git` and `.alchemy`; use `.deployignore` or directory `ignore` for other sensitive files. + +## Adoption and ownership + +- Existing unowned resources: `bunx alchemy deploy --adopt`; subsequent updates and deletion belong to the stack. +- Project tag `alchemy:<48 hex>` hashes stack/stage/resource FQN; matching tags recover ownership after state loss without `--adopt`. +- Keep logical IDs, stack, and stage stable; do not remove or forge ownership tags. +- Existing explicit service/storage hostnames and variables/routes require adoption; incompatible service types are refused. +- Resource `.ref(...)` reads Alchemy state; not remote lookup or adoption. + +## Behaviour notes + +- Drift: `bunx alchemy drift --no-input`; intentional repair: `bunx alchemy drift --repair --no-input`. +- Generated secrets stay out of resource attributes; environment attributes store digests. Masked secret-content drift cannot be detected. +- Resolved props, including user-supplied secrets, persist as plaintext in Alchemy state; `Redacted` does not encrypt state. +- Routing sync commits all staged edits for the project/routing kind. Foreign staged edits block sync unless `forceSync: true` or `ZEROPS_ROUTING_FORCE_SYNC=true`; use one routing writer per project/kind. +- PostgreSQL disk floor: 2 GB; `ZEROPS_POSTGRESQL_MIN_DISK_GB` can raise it, never lower it. Explicit lower bounds are rejected. +- Alchemy v2 is beta; provider pinned to `alchemy@2.0.0-beta.84`. +- Destroy deletes managed resources, including database and object-storage data. + +## Links + +- [GitHub repository](https://github.com/zeropsio/alchemy) +- [Alchemy documentation](https://alchemy.run) diff --git a/apps/docs/sidebars.js b/apps/docs/sidebars.js index 6b4c3853..581198a4 100644 --- a/apps/docs/sidebars.js +++ b/apps/docs/sidebars.js @@ -940,6 +940,15 @@ module.exports = { }, className: 'homepage-sidebar-item', }, + { + type: 'doc', + id: 'references/alchemy', + label: 'Alchemy', + customProps: { + sidebar_icon: 'curly-braces', + }, + className: 'homepage-sidebar-item', + }, { type: 'doc', id: 'references/api', From afa1ad8691d7e2c8fc3ad3e90297d221e4b7d00a Mon Sep 17 00:00:00 2001 From: Samyazz <49154465+Samyazz@users.noreply.github.com> Date: Fri, 30 Oct 2026 08:32:40 +0100 Subject: [PATCH 2/2] Alchemy reference: managed family helpers (0.2.0) --- apps/docs/content/references/alchemy.mdx | 34 +++++++++++++++++++++--- 1 file changed, 30 insertions(+), 4 deletions(-) diff --git a/apps/docs/content/references/alchemy.mdx b/apps/docs/content/references/alchemy.mdx index 7fa06ca0..7a544ece 100644 --- a/apps/docs/content/references/alchemy.mdx +++ b/apps/docs/content/references/alchemy.mdx @@ -3,6 +3,8 @@ title: Alchemy description: Manage Zerops resources and deployments with Alchemy. --- +Provider version: **0.2.0**; requires `alchemy@2.0.0-beta.84`. + ## Install ```sh @@ -49,8 +51,8 @@ export default Alchemy.Stack("ZeropsApp", { state: Alchemy.localState(), }, Effect.gen(function* () { const project = yield* Zerops.Project("Project", { mode: "LIGHT" }); - const db = yield* Zerops.ManagedService("Database", { - project, hostname: "db", type: "postgresql:single@16", + const db = yield* Zerops.Postgres("Database", { + project, hostname: "db", version: "16", }); const api = yield* Zerops.Service("Api", { project, hostname: "api", type: "nodejs@22", @@ -85,13 +87,37 @@ bunx alchemy deploy | `Zerops.Project` | Project | | `Zerops.Service` | Runtime service and source deployment; optional generated subdomain | | `Zerops.ManagedService` | Managed service without application code | -| `Zerops.Postgres`, `Zerops.MariaDB`, `Zerops.Valkey` | Typed managed-service factories | +| Managed family helpers | Typed managed services; see below | | `Zerops.ProjectVariable` | Project environment variable | | `Zerops.ServiceVariable` | Service environment variable | | `Zerops.ObjectStorage` | Object-storage service, quota, access policy | | `Zerops.HttpRoute` | Custom-domain HTTP routing | | `Zerops.PortRoute` | Public IPv6 TCP/UDP routing | + +## Managed families + +| Helper | Versions | Modes | Floor | Typical ref keys | +| --- | --- | --- | --- | --- | +| `Postgres` | 14, 16, 17, 18 | Single / HA | Disk 2 GB | `connectionString`, `hostname`, `user`, `password` | +| `MariaDB` | 10.6 | Single / HA | Catalogue minimum | `connectionString`, `dbName`, `user`, `password` | +| `Valkey` | 7.2 | Single / HA | Catalogue minimum | `connectionString`, `connectionTlsString`, `hostname`, `password` | +| `ClickHouse` | 25.3 | Single / HA | RAM 0.375 GB | `connectionString`, `portHttp`, `user`, `password` | +| `Elasticsearch` | 8.16, 9.2 | Single / HA | RAM 2 GB | `connectionString`, `hostname`, `user`, `password` | +| `Kafka` | 3.9 | Single / HA | Catalogue minimum | `hostname`, `port`, `user`, `password` | +| `Nats` | 2.10, 2.12 | Single / HA | Catalogue minimum | `connectionString`, `portManagement`, `user`, `password` | +| `Qdrant` | 1.10, 1.12 | Single / HA | Catalogue minimum | `connectionString`, `grpcConnectionString`, `apiKey`, `readOnlyApiKey` | +| `Typesense` | 27.1, 30.2 | Single / HA | Catalogue minimum | `connectionString`, `apiKey`, `hostname`, `port` | +| `SeaweedFS` | 3.85 | Single / HA | Catalogue minimum | `hostname`, `port`, `projectId`, `serviceId` | +| `Meilisearch` | 1.10, 1.20, 1.44 | Single only | Catalogue minimum | `connectionString`, `masterKey`, `defaultSearchKey`, `hostname` | +| `LocalStorage` | 1 | Single only | Catalogue minimum | `hostname`, `projectId`, `serviceId`, `BACKUP_PERIOD` | + +- Helpers take `project`, `version`, optional `hostname` and managed-service props; default mode is `"NON_HA"` (single). +- `mode: "HA"` unlocks PostgreSQL `connectionStringReplicas` / `portReplicas` and Valkey `connectionStringReplicas` / `connectionTlsStringReplicas` / `portReplicas` / `portTlsReplicas`. +- `SeaweedFS` is shared storage; deprecated `shared-storage` import aliases map to it. +- `ManagedService({ type })` is the untyped escape hatch; family floors and mode restrictions still apply. +- Full ref keys and floor environment overrides: [provider README](https://github.com/zeropsio/alchemy#managed-families). + ## Deploy sources | Source | `Zerops.Service` props | @@ -120,7 +146,7 @@ bunx alchemy deploy - Generated secrets stay out of resource attributes; environment attributes store digests. Masked secret-content drift cannot be detected. - Resolved props, including user-supplied secrets, persist as plaintext in Alchemy state; `Redacted` does not encrypt state. - Routing sync commits all staged edits for the project/routing kind. Foreign staged edits block sync unless `forceSync: true` or `ZEROPS_ROUTING_FORCE_SYNC=true`; use one routing writer per project/kind. -- PostgreSQL disk floor: 2 GB; `ZEROPS_POSTGRESQL_MIN_DISK_GB` can raise it, never lower it. Explicit lower bounds are rejected. +- Unset scaling minima default to family floors; explicit min/max below the floor are rejected. `ZEROPS_POSTGRESQL_MIN_DISK_GB`, `ZEROPS_CLICKHOUSE_MIN_RAM_GB` and `ZEROPS_ELASTICSEARCH_MIN_RAM_GB` replace their floors, bounded below by catalogue minima (1 GB disk, 0.25 GB RAM and 0.75 GB RAM respectively). - Alchemy v2 is beta; provider pinned to `alchemy@2.0.0-beta.84`. - Destroy deletes managed resources, including database and object-storage data.