Skip to content

Commit 0d3dca0

Browse files
committed
More site info/content
1 parent d2d7ad7 commit 0d3dca0

149 files changed

Lines changed: 8152 additions & 199 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.env.template‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
# Cloudflare dashboard: Account home > Search > "Copy account ID"
2+
CLOUDFLARE_ACCOUNT_ID=
3+
# Cloudflare dashboard: My Profile > API Tokens > Create Token
4+
CLOUDFLARE_API_TOKEN=

‎.gitignore‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,8 @@ tests/**/js/
1414

1515
# Nacara site output
1616
site/output/
17+
18+
# Local credentials: copy .env.template to .env. Git ignores .env and keeps the template.
19+
.env
20+
.env.*
21+
!.env.template

‎site/Site.fs‎

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ let theme =
119119
Theme.defaults
120120
|> Theme.navbar
121121
[
122+
NavbarSection ("Start here", "guide", "/guide/")
122123
NavbarDropdown (
123124
"Libraries",
124125
[
@@ -128,6 +129,7 @@ let theme =
128129
NavbarDescribed ("Background Work", "Queues and Workflows", "/libraries/platform/background-work/")
129130
NavbarDescribed ("Agents", "Agents SDK, Code Mode, Shell and Voice", "/libraries/agents/")
130131
NavbarDescribed ("AI", "Workers AI, AI Gateway and AI Search", "/libraries/ai/")
132+
NavbarDescribed ("Hybrid Search", "Keyword and vector search, indexed incrementally", "/libraries/hybrid-search/")
131133
NavbarDescribed ("Compute", "Sandbox and Computer", "/libraries/compute/")
132134
NavbarDescribed ("Services", "Containers, Actors, OAuth and more", "/libraries/services/")
133135
NavbarDescribed ("RPC", "Cap'n Web", "/libraries/rpc/")
@@ -139,6 +141,19 @@ let theme =
139141
NavbarSection ("Line-up", "libraries", "/libraries/")
140142
NavbarLink ("Control plane", "/libraries/control-plane/")
141143
]
144+
|> Theme.menu
145+
"guide"
146+
[
147+
Menu.section
148+
"Start Here"
149+
[
150+
Menu.page "guide/index.md"
151+
Menu.page "guide/credentials.md"
152+
Menu.page "guide/local-build.md"
153+
Menu.page "guide/first-worker.md"
154+
Menu.page "guide/first-deploy.md"
155+
]
156+
]
142157
|> Theme.menu
143158
"libraries"
144159
[
@@ -155,6 +170,7 @@ let theme =
155170
]
156171
Menu.page "libraries/agents.md"
157172
Menu.page "libraries/ai.md"
173+
Menu.page "libraries/hybrid-search.md"
158174
Menu.page "libraries/compute.md"
159175
Menu.page "libraries/services.md"
160176
Menu.page "libraries/rpc.md"
@@ -166,8 +182,10 @@ let theme =
166182
"Control plane"
167183
[
168184
Menu.page "libraries/control-plane/index.md"
185+
Menu.link "Credentials" "/FSharp.CloudEdge/guide/credentials/"
169186
Menu.page "libraries/control-plane/account-setup.md"
170187
Menu.page "libraries/control-plane/worker-upload.md"
188+
Menu.page "libraries/control-plane/asset-uploads.md"
171189
Menu.page "libraries/control-plane/clients.md"
172190
]
173191
]

‎site/content/guide/credentials.md‎

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
---
2+
title: Credentials
3+
description: The account ID and API token your F# programs use.
4+
order: 2
5+
---
6+
7+
<div class="ce-block-head">
8+
<p class="ce-block-lead">Your F# programs call Cloudflare's API with two values: your account ID and an API token. You find both in the Cloudflare dashboard, and your programs read them from environment variables.</p>
9+
<ul class="ce-facts">
10+
<li><span>You need</span> A Cloudflare account</li>
11+
<li><span>You get</span> <code>CLOUDFLARE_ACCOUNT_ID</code> and <code>CLOUDFLARE_API_TOKEN</code>, kept in <code>.env</code></li>
12+
</ul>
13+
</div>
14+
15+
## Account ID
16+
17+
The account ID identifies your Cloudflare account. Every account-level operation in the generated clients takes it as an `accountId` argument, `StorageClient.D1CreateDatabase` among them.
18+
19+
1. Open the Cloudflare dashboard and go to **Account home**.
20+
2. Select **Search**, or press `Ctrl+K` (`Cmd+K` on a Mac).
21+
3. Enter `Copy account ID` and choose the result. The ID is now on your clipboard.
22+
23+
The **Account Details** section of **Workers & Pages** shows the same ID, with a copy button beside **Account ID**.
24+
25+
## Scoped API Token
26+
27+
Your programs send the token with every request, and Cloudflare checks each request against the token's permissions. Create a user token with the five permissions that the later examples require.
28+
29+
1. Go to **My Profile** > **API Tokens** and select **Create Token**.
30+
2. In the **Custom token** section, click **Get started** beside **Create Custom Token**.
31+
3. Under **Token name**, enter `hello-worker`.
32+
4. Under **Permissions**, add a row for each permission in the table below. Use **Add more** to start each new row.
33+
5. In each row, set the first menu to **Account** and the last one to **Edit**. In the middle menu, pick the permission group from the table, such as **D1**.
34+
6. Under **Account Resources**, keep **Include** and choose your account.
35+
7. Select **Continue to summary**, review the five permissions, and finish with **Create Token**.
36+
8. Copy the token. The same page has a `curl` command in its **Test this token** section. Run it. A reply with `"status": "active"` means the token works.
37+
38+
:::warning
39+
Cloudflare shows the token once. Before you leave the page, save it in a password manager for the `.env` steps.
40+
:::
41+
42+
## Token Permissions
43+
44+
All five are **Account** permissions at the **Edit** level. On the API tab of Cloudflare's [permissions reference](https://developers.cloudflare.com/fundamentals/api/reference/permissions/), the same permission names end in **Write** where the dashboard uses **Edit**.
45+
46+
| Permission | Covers | Used on |
47+
| --- | --- | --- |
48+
| D1 Edit | D1 databases | [Account Setup](../libraries/control-plane/account-setup.md) |
49+
| Workers R2 Storage Edit | R2 buckets | [Account Setup](../libraries/control-plane/account-setup.md) |
50+
| Workers KV Storage Edit | KV namespaces | [Account Setup](../libraries/control-plane/account-setup.md) |
51+
| Queues Edit | Queues | [Account Setup](../libraries/control-plane/account-setup.md) |
52+
| Workers Scripts Edit | Worker scripts | [Worker Upload](../libraries/control-plane/worker-upload.md), [First Deploy](first-deploy.md) |
53+
54+
Other clients require other permissions. You can add them later, since Cloudflare lets you edit an existing token.
55+
56+
## Token Safety
57+
58+
- **Use a scoped token.** Cloudflare's Global API Key has the same permissions as your user, on all of your resources. Anyone holding your new token can perform the actions its five permissions grant.
59+
- **Keep tokens out of source control.** The token belongs in `.env`, which Git ignores in the FSharp.CloudEdge folder. GitHub scans public repositories for Cloudflare tokens. When it finds one, Cloudflare revokes the token and notifies you by email.
60+
- **Roll a leaked token.** On **My Profile** > **API Tokens**, open the three-dot menu next to the token and choose **Roll**, then **Confirm**. Cloudflare invalidates the old secret, and the new one has the same permissions.
61+
62+
## The .env File
63+
64+
You clone FSharp.CloudEdge into your `repos` folder on [Local Build](local-build.md). Its root holds a template for this file, `.env.template`, and its `.gitignore` lists `.env`.
65+
66+
1. From your `repos` folder, copy the template and make `.env` readable by your user alone.
67+
68+
```bash
69+
cd FSharp.CloudEdge
70+
cp .env.template .env
71+
chmod 600 .env
72+
cat .env
73+
```
74+
75+
```text
76+
# Cloudflare dashboard: Account home > Search > "Copy account ID"
77+
CLOUDFLARE_ACCOUNT_ID=
78+
# Cloudflare dashboard: My Profile > API Tokens > Create Token
79+
CLOUDFLARE_API_TOKEN=
80+
```
81+
82+
2. Open `.env` in your editor. Paste each value straight after its `=` sign: the account ID on the `CLOUDFLARE_ACCOUNT_ID=` line and the token on the `CLOUDFLARE_API_TOKEN=` line. Save your changes.
83+
84+
3. Confirm that Git ignores `.env`.
85+
86+
```bash
87+
git check-ignore .env
88+
```
89+
90+
```text
91+
.env
92+
```
93+
94+
## Shell Variables
95+
96+
`Environment.GetEnvironmentVariable` reads the environment that your terminal passes to each program it starts. Load `.env` into that environment from the FSharp.CloudEdge folder.
97+
98+
```bash
99+
set -a
100+
source .env
101+
set +a
102+
```
103+
104+
`set -a` marks every variable that `source` reads from `.env` for export, and `set +a` turns the marking off. Check the result:
105+
106+
```bash
107+
printenv CLOUDFLARE_ACCOUNT_ID
108+
```
109+
110+
It prints your account ID. If the output is empty, run the three lines again in this terminal.
111+
112+
In each new terminal, load `.env` again. From your hello-worker folder, the path is `../FSharp.CloudEdge/.env`:
113+
114+
```bash
115+
set -a
116+
source ../FSharp.CloudEdge/.env
117+
set +a
118+
```
119+
120+
## Client Setup
121+
122+
Every generated client takes an `HttpClient`. This one uses Cloudflare's API base address and sends your token in a bearer header. When a variable is missing, `fromEnvironment` reports the name and exits.
123+
124+
```fsharp
125+
module ClientSetup
126+
127+
open System
128+
open System.Net.Http
129+
open System.Net.Http.Headers
130+
131+
let fromEnvironment name =
132+
match Environment.GetEnvironmentVariable name with
133+
| null | "" ->
134+
eprintfn "%s is not set. Load .env into this terminal first." name
135+
exit 1
136+
| value -> value
137+
138+
let accountId () = fromEnvironment "CLOUDFLARE_ACCOUNT_ID"
139+
140+
let cloudflareHttp () =
141+
let token = fromEnvironment "CLOUDFLARE_API_TOKEN"
142+
let http = new HttpClient()
143+
http.BaseAddress <- Uri "https://api.cloudflare.com/client/v4"
144+
let headers = http.DefaultRequestHeaders
145+
headers.Authorization <- AuthenticationHeaderValue("Bearer", token)
146+
http
147+
```
148+
149+
A program that uses it, started before `.env` is loaded, prints this line:
150+
151+
```text
152+
CLOUDFLARE_API_TOKEN is not set. Load .env into this terminal first.
153+
```
154+
155+
## Token Check
156+
157+
`UserApiTokensVerifyToken` on the Tenancy client sends `GET /user/tokens/verify`, the same request as the **Test this token** command. The result is a union. `OK` holds the reply to HTTP 200, and `Status4XX` holds the status code and Cloudflare's errors for a 4xx response. `checkToken` takes the `HttpClient` from Client Setup.
158+
159+
```fsharp
160+
module TokenCheck
161+
162+
open System.Net.Http
163+
open FSharp.CloudEdge.Core.Api.Types
164+
open FSharp.CloudEdge.Tenancy
165+
166+
let checkToken (http: HttpClient) =
167+
task {
168+
let tenancy = TenancyClient http
169+
match! tenancy.UserApiTokensVerifyToken() with
170+
| UserApiTokensVerifyToken.OK payload ->
171+
let tokenStatus =
172+
match payload.result with
173+
| Some result -> string result["status"]
174+
| None -> "unknown"
175+
printfn "Token status: %s" tokenStatus
176+
return tokenStatus = "active"
177+
| UserApiTokensVerifyToken.Status4XX(httpStatus, failure) ->
178+
for error in failure.errors do
179+
eprintfn "HTTP %d: %s" httpStatus error.message
180+
return false
181+
}
182+
```
183+
184+
With a working token, the output is:
185+
186+
```text
187+
Token status: active
188+
```
189+
190+
For a rejected token, the `Status4XX` branch prints the HTTP status with each error message from Cloudflare's reply, and `checkToken` returns `false`.
191+
192+
## Next Step
193+
194+
<div class="ce-next">
195+
<a class="ce-next__card" href="/FSharp.CloudEdge/guide/local-build/"><strong>Local Build</strong><span>Clone and build the libraries</span></a>
196+
</div>

0 commit comments

Comments
 (0)