@jimhoyd/urlcode 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CONTRIBUTING.md +80 -0
- package/LICENSE +202 -0
- package/NOTICE +20 -0
- package/README.md +342 -0
- package/ROADMAP.md +248 -0
- package/SECURITY.md +40 -0
- package/data/agents/LICENSES/ai-robots-txt.txt +24 -0
- package/data/agents/LICENSES/crawler-user-agents.txt +23 -0
- package/data/agents/ai-crawlers.json +1240 -0
- package/data/agents/crawlers.json +10515 -0
- package/data/agents/index.d.ts +3 -0
- package/data/agents/index.js +2453 -0
- package/data/agents/monitoring.json +1520 -0
- package/data/agents/seo.json +3865 -0
- package/dist/BUILD-MANIFEST.json +60 -0
- package/dist/adapters.js +59 -0
- package/dist/agent-lists.js +59 -0
- package/dist/assets.js +129 -0
- package/dist/authoring.js +68 -0
- package/dist/aws.js +110 -0
- package/dist/build-cloudflare.js +164 -0
- package/dist/cli.js +185 -0
- package/dist/client-address.js +85 -0
- package/dist/cloudflare.js +165 -0
- package/dist/compliance-rules/baseline.js +98 -0
- package/dist/compliance-rules/privacy.js +38 -0
- package/dist/compliance-rules/shared.js +62 -0
- package/dist/compliance-rules/strict.js +61 -0
- package/dist/compliance.js +219 -0
- package/dist/config-worker.js +9 -0
- package/dist/config.js +172 -0
- package/dist/errors.js +8 -0
- package/dist/function-sources.js +54 -0
- package/dist/function-worker.js +105 -0
- package/dist/functions.js +174 -0
- package/dist/guest-api.js +114 -0
- package/dist/header-validation.js +18 -0
- package/dist/http-policy.js +74 -0
- package/dist/http-response.js +84 -0
- package/dist/index.js +11 -0
- package/dist/link-api.js +136 -0
- package/dist/link-cli.js +141 -0
- package/dist/link-events.js +76 -0
- package/dist/link-records.js +31 -0
- package/dist/link-store-worker.js +150 -0
- package/dist/link-store.js +250 -0
- package/dist/logging.js +22 -0
- package/dist/management-policy.js +41 -0
- package/dist/match.js +124 -0
- package/dist/observability.js +242 -0
- package/dist/plugins.js +74 -0
- package/dist/policies/agents.js +248 -0
- package/dist/policies/cache.js +297 -0
- package/dist/policies/compression.js +187 -0
- package/dist/policies/security.js +0 -0
- package/dist/policies/throttle.js +131 -0
- package/dist/policies.js +142 -0
- package/dist/policy.js +55 -0
- package/dist/prerender.js +165 -0
- package/dist/project-tests.js +23 -0
- package/dist/readiness.js +216 -0
- package/dist/router.js +166 -0
- package/dist/runtime.js +244 -0
- package/dist/scaffold.js +0 -0
- package/dist/scripts/operational-drills.js +75 -0
- package/dist/server.js +270 -0
- package/dist/site.js +0 -0
- package/dist/sqlite-version.js +6 -0
- package/dist/types/adapters.d.ts +12 -0
- package/dist/types/agent-lists.d.ts +5 -0
- package/dist/types/assets.d.ts +13 -0
- package/dist/types/authoring.d.ts +2 -0
- package/dist/types/aws.d.ts +35 -0
- package/dist/types/build-cloudflare.d.ts +14 -0
- package/dist/types/cli.d.ts +2 -0
- package/dist/types/client-address.d.ts +9 -0
- package/dist/types/cloudflare.d.ts +75 -0
- package/dist/types/compliance-rules/baseline.d.ts +12 -0
- package/dist/types/compliance-rules/privacy.d.ts +6 -0
- package/dist/types/compliance-rules/shared.d.ts +24 -0
- package/dist/types/compliance-rules/strict.d.ts +9 -0
- package/dist/types/compliance.d.ts +119 -0
- package/dist/types/config-worker.d.ts +1 -0
- package/dist/types/config.d.ts +21 -0
- package/dist/types/errors.d.ts +7 -0
- package/dist/types/function-sources.d.ts +21 -0
- package/dist/types/function-worker.d.ts +1 -0
- package/dist/types/functions.d.ts +92 -0
- package/dist/types/guest-api.d.ts +16 -0
- package/dist/types/header-validation.d.ts +2 -0
- package/dist/types/http-policy.d.ts +39 -0
- package/dist/types/http-response.d.ts +43 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/link-api.d.ts +30 -0
- package/dist/types/link-cli.d.ts +36 -0
- package/dist/types/link-events.d.ts +27 -0
- package/dist/types/link-records.d.ts +11 -0
- package/dist/types/link-store-worker.d.ts +1 -0
- package/dist/types/link-store.d.ts +130 -0
- package/dist/types/logging.d.ts +9 -0
- package/dist/types/management-policy.d.ts +9 -0
- package/dist/types/match.d.ts +81 -0
- package/dist/types/observability.d.ts +104 -0
- package/dist/types/plugins.d.ts +27 -0
- package/dist/types/policies/agents.d.ts +86 -0
- package/dist/types/policies/cache.d.ts +82 -0
- package/dist/types/policies/compression.d.ts +41 -0
- package/dist/types/policies/security.d.ts +37 -0
- package/dist/types/policies/throttle.d.ts +55 -0
- package/dist/types/policies.d.ts +36 -0
- package/dist/types/policy.d.ts +21 -0
- package/dist/types/prerender.d.ts +31 -0
- package/dist/types/project-tests.d.ts +13 -0
- package/dist/types/readiness.d.ts +121 -0
- package/dist/types/router.d.ts +11 -0
- package/dist/types/runtime.d.ts +91 -0
- package/dist/types/scaffold.d.ts +17 -0
- package/dist/types/server.d.ts +37 -0
- package/dist/types/site.d.ts +12 -0
- package/dist/types/sqlite-version.d.ts +1 -0
- package/dist/types/types.d.ts +332 -0
- package/dist/types/vercel.d.ts +12 -0
- package/dist/types.js +177 -0
- package/dist/vercel.js +65 -0
- package/docs/AI-AUTHORING.md +113 -0
- package/docs/ASSETS.md +106 -0
- package/docs/AWS.md +77 -0
- package/docs/BEST-PRACTICES.md +267 -0
- package/docs/CAPACITY.md +208 -0
- package/docs/CLOUDFLARE.md +110 -0
- package/docs/COMPLIANCE.md +242 -0
- package/docs/DYNAMIC-LINKS.md +561 -0
- package/docs/FUNCTION-SECURITY.md +113 -0
- package/docs/HTTP.md +129 -0
- package/docs/INSTALL.md +90 -0
- package/docs/LOAD-TESTING.md +91 -0
- package/docs/LOCAL-DEVELOPMENT.md +99 -0
- package/docs/MANAGEMENT-SECURITY.md +82 -0
- package/docs/MIDDLEWARE.md +83 -0
- package/docs/MONITORING.md +132 -0
- package/docs/OBSERVABILITY.md +229 -0
- package/docs/OPERATIONAL-PROOF.md +42 -0
- package/docs/OPERATIONS.md +207 -0
- package/docs/ORGANIZATION.md +135 -0
- package/docs/PERFORMANCE.md +72 -0
- package/docs/PLUGINS.md +234 -0
- package/docs/POLICIES.md +489 -0
- package/docs/PRERENDER.md +193 -0
- package/docs/PROJECT-DIRECTION.md +51 -0
- package/docs/READINESS.md +125 -0
- package/docs/README.md +58 -0
- package/docs/RELEASE-READINESS.md +95 -0
- package/docs/RELEASE-SECURITY.md +72 -0
- package/docs/RESILIENCE.md +160 -0
- package/docs/ROUTING.md +95 -0
- package/docs/SANDBOX-REVIEW.md +59 -0
- package/docs/SCAFFOLDING.md +72 -0
- package/docs/SECURITY-AUDIT.md +124 -0
- package/docs/SITE.md +150 -0
- package/docs/SPECIFICATION.md +232 -0
- package/docs/SPIKE-EXTENSIONS.md +475 -0
- package/docs/STANDARDS.md +303 -0
- package/docs/STARTERS.md +51 -0
- package/docs/TUNNELS.md +75 -0
- package/docs/TYPESCRIPT.md +102 -0
- package/docs/VERCEL.md +107 -0
- package/docs/YAML-GUIDE.md +521 -0
- package/docs/YAML-REFERENCE.md +328 -0
- package/docs/policies/agents.md +182 -0
- package/docs/policies/cache.md +139 -0
- package/docs/policies/compression.md +168 -0
- package/docs/policies/security.md +160 -0
- package/docs/policies/throttle.md +103 -0
- package/examples/assets/.env.example +1 -0
- package/examples/assets/.gitattributes +2 -0
- package/examples/assets/Makefile +30 -0
- package/examples/assets/README.md +18 -0
- package/examples/assets/functions/hello.mjs +3 -0
- package/examples/assets/gitignore.template +7 -0
- package/examples/assets/public/about.html +2 -0
- package/examples/assets/public/assets/example.txt +1 -0
- package/examples/assets/public/guide.txt +1 -0
- package/examples/assets/tests/requests.json +44 -0
- package/examples/assets/urlcode.yaml +27 -0
- package/examples/aws/README.md +13 -0
- package/examples/aws/handler.mjs +5 -0
- package/examples/aws/public/index.html +3 -0
- package/examples/aws/public/notes.txt +1 -0
- package/examples/aws/template.yaml +33 -0
- package/examples/aws/tests/requests.json +9 -0
- package/examples/aws/urlcode.yaml +19 -0
- package/examples/cloudflare/README.md +18 -0
- package/examples/cloudflare/package.json +14 -0
- package/examples/cloudflare/tests/requests.json +9 -0
- package/examples/cloudflare/urlcode.yaml +24 -0
- package/examples/cloudflare/wrangler.toml +5 -0
- package/examples/compliance/README.md +20 -0
- package/examples/compliance/rules.mjs +65 -0
- package/examples/cookbook/README.md +21 -0
- package/examples/cookbook/functions/choice.mjs +4 -0
- package/examples/cookbook/functions/echo.mjs +3 -0
- package/examples/cookbook/functions/hello.mjs +3 -0
- package/examples/cookbook/functions/text.mjs +3 -0
- package/examples/cookbook/middleware/headers.mjs +6 -0
- package/examples/cookbook/public/about.html +1 -0
- package/examples/cookbook/public/assets/index.html +1 -0
- package/examples/cookbook/public/assets/site.css +1 -0
- package/examples/cookbook/public/favicon.svg +1 -0
- package/examples/cookbook/public/guide.txt +1 -0
- package/examples/cookbook/public/llms.txt +6 -0
- package/examples/cookbook/routes/code.yaml +55 -0
- package/examples/cookbook/routes/files.yaml +17 -0
- package/examples/cookbook/routes/policies.yaml +28 -0
- package/examples/cookbook/routes/redirects.yaml +38 -0
- package/examples/cookbook/routes/responses.yaml +26 -0
- package/examples/cookbook/tests/requests.json +254 -0
- package/examples/cookbook/urlcode.yaml +22 -0
- package/examples/live-links/README.md +11 -0
- package/examples/live-links/tests/requests.json +6 -0
- package/examples/live-links/urlcode.yaml +16 -0
- package/examples/monitoring/blackbox-jobs.yaml +37 -0
- package/examples/monitoring/prometheus-rules.yaml +88 -0
- package/examples/monitoring/prometheus-scrape.yaml +20 -0
- package/examples/monitoring/vector.toml +65 -0
- package/examples/prerender/README.md +48 -0
- package/examples/prerender/functions/page.mjs +6 -0
- package/examples/prerender/middleware/template.mjs +29 -0
- package/examples/prerender/prerender.d.mts +4 -0
- package/examples/prerender/prerender.mjs +63 -0
- package/examples/prerender/tests/requests.json +39 -0
- package/examples/prerender/urlcode.yaml +50 -0
- package/examples/tunnel/dev-with-ngrok.sh +61 -0
- package/examples/vercel/README.md +13 -0
- package/examples/vercel/api/index.js +5 -0
- package/examples/vercel/package.json +8 -0
- package/examples/vercel/public/index.html +3 -0
- package/examples/vercel/public/notes.txt +1 -0
- package/examples/vercel/tests/requests.json +48 -0
- package/examples/vercel/urlcode.yaml +19 -0
- package/examples/vercel/vercel.json +10 -0
- package/llms.txt +46 -0
- package/package.json +123 -0
- package/schemas/urlcode.schema.json +1230 -0
- package/starters/default/.gitattributes +1 -0
- package/starters/default/Makefile +30 -0
- package/starters/default/README.md +34 -0
- package/starters/default/functions/hello.mjs +3 -0
- package/starters/default/gitignore.template +8 -0
- package/starters/default/middleware/headers.mjs +6 -0
- package/starters/default/routes/functions.yaml +20 -0
- package/starters/default/routes/marketing/links.yaml +7 -0
- package/starters/default/starter.json +5 -0
- package/starters/default/tests/requests.json +56 -0
- package/starters/default/urlcode.yaml +8 -0
package/docs/SITE.md
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
# Site conventions
|
|
2
|
+
|
|
3
|
+
The optional top-level `site` block generates the small well-known files a
|
|
4
|
+
site is expected to serve. Every key is off unless declared, and each declared
|
|
5
|
+
key becomes one ordinary native route (`respond` or `page`) that is merged into
|
|
6
|
+
the route table before compilation. Everything downstream is unchanged: the
|
|
7
|
+
route appears in `urlcode routes` with `generated: "site.<key>"`, the audit
|
|
8
|
+
generates fixtures for it, host policies apply to it and every deployment
|
|
9
|
+
target compiles it like a route the project wrote by hand. `site` is accepted
|
|
10
|
+
only in the entry `urlcode.yaml`, not in included files.
|
|
11
|
+
|
|
12
|
+
```yaml
|
|
13
|
+
version: "1"
|
|
14
|
+
site:
|
|
15
|
+
robots:
|
|
16
|
+
disallow: [ai-crawlers, /admin]
|
|
17
|
+
allow: [/admin/public]
|
|
18
|
+
sitemap: true
|
|
19
|
+
sitemap:
|
|
20
|
+
exclude: [/drafts/*]
|
|
21
|
+
changefreq: weekly
|
|
22
|
+
favicon: public/favicon.svg
|
|
23
|
+
securityTxt:
|
|
24
|
+
contact: [mailto:security@example.com]
|
|
25
|
+
expires: "2027-01-01T00:00:00Z"
|
|
26
|
+
policy: [https://example.com/security-policy]
|
|
27
|
+
preferredLanguages: [en, fr]
|
|
28
|
+
llms: llms.txt
|
|
29
|
+
routes:
|
|
30
|
+
/: {page: {file: public/index.html}}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
The [cookbook](../examples/cookbook/urlcode.yaml) declares `robots`, `favicon`,
|
|
34
|
+
`securityTxt` and `llms` with request fixtures; `sitemap` is exercised by the
|
|
35
|
+
unit tests because it needs a public origin (below).
|
|
36
|
+
|
|
37
|
+
## Precedence with declared routes
|
|
38
|
+
|
|
39
|
+
A route the project declares at a generated path always wins. The generated
|
|
40
|
+
route is dropped and the activation log records
|
|
41
|
+
`{"event":"site","key":"robots","path":"/robots.txt","status":"shadowed"}`.
|
|
42
|
+
This is how a project keeps a hand-written `robots.txt` while still using
|
|
43
|
+
`site.favicon`, or migrates one file at a time.
|
|
44
|
+
|
|
45
|
+
## The public origin
|
|
46
|
+
|
|
47
|
+
`robots.txt`'s `Sitemap:` line and every `<loc>` in `sitemap.xml` are absolute
|
|
48
|
+
URLs, so the runtime needs to know the origin the site is served from. It
|
|
49
|
+
never guesses from a request: a generated file is a fixed response compiled at
|
|
50
|
+
activation, and a `Host` header is client-controlled. The origin is the
|
|
51
|
+
operator's `--origin https://links.example` flag on `serve`, `dev`,
|
|
52
|
+
`validate`, `test`, `routes`, `audit`, `benchmark` and `build`, or the
|
|
53
|
+
`origin` option of `startServer`/`createRuntime`/`buildCloudflare`.
|
|
54
|
+
|
|
55
|
+
- `site.robots.sitemap: true` without an origin omits the `Sitemap:` line and
|
|
56
|
+
logs `{"event":"site","key":"robots","severity":"info",...}` at activation.
|
|
57
|
+
- `site.sitemap` without an origin **refuses activation**: a sitemap of relative
|
|
58
|
+
URLs is invalid under the protocol, so there is no useful degraded form.
|
|
59
|
+
|
|
60
|
+
## Keys
|
|
61
|
+
|
|
62
|
+
### `robots` → `/robots.txt` (RFC 9309)
|
|
63
|
+
|
|
64
|
+
| Field | Meaning |
|
|
65
|
+
| --- | --- |
|
|
66
|
+
| `disallow` | bundled agent list names (`ai-crawlers`, `crawlers`, `seo`, `monitoring`, the same lists as the [`agents` policy](policies/agents.md)) and/or paths starting with `/` |
|
|
67
|
+
| `allow` | the same shapes, emitted as `Allow:` |
|
|
68
|
+
| `sitemap` | `true` appends `Sitemap: <origin>/sitemap.xml` when the origin is known |
|
|
69
|
+
| `extra` | literal lines appended verbatim (comments, `Crawl-delay`, ...) |
|
|
70
|
+
|
|
71
|
+
List names become one group of `User-agent:` lines followed by `Disallow: /`
|
|
72
|
+
(or `Allow: /`). Paths go under `User-agent: *`; with no paths that group is
|
|
73
|
+
`Allow: /`. A list entry whose name is not usable as a product token (it has
|
|
74
|
+
spaces or pattern metacharacters) is skipped and counted in an info log line.
|
|
75
|
+
The result is served as `text/plain; charset=utf-8`.
|
|
76
|
+
|
|
77
|
+
```
|
|
78
|
+
User-agent: GPTBot
|
|
79
|
+
User-agent: ClaudeBot
|
|
80
|
+
Disallow: /
|
|
81
|
+
|
|
82
|
+
User-agent: *
|
|
83
|
+
Disallow: /admin
|
|
84
|
+
Allow: /admin/public
|
|
85
|
+
|
|
86
|
+
Sitemap: https://links.example/sitemap.xml
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### `sitemap` → `/sitemap.xml` (sitemaps.org protocol 0.9)
|
|
90
|
+
|
|
91
|
+
`true`, or `{ exclude, changefreq, priority }`. The sitemap lists every active
|
|
92
|
+
literal GET route that serves HTML: a `page` whose file is `.html`/`.htm` or
|
|
93
|
+
whose `contentType` is `text/html`; a `respond` route whose `Content-Type`
|
|
94
|
+
response header is `text/html`; and the `.html` files under a `static` mount
|
|
95
|
+
(the mount's `index` file is listed as its directory URL). Excluded:
|
|
96
|
+
parameterized routes, redirects, functions, downloads and stored links,
|
|
97
|
+
disabled or expired routes, `/robots.txt` and `/sitemap.xml`, any route whose
|
|
98
|
+
`response.headers` set `X-Robots-Tag` containing `noindex`, and anything an
|
|
99
|
+
`exclude` pattern matches (an exact path, or a prefix ending in `/*`).
|
|
100
|
+
`lastmod` is the file's modification date for asset routes and omitted
|
|
101
|
+
otherwise. URLs are sorted and XML-escaped; the response is
|
|
102
|
+
`application/xml; charset=utf-8`.
|
|
103
|
+
|
|
104
|
+
More than 50,000 URLs, or a document over the 1 MiB declared-response limit,
|
|
105
|
+
refuses activation with a message saying to generate the file at build time
|
|
106
|
+
and serve it as a static asset instead; the runtime does not split or index
|
|
107
|
+
sitemaps.
|
|
108
|
+
|
|
109
|
+
### `favicon` → `/favicon.ico`
|
|
110
|
+
|
|
111
|
+
A project-relative `.ico`, `.svg` or `.png` file, served as a `page` route
|
|
112
|
+
with `image/x-icon`, `image/svg+xml` or `image/png` and
|
|
113
|
+
`cacheControl: public, max-age=3600` (the closest value in the
|
|
114
|
+
[allowed vocabulary](ASSETS.md)). The route has the usual asset semantics:
|
|
115
|
+
ETag, Last-Modified, conditional requests and ranges.
|
|
116
|
+
|
|
117
|
+
### `securityTxt` → `/.well-known/security.txt` (RFC 9116)
|
|
118
|
+
|
|
119
|
+
| Field | Rule |
|
|
120
|
+
| --- | --- |
|
|
121
|
+
| `contact` (required) | one or more `mailto:`, `tel:` or `https:` URIs |
|
|
122
|
+
| `expires` (required) | UTC ISO timestamp; must be in the future at activation; more than a year away logs a warning (the RFC recommends less than a year) |
|
|
123
|
+
| `policy`, `acknowledgments`, `canonical` | `https:` URIs |
|
|
124
|
+
| `encryption` | `https:`, `dns:` or `openpgp4fpr:` URIs |
|
|
125
|
+
| `preferredLanguages` | language tags, emitted as one comma-separated line |
|
|
126
|
+
|
|
127
|
+
Fields are emitted in the RFC's order (Acknowledgments, Canonical, Contact,
|
|
128
|
+
Encryption, Expires, Policy, Preferred-Languages), one value per line. The
|
|
129
|
+
file is unsigned; add a signed copy as a declared route if you need one. The
|
|
130
|
+
`.well-known` segment is an ordinary route segment (only `.` and `..` are
|
|
131
|
+
refused).
|
|
132
|
+
|
|
133
|
+
### `llms` → `/llms.txt`
|
|
134
|
+
|
|
135
|
+
A project-relative text file served as a `page` route with
|
|
136
|
+
`text/plain; charset=utf-8` and the default `no-cache`.
|
|
137
|
+
|
|
138
|
+
## Per-target support
|
|
139
|
+
|
|
140
|
+
| Target | `robots`, `sitemap`, `securityTxt` (`respond`) | `favicon`, `llms` (`page`) |
|
|
141
|
+
| --- | --- | --- |
|
|
142
|
+
| self-hosted, Vercel, AWS | served | served |
|
|
143
|
+
| Cloudflare | compiled into the artifact (`build --origin` for absolute URLs) | refused at build time like any `page` route: the target has no asset binding; serve them from the platform's static assets |
|
|
144
|
+
|
|
145
|
+
## Not in this release
|
|
146
|
+
|
|
147
|
+
No per-route `noindex` field (use `response.headers: {X-Robots-Tag: noindex}`,
|
|
148
|
+
which the sitemap honours), no sitemap index or split files, no `humans.txt`,
|
|
149
|
+
no signed `security.txt`, and no project `.json` agent lists in `robots`
|
|
150
|
+
(bundled names only).
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
# Implemented 0.1 contract
|
|
2
|
+
|
|
3
|
+
This document and [JSON Schema](../schemas/urlcode.schema.json) describe
|
|
4
|
+
0.2.0. `version: "1"` is the stable project-format contract for the 0.1 release
|
|
5
|
+
line. Later planned features are rejected until implemented.
|
|
6
|
+
|
|
7
|
+
## Files and validation
|
|
8
|
+
|
|
9
|
+
`urlcode.yaml` contains `version`, `routes`, and optional `includes` (an explicit
|
|
10
|
+
list of project-relative YAML files). Included files have the same version/routes
|
|
11
|
+
shape and cannot recursively include files. Duplicate paths across files fail.
|
|
12
|
+
See [organization examples](ORGANIZATION.md) for one-file, multi-file and mixed
|
|
13
|
+
layouts. All references resolve from the project root, not the including file.
|
|
14
|
+
File references resolve inside the project; escaping symlinks fail. No glob,
|
|
15
|
+
remote config or arbitrary infrastructure configuration.
|
|
16
|
+
|
|
17
|
+
YAML 1.2 JSON-compatible values only: string mapping keys, finite numbers,
|
|
18
|
+
booleans and null. No duplicate keys, aliases, anchors, tags, merge keys,
|
|
19
|
+
multiple documents, reserved prototype keys or nesting of 40+ levels. Unknown
|
|
20
|
+
schema fields fail. Files are limited to 32 MiB each, 256 includes and 100,000
|
|
21
|
+
routes total, with a 64 MiB aggregate YAML source cap. Loading runs in a worker
|
|
22
|
+
with a 256 MiB old-generation heap, a 10-second wall deadline and at most two
|
|
23
|
+
concurrent loads per Node isolate. These are not a total process RSS bound.
|
|
24
|
+
Route compilation yields every 64 routes and checks a 10-second cooperative
|
|
25
|
+
deadline; individual synchronous operations are not preempted. At most 1,000 parameterized routes and 1,024 distinct input schemas.
|
|
26
|
+
|
|
27
|
+
## Routes
|
|
28
|
+
|
|
29
|
+
Keys are absolute case-sensitive paths. Trailing slashes are significant.
|
|
30
|
+
Parameters occupy whole segments, e.g. `/p/{id}`, with distinct identifier names.
|
|
31
|
+
Each parameter matches exactly one nonempty segment, never across `/`; it is not
|
|
32
|
+
greedy. No regex paths, host matching or dot segments. Only static directory mounts
|
|
33
|
+
support a terminal `/*` wildcard with an otherwise literal path. Route keys cannot contain
|
|
34
|
+
percent encoding, spaces, backslashes or query strings. Path length is limited
|
|
35
|
+
to 2,048 characters and 32 segments. `/_urlcode` is reserved.
|
|
36
|
+
|
|
37
|
+
One handler per route: `function`, `redirect`, `page`, `static`, `download`, `respond` or `link`.
|
|
38
|
+
See [asset configuration](ASSETS.md) for file handlers. Optional properties:
|
|
39
|
+
|
|
40
|
+
- `methods`: unique HTTP methods; default GET and HEAD. Explicit lists are exact;
|
|
41
|
+
adding GET does not implicitly add HEAD. Wrong method returns 405 plus Allow.
|
|
42
|
+
- `enabled`: false returns 404, the same as unknown paths.
|
|
43
|
+
- `expires`: UTC ISO timestamp (`...ssZ` or `...ss.sssZ`); expired routes return 410.
|
|
44
|
+
- `description`: optional authoring metadata.
|
|
45
|
+
- `middleware`: ordered list of up to 16 `{source, export?}` modules wrapping any
|
|
46
|
+
handler. See [middleware](MIDDLEWARE.md) for the portable contract.
|
|
47
|
+
- `parameters`, `env`, `secrets`: inputs and explicit binding references.
|
|
48
|
+
|
|
49
|
+
Literal paths win; parameter routes with more literal segments win next;
|
|
50
|
+
static mounts follow, longest prefix first. A missing file in the selected mount
|
|
51
|
+
returns 404 without falling back to a shorter mount.
|
|
52
|
+
Equally specific overlapping patterns fail even if methods differ. Match a route
|
|
53
|
+
before checking its methods; do not fall back to a less specific route for 405.
|
|
54
|
+
Requests decode the path once; invalid UTF-8/percent encoding, encoded slashes or
|
|
55
|
+
backslashes, control characters and dot segments return 400. Query values decode
|
|
56
|
+
once. Incoming query data is not automatically forwarded.
|
|
57
|
+
|
|
58
|
+
See [route matching and new links](ROUTING.md) for examples, precedence, wildcard
|
|
59
|
+
limits, reload behavior and the distinction between YAML routes and live link data.
|
|
60
|
+
|
|
61
|
+
The optional top-level `site` block (entry file only) generates native routes
|
|
62
|
+
for site conventions: `robots` → `/robots.txt`, `sitemap` → `/sitemap.xml`,
|
|
63
|
+
`favicon` → `/favicon.ico`, `securityTxt` → `/.well-known/security.txt` and
|
|
64
|
+
`llms` → `/llms.txt`. Each is an ordinary `respond` or `page` route merged in
|
|
65
|
+
before compilation and counted by `routes`/`audit`; a declared route at the same
|
|
66
|
+
path wins and the generated one is logged as shadowed. Absolute URLs come from
|
|
67
|
+
the operator's `--origin`; `sitemap` refuses activation without one. See
|
|
68
|
+
[site conventions](SITE.md).
|
|
69
|
+
|
|
70
|
+
## HTTP request/response configuration
|
|
71
|
+
|
|
72
|
+
Routes accept `request.body` validation and `response.headers` overrides. The
|
|
73
|
+
`respond` handler serves declared text/JSON with a status without running code.
|
|
74
|
+
See [HTTP configuration](HTTP.md) for the exact supported fields, precedence,
|
|
75
|
+
security restrictions and examples.
|
|
76
|
+
|
|
77
|
+
## Policies
|
|
78
|
+
|
|
79
|
+
Optional top-level `policies` and `profiles` keys, and `routes.<path>.policies`,
|
|
80
|
+
declare host-enforced behavior around a route: `throttle`, `agents`, `security`,
|
|
81
|
+
`compression` and `cache`. All are off unless declared; a route's keys merge
|
|
82
|
+
over the project's, `false` disables one, and a target that cannot enforce a
|
|
83
|
+
policy refuses activation naming the route. The five policies are implemented
|
|
84
|
+
for the self-hosted server; Vercel and AWS accept `agents`, `security`, `cache`
|
|
85
|
+
and route-partitioned `throttle`; the Cloudflare build compiles `agents` and
|
|
86
|
+
`security` only. See [policies](POLICIES.md) for the pipeline position, merge
|
|
87
|
+
rules and the per-target table, and [plugins](PLUGINS.md) for the host hook API
|
|
88
|
+
operators pass in code.
|
|
89
|
+
|
|
90
|
+
## Inputs
|
|
91
|
+
|
|
92
|
+
Declare each path placeholder as a required string. Query/header inputs may be
|
|
93
|
+
string, integer, number or boolean. Query arrays declare scalar `items`; repeated
|
|
94
|
+
keys retain order (maximum 100 values). Header names are case-insensitive.
|
|
95
|
+
Duplicate scalar query/header inputs return 400. Required missing inputs return
|
|
96
|
+
400; defaults apply only to absent inputs. Empty strings are present values.
|
|
97
|
+
|
|
98
|
+
Supported validation: `type`, scalar `enum`, `default`, string `minLength`/
|
|
99
|
+
`maxLength`, numeric `minimum`/`maximum`, query array `items` and `maxItems`.
|
|
100
|
+
Regular-expression patterns, structured bodies, cookies, nested inputs and
|
|
101
|
+
OpenAPI `style`/`explode` fields are not implemented. This uses a documented
|
|
102
|
+
OpenAPI-like input subset; it is not an OpenAPI document or full JSON Schema
|
|
103
|
+
input vocabulary. String limits are at most 8,192 characters.
|
|
104
|
+
|
|
105
|
+
Integers use `-?(0|[1-9][0-9]*)` and must be safe JavaScript integers. Numbers
|
|
106
|
+
allow the same grammar plus a fractional suffix; no exponent, plus sign, leading
|
|
107
|
+
zeros, whitespace, NaN or infinity. Booleans are exactly `true` or `false`.
|
|
108
|
+
Unknown query keys are ignored unless explicitly passed by a redirect.
|
|
109
|
+
|
|
110
|
+
## Redirects
|
|
111
|
+
|
|
112
|
+
`redirect.url` is an absolute HTTP(S) URL with literal scheme/host and no embedded
|
|
113
|
+
credentials or whitespace/control characters. `{pathInput}` placeholders are
|
|
114
|
+
allowed only in the destination pathname and encoded as single components.
|
|
115
|
+
No environment/secret interpolation. Status defaults to 302; allowed values are
|
|
116
|
+
301, 302, 303, 307 and 308.
|
|
117
|
+
|
|
118
|
+
`redirect.query.map` maps output keys to `{from: path|query|header, name: input}`
|
|
119
|
+
references to declared inputs. Typed/defaulted values are used. Arrays produce
|
|
120
|
+
repeated output keys. Absent optional inputs are omitted.
|
|
121
|
+
`redirect.query.pass` is false or an explicit allowlist; unrestricted `true` is
|
|
122
|
+
not supported. Conflicts between destination keys, maps and passthrough fail.
|
|
123
|
+
Declared passthrough inputs use validated/defaulted values; undeclared allowlisted
|
|
124
|
+
keys preserve repeated values. Headers are forwarded only through explicit maps.
|
|
125
|
+
|
|
126
|
+
## Stored links
|
|
127
|
+
|
|
128
|
+
The entry `urlcode.yaml` must opt in with `dynamicLinks: true` (default false).
|
|
129
|
+
Included files cannot set this project-level flag. Parameterized redirects and
|
|
130
|
+
functions do not require it.
|
|
131
|
+
|
|
132
|
+
`link: {collection: links, code: {from: path, name: code}}` resolves a declared
|
|
133
|
+
path input against an operator-bound store. GET/HEAD only. The logical collection
|
|
134
|
+
is portable; file paths and store credentials are external deployment bindings.
|
|
135
|
+
No general storage capability is exposed to guest code. See [dynamic links](DYNAMIC-LINKS.md)
|
|
136
|
+
for validation, persistence, mutation, expiry and read-after-write behavior.
|
|
137
|
+
|
|
138
|
+
## Functions
|
|
139
|
+
|
|
140
|
+
```yaml
|
|
141
|
+
version: "1"
|
|
142
|
+
routes:
|
|
143
|
+
/hello/{name}:
|
|
144
|
+
parameters:
|
|
145
|
+
- name: name
|
|
146
|
+
in: path
|
|
147
|
+
required: true
|
|
148
|
+
schema: {type: string, minLength: 1}
|
|
149
|
+
function:
|
|
150
|
+
source: functions/hello.mjs
|
|
151
|
+
export: default
|
|
152
|
+
args:
|
|
153
|
+
name: {from: path, name: name}
|
|
154
|
+
env:
|
|
155
|
+
GREETING: {value: Hello}
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
```js
|
|
159
|
+
export default function hello(request, { args, env }) {
|
|
160
|
+
return Response.json({ message: `${env.GREETING}, ${args.name}!` });
|
|
161
|
+
}
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
ES modules only (`.mjs` or `.js`, independent of Node package settings).
|
|
165
|
+
TypeScript is not included. `export` defaults to `default`. Functions execute
|
|
166
|
+
inside QuickJS/WASM, never through Node imports. Only relative `.js`/`.mjs`
|
|
167
|
+
project imports are supported, with a snapshotted dependency graph. No bare/npm,
|
|
168
|
+
Node built-in, remote, dynamic source imports or `import.meta`. Runtime-created
|
|
169
|
+
imports remain restricted to the route's middleware and handler dependency graphs; there is no fallback.
|
|
170
|
+
Source limits: 128 modules, 1 MiB per module, 4 MiB total.
|
|
171
|
+
|
|
172
|
+
The current guest API is a **text/JSON subset**, not the complete native Fetch
|
|
173
|
+
API: Request `url`, `method`, `headers`, `text()`, `json()`; Headers append/set/
|
|
174
|
+
delete/get/has/entries/getSetCookie; Response constructor with string/null body,
|
|
175
|
+
`status`, `headers`, `ok`, `text()`, `json()`, static `json()` and `redirect()`.
|
|
176
|
+
Requests decode body bytes as UTF-8. Binary/streaming bodies, URL helpers,
|
|
177
|
+
fetch/WebSocket, crypto and filesystem are not exposed. Promise/async and
|
|
178
|
+
bounded timers (128 pending per invocation) work inside the guest. Unsupported
|
|
179
|
+
APIs fail; they never execute on the host. Do not claim full browser/Node API parity.
|
|
180
|
+
|
|
181
|
+
Context contains `inputs.path/query/header`, `args`, `env`, `secrets`. Arguments
|
|
182
|
+
may be scalar literals, input references, `{env: alias}` or `{secret: alias}`.
|
|
183
|
+
Bindings use `{value: "literal"}`, `{env: EXTERNAL_NAME}` or `{secret: logical_name}`.
|
|
184
|
+
Literal non-secret values need no grant. Every external environment or secret
|
|
185
|
+
binding is denied unless an operator policy grants that exact name to the route
|
|
186
|
+
and matches the SHA-256 of the current configuration/source snapshot.
|
|
187
|
+
A project cannot grant itself capabilities. See [policy setup](FUNCTION-SECURITY.md).
|
|
188
|
+
Missing bindings also reject activation. Inspection parses source without running it.
|
|
189
|
+
|
|
190
|
+
Development may read `.env.local`; process values win. Serving never reads it.
|
|
191
|
+
Dotenv supports single-line NAME=value, paired single/double quotes, blank lines
|
|
192
|
+
and full-line comments, without expansion/escapes/shell execution. Loading a
|
|
193
|
+
value does not authorize exposing it to a function; the policy still applies.
|
|
194
|
+
|
|
195
|
+
Every invocation has a fresh guest heap and module state. No cross-request
|
|
196
|
+
counters, cached secrets or prototype mutation. QuickJS heap limit is 32 MiB,
|
|
197
|
+
stack limit 512 KiB; outer worker and deployment limits are additional defenses,
|
|
198
|
+
not a claim that total process RSS is capped at 32 MiB. Two workers, no queue;
|
|
199
|
+
saturation returns 503. The independent 5-second deadline terminates a worker
|
|
200
|
+
and returns 504. Generic failures return 502; worker replacement is bounded.
|
|
201
|
+
|
|
202
|
+
HEAD invokes the handler as HEAD and suppresses body output. Code must guard
|
|
203
|
+
its own application side effects when future brokered integrations are enabled.
|
|
204
|
+
Guest console output is discarded. Functions see the configured public origin,
|
|
205
|
+
not arbitrary Host/forwarded headers. Request/response bodies default to 1 MiB;
|
|
206
|
+
response headers 16 KiB, maximum 256 pairs. Hop-by-hop headers are stripped;
|
|
207
|
+
cookies are preserved individually. Default response cache policy is `no-store`.
|
|
208
|
+
|
|
209
|
+
No unrestricted host execution option exists. Network integrations and persistent
|
|
210
|
+
state need future explicit, tested capability brokers. Approved secrets can be
|
|
211
|
+
returned by code that receives them; isolation does not automatically enforce
|
|
212
|
+
information-flow rules on authorized inputs. Keep grants narrow and review the
|
|
213
|
+
exact pinned revision. The sandbox still needs independent security review before hostile multi-tenant use.
|
|
214
|
+
|
|
215
|
+
## Reload and status
|
|
216
|
+
|
|
217
|
+
`dev` polls project YAML/JSON/JS and `.env.local` every 500 ms, plus declared
|
|
218
|
+
asset files/directories (including binary assets and explicit build directories).
|
|
219
|
+
Asset polling uses file metadata; production assets stay fixed until restart.
|
|
220
|
+
The general source scan excludes common
|
|
221
|
+
build/dependency directories and hidden files. Includes and source dependencies
|
|
222
|
+
must be normal watched files; changes in symlink targets or `node_modules`
|
|
223
|
+
require restart. A candidate fully validates and initializes its functions
|
|
224
|
+
and snapshots its assets before activation. Invalid candidates leave the old snapshot serving. In-flight
|
|
225
|
+
function calls finish on their original snapshot; new requests use the new one.
|
|
226
|
+
Production `serve` is a fixed snapshot; restart/redeploy for code, secret or
|
|
227
|
+
operator-policy changes. Config/code edits invalidate old binding grants.
|
|
228
|
+
|
|
229
|
+
The health `version` combines route-definition and asset-representation digests,
|
|
230
|
+
not a full artifact digest
|
|
231
|
+
or secret fingerprint. Production release identity should be the Git commit and
|
|
232
|
+
container image digest. See [operations](OPERATIONS.md).
|