# Injected process.env

Every FullStacked Cloud project reads its configuration from `process.env`: the platform hosts, the credentials of linked managed data and Edge tunnels, the project's custom variables, and `AUTH_TOKEN`, the current user's own token. The environment comes from `GET https://git.fullstacked.cloud/api/v1/projects/:id/env`, resolved for the caller, plus `AUTH_TOKEN` added at launch. Code never hardcodes a host, a database user or a token.

## Where the environment comes from

| Where the code runs | `process.env` contains |
| :--- | :--- |
| FullStacked Cloud Client GUI | The resolved environment of the signed-in user plus `AUTH_TOKEN` = their session token. If the environment cannot be fetched, the project still runs with `AUTH_TOKEN` alone. |
| Local CLI (`npx fullstacked`) | `<project>/.env` merged with `-e KEY=VALUE` flags (flags win). Write `.env` from `GET .../env?format=dotenv` and pass the token: `npx fullstacked -e AUTH_TOKEN=$AUTH_TOKEN` with a personal access token (`fsc_pat_...`, https://console.fullstacked.cloud Settings, Access tokens). Keep `.env` out of Git. |
| Project action run (`actions/<name>.ts`) | The environment resolved for the caller of the run, `AUTH_TOKEN` = the caller's token, plus run variables (see [Project Actions](https://docs.fullstacked.cloud/actions)). |

## Variables

| Variable | Present | Value |
| :--- | :--- | :--- |
| `AUTH_URL` | Resolved environment | Authentication service base URL, `https://auth.fullstacked.cloud` here. Use for `/api/v1/me`, `/api/v1/user/access`, token exchange. |
| `AUTH_HOST` | Resolved environment | Its host, `auth.fullstacked.cloud`. |
| `TUNNELS_HOST` | Resolved environment | Tunnels hub host for `tunnel.register({ host })`, `tunnels.fullstacked.cloud`. |
| `DOCS_URL` | Resolved environment | This documentation, `https://docs.fullstacked.cloud` (`?format=md` for Markdown). |
| `AUTH_TOKEN` | At launch only | The current user's FullStacked Cloud token: `fsc_ses_...` (Client GUI), `fsc_ath_<slug>_...` (enterprise sign-in), `fsc_pat_...` (personal access token) or the action caller's token. Never part of `GET .../env`, never stored in the project. |
| `PG_DATA_TOKEN`, `REDIS_DATA_TOKEN`, `MONGO_DATA_TOKEN`, `S3_DATA_TOKEN` | Linked data instance | `tun_...` routing token of the instance's tunnel at the caller's access level. Use as `` `${AUTH_TOKEN}:${PG_DATA_TOKEN}` ``. |
| `DATA_USER`, `DATA_PASSWORD` | Linked PostgreSQL, Redis, MongoDB | `app_rw` or `app_ro` and its password, matching the caller's access (read-write or read-only). |
| `DATA_DB` | Linked PostgreSQL, MongoDB | Database name, e.g. `data_pg_1`, `data_mongo_1`. Not set for Redis. |
| `DATA_KEY_ID`, `DATA_KEY_SECRET`, `DATA_BUCKET` | Linked S3 | Access key, secret key and bucket name for the caller's access level. |
| `<PREFIX>_TUNNEL_TOKEN` | Linked Edge tunnel | `tun_...` token of the tunnel. Use as `` `${AUTH_TOKEN}:${OFFICE_API_TUNNEL_TOKEN}` ``. |
| Custom variables | Set on the project | Any `NAME=value` stored with `PUT .../env` (Console: Project, Environment). |

The four platform hosts are part of every resolved environment, for the environment the project belongs to (live here): the same code runs against test and live. They are missing when no environment was resolved: a Client GUI launch whose environment request failed (only `AUTH_TOKEN` is set), or a local CLI run without a `.env` written from `GET .../env`. Check them like any other variable.

## Naming rules

- The **oldest linked data instance** gets unprefixed names (`DATA_USER`, `PG_DATA_TOKEN`, ...).
- Every **other linked data instance** gets the same names prefixed with its display name: upper-cased, non-alphanumeric runs replaced by `_`, leading and trailing `_` trimmed, `_` prepended before a leading digit (instance `analytics-db` gives `ANALYTICS_DB_DATA_USER`, `ANALYTICS_DB_PG_DATA_TOKEN`, ...).
- **Edge tunnels** are always prefixed with the tunnel name, normalized the same way (`office-api` gives `OFFICE_API_TUNNEL_TOKEN`). Tunnel names are unique per Edge only: two linked tunnels with the same name produce the same variable, and the second is dropped into `conflicts`. Give one of them a prefix mapping.
- A **prefix mapping** (`PUT .../env` with `mappings`) overrides the prefix of one resource; an empty prefix is not allowed (prefix: `A-Z` then up to 63 of `A-Z`, `0-9`, `_`).
- Names never overwrite each other. Platform hosts come first, then linked data (oldest link first), then tunnels, then custom variables; a later entry with an existing name is dropped and reported in `conflicts`.
- Resources the caller cannot use are omitted silently, so a variable can be absent for one user and present for another: check before use.

```ts
function requireEnv(name: string): string {
    const value = process.env[name];
    if (!value) throw new Error(`${name} is not set: link the resource to the project or run with AUTH_TOKEN`);
    return value;
}
```

## GET /api/v1/projects/:id/env

`GET https://git.fullstacked.cloud/api/v1/projects/<projectId>/env?format=json|dotenv` with `Authorization: Bearer <fsc_* token>`. Any project tier may call it; the values are resolved with the caller's own access. MCP: `projects_get_env`.

```json
{
  "projectId": "7f3b89a2-4c1e-48a0-9d21-f8e910243abc",
  "project": "alice/task-flow",
  "accessTier": "FULL_ACCESS",
  "env": {
    "TUNNELS_HOST": "tunnels.fullstacked.cloud",
    "AUTH_HOST": "auth.fullstacked.cloud",
    "AUTH_URL": "https://auth.fullstacked.cloud",
    "DOCS_URL": "https://docs.fullstacked.cloud",
    "PG_DATA_TOKEN": "tun_4b8c9d...",
    "DATA_USER": "app_rw",
    "DATA_PASSWORD": "...",
    "DATA_DB": "data_pg_1",
    "OFFICE_API_TUNNEL_TOKEN": "tun_3f9a2b...",
    "APP_TITLE": "Task Flow"
  },
  "meta": { "PG_DATA_TOKEN": { "source": "linked_data", "resourceId": "9b2f6c1e-...", "name": "tasks-db", "engine": "postgres", "access": "READ_WRITE", "secret": true } },
  "resources": [{ "source": "linked_data", "resourceId": "9b2f6c1e-...", "name": "tasks-db", "prefix": "", "mapped": false }],
  "variables": { "APP_TITLE": "Task Flow" },
  "mappings": {},
  "conflicts": []
}
```

`meta` has one entry per variable (`source`: `platform`, `linked_data`, `linked_tunnel` or `custom`; `secret` is false only for hosts, `DATA_USER`, `DATA_DB`, `DATA_BUCKET` and custom variables). `format=dotenv` returns the same `env` as `KEY=value` lines.

## PUT /api/v1/projects/:id/env

Requires `write` on the project. MCP: `projects_set_env`.

```json
{ "variables": { "APP_TITLE": "Task Flow", "OLD_FLAG": null }, "mappings": { "<resourceId>": { "prefix": "CACHE" } } }
```

- `null` removes a variable or mapping.
- Names: `^[A-Z_][A-Z0-9_]{0,127}$`; values: single-line strings up to 4096 characters; at most 200 variables and 100 mappings.
- Setting `AUTH_TOKEN`, `AUTH_URL`, `AUTH_HOST`, `TUNNELS_HOST` or `DOCS_URL` is refused (`400 RESERVED_VARIABLE`).
- Custom variables are visible to every project tier, including release-only users: store configuration there, never secrets.

## Endpoints

### GET /api/v1/projects/:id/env

The project's resolved runtime environment: DATA_* wiring and tokens of linked instances, platform URLs (AUTH_URL, AUTH_HOST, TUNNELS_HOST, DOCS_URL) and custom variables. ?format=json|dotenv; never contains AUTH_TOKEN.

- **Service**: `git` (`https://git.fullstacked.cloud`)
- **Auth**: Bearer fsc_*

curl:

```bash
curl -sS -H "Authorization: Bearer $AUTH_TOKEN" "https://git.fullstacked.cloud/api/v1/projects/<projectId>/env?format=dotenv"
```

### PUT /api/v1/projects/:id/env

Merges { variables?, mappings? } into the project's environment config (null removes a key). Needs write.

- **Service**: `git` (`https://git.fullstacked.cloud`)
- **Auth**: Bearer fsc_*

Request:

```json
{
  "variables": {
    "API_BASE": "https://example.com"
  }
}
```
