@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
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
version: "1"
|
|
2
|
+
routes:
|
|
3
|
+
/go:
|
|
4
|
+
redirect:
|
|
5
|
+
url: https://example.com/target
|
|
6
|
+
/u/{id}:
|
|
7
|
+
parameters:
|
|
8
|
+
- {name: id, in: path, required: true, schema: {type: string}}
|
|
9
|
+
redirect:
|
|
10
|
+
url: https://example.com/users/{id}
|
|
11
|
+
/health:
|
|
12
|
+
respond:
|
|
13
|
+
json: {ok: true}
|
|
14
|
+
/:
|
|
15
|
+
page:
|
|
16
|
+
file: public/index.html
|
|
17
|
+
/files/*:
|
|
18
|
+
static:
|
|
19
|
+
directory: public
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# URLCode on Cloudflare Workers
|
|
2
|
+
|
|
3
|
+
A declarative project compiled to a Worker. See
|
|
4
|
+
[the target guide](../../docs/CLOUDFLARE.md) for what is and is not supported.
|
|
5
|
+
|
|
6
|
+
```sh
|
|
7
|
+
urlcode test --project . # the same assertions run against the local runtime
|
|
8
|
+
npm run build # writes dist/{index,artifact,validators}.js
|
|
9
|
+
npx wrangler deploy
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The build is the deploy unit: `dist/` is generated, never edited, and never
|
|
13
|
+
committed. Rebuild after every change to `urlcode.yaml` — the Worker reads the
|
|
14
|
+
artifact, not the YAML.
|
|
15
|
+
|
|
16
|
+
`wrangler.toml` sets no `nodejs_compat` flag on purpose. The runtime and the
|
|
17
|
+
precompiled schema validators use Web standards only, so nothing here needs a
|
|
18
|
+
Node compatibility layer.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "urlcode-cloudflare-example",
|
|
3
|
+
"private": true,
|
|
4
|
+
"type": "module",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"build": "urlcode build --target cloudflare --project . --out dist"
|
|
7
|
+
},
|
|
8
|
+
"dependencies": {
|
|
9
|
+
"@jimhoyd/urlcode": "^0.3.0"
|
|
10
|
+
},
|
|
11
|
+
"devDependencies": {
|
|
12
|
+
"wrangler": "^4"
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
[
|
|
2
|
+
{"path": "/go", "status": 302, "expectHeaders": {"location": "https://example.com/target"}},
|
|
3
|
+
{"path": "/u/42", "status": 302, "expectHeaders": {"location": "https://example.com/users/42"}},
|
|
4
|
+
{"path": "/search?q=links", "status": 302, "expectHeaders": {"location": "https://example.com/search?q=links"}},
|
|
5
|
+
{"path": "/search", "status": 302, "expectHeaders": {"location": "https://example.com/search?q=urlcode"}},
|
|
6
|
+
{"path": "/health", "status": 200, "expectBody": "{\"ok\":true}"},
|
|
7
|
+
{"path": "/nothing-here", "status": 404},
|
|
8
|
+
{"path": "/go", "method": "HEAD", "status": 302, "expectHeaders": {"location": "https://example.com/target"}, "expectBody": ""}
|
|
9
|
+
]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
version: "1"
|
|
2
|
+
routes:
|
|
3
|
+
/go:
|
|
4
|
+
redirect:
|
|
5
|
+
url: https://example.com/target
|
|
6
|
+
/u/{id}:
|
|
7
|
+
parameters:
|
|
8
|
+
- {name: id, in: path, required: true, schema: {type: string}}
|
|
9
|
+
redirect:
|
|
10
|
+
url: https://example.com/users/{id}
|
|
11
|
+
/search:
|
|
12
|
+
parameters:
|
|
13
|
+
- {name: q, in: query, required: false, schema: {type: string, maxLength: 64, default: urlcode}}
|
|
14
|
+
redirect:
|
|
15
|
+
url: https://example.com/search
|
|
16
|
+
query:
|
|
17
|
+
map:
|
|
18
|
+
q: {from: query, name: q}
|
|
19
|
+
/health:
|
|
20
|
+
respond:
|
|
21
|
+
json: {ok: true}
|
|
22
|
+
response:
|
|
23
|
+
headers:
|
|
24
|
+
cache-control: no-store
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Custom compliance rules
|
|
2
|
+
|
|
3
|
+
`rules.mjs` is an operator rules module for `urlcode audit --compliance-rules`.
|
|
4
|
+
It adds three rules (an approved redirect host list, a description on every
|
|
5
|
+
route, a reminder to declare the origin), disables the built-in expired-routes
|
|
6
|
+
notice and raises the security-headers rule to `high`. See
|
|
7
|
+
[docs/COMPLIANCE.md](../../docs/COMPLIANCE.md) for the contract.
|
|
8
|
+
|
|
9
|
+
Run it against the cookbook from the runtime checkout. The module must be an
|
|
10
|
+
absolute path outside the audited project:
|
|
11
|
+
|
|
12
|
+
```sh
|
|
13
|
+
node src/cli.ts audit --project examples/cookbook \
|
|
14
|
+
--compliance baseline --compliance-rules "$PWD/examples/compliance/rules.mjs" --compliance-warn
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
Without `--compliance-warn` the run exits 1: the override makes the cookbook's
|
|
18
|
+
routes without `policies.security` high findings. The report's `compliance`
|
|
19
|
+
section lists every finding with its rule, severity, route, message,
|
|
20
|
+
remediation and the standard it cites.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
// Operator compliance rules for `urlcode audit --compliance-rules`.
|
|
2
|
+
// Runnable against the cookbook from the runtime checkout:
|
|
3
|
+
//
|
|
4
|
+
// node src/cli.js audit --project examples/cookbook \
|
|
5
|
+
// --compliance baseline --compliance-rules "$PWD/examples/compliance/rules.mjs" --compliance-warn
|
|
6
|
+
//
|
|
7
|
+
// The file must sit outside the audited project (it is trusted host code, the
|
|
8
|
+
// same rule as --policy). It exports `rules` to add, `disable` to drop
|
|
9
|
+
// built-in rules by id, and `override` to change fields of an existing rule.
|
|
10
|
+
// Every check reads only the context runCompliance hands it: the parsed YAML
|
|
11
|
+
// (`document`, `routes`), the runtime's test plan (`plan`), the effective
|
|
12
|
+
// policies per route (`policies`, `effective`), the declared `origin` and the
|
|
13
|
+
// declared `host` settings.
|
|
14
|
+
|
|
15
|
+
// Which redirect hosts this operator considers their own.
|
|
16
|
+
const allowedHosts = ['example.com', 'www.example.com'];
|
|
17
|
+
|
|
18
|
+
export const rules = [
|
|
19
|
+
{
|
|
20
|
+
id: 'acme/redirect-hosts',
|
|
21
|
+
title: 'Redirects only leave for approved hosts',
|
|
22
|
+
standard: { name: 'ACME link policy', reference: 'https://example.com/policies/links', section: 'Outbound redirects' },
|
|
23
|
+
severity: 'high',
|
|
24
|
+
appliesTo: 'route',
|
|
25
|
+
check({ route, config }) {
|
|
26
|
+
const url = config.redirect?.url;
|
|
27
|
+
if (route.state !== 'active' || typeof url !== 'string') return [];
|
|
28
|
+
// Templates such as https://host/{id} still start with a fixed host.
|
|
29
|
+
let host;
|
|
30
|
+
try { host = new URL(url.replace(/\{[^}]*\}/g, 'x')).hostname; } catch { return [{ message: `${route.path} redirect target could not be parsed`, remediation: 'Use an absolute https URL' }]; }
|
|
31
|
+
if (allowedHosts.includes(host)) return [];
|
|
32
|
+
return [{ message: `${route.path} redirects to ${host}, which is not an approved host`, remediation: `Redirect only to ${allowedHosts.join(', ')} or extend the allow list in rules.mjs` }];
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
id: 'acme/described-routes',
|
|
37
|
+
title: 'Every active route carries a description',
|
|
38
|
+
standard: { name: 'ACME YAML conventions', reference: 'https://example.com/policies/yaml' },
|
|
39
|
+
severity: 'low',
|
|
40
|
+
appliesTo: 'route',
|
|
41
|
+
check({ route, config }) {
|
|
42
|
+
if (route.state !== 'active' || typeof config.description === 'string') return [];
|
|
43
|
+
return [{ message: `${route.path} has no description`, remediation: 'Add a one-line description so audits and reviews can name the route by purpose' }];
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'acme/declared-origin',
|
|
48
|
+
title: 'The audit declares the public origin',
|
|
49
|
+
standard: { name: 'ACME deployment checklist', reference: 'https://example.com/policies/deploy' },
|
|
50
|
+
severity: 'info',
|
|
51
|
+
appliesTo: 'project',
|
|
52
|
+
check({ origin }) {
|
|
53
|
+
if (origin) return [];
|
|
54
|
+
return [{ message: 'No --origin was declared, so origin-dependent rules cannot confirm https', remediation: 'Pass --origin https://your.host to audit' }];
|
|
55
|
+
},
|
|
56
|
+
},
|
|
57
|
+
];
|
|
58
|
+
|
|
59
|
+
// The cookbook keeps an expired route on purpose to show a 410.
|
|
60
|
+
export const disable = ['rfc9110/expired-routes'];
|
|
61
|
+
|
|
62
|
+
// This operator treats a missing security profile as blocking.
|
|
63
|
+
export const override = {
|
|
64
|
+
'oshp/security-headers': { severity: 'high' },
|
|
65
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# Runnable YAML cookbook
|
|
2
|
+
|
|
3
|
+
25 routes covering all six handlers, middleware, inputs, body validation, response
|
|
4
|
+
headers, cookies, methods, expiry, assets, included files and host policies
|
|
5
|
+
(security headers, agent denial, caching and a request budget) plus generated site
|
|
6
|
+
conventions (robots.txt, favicon, security.txt, llms.txt). No credentials or
|
|
7
|
+
external services are required. Redirects target example.com; tests never follow them.
|
|
8
|
+
|
|
9
|
+
From the runtime checkout:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
node src/cli.ts validate --project examples/cookbook
|
|
13
|
+
node src/cli.ts test --project examples/cookbook
|
|
14
|
+
node src/cli.ts audit --project examples/cookbook --expect-routes 25
|
|
15
|
+
node src/cli.ts dev --project examples/cookbook
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
The [YAML guide](../../docs/YAML-GUIDE.md) explains the recipes and binding policy.
|
|
19
|
+
`/notice` deliberately returns 503, `/paused` 404 and `/expired` 410. `/preflight`
|
|
20
|
+
is an OPTIONS/header example, not a complete cross-origin API. The small default
|
|
21
|
+
starter remains the recommended starting point for a new application.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!doctype html><title>About URLCode</title>About
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<!doctype html><title>Assets</title>Assets
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
body { color: navy; }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><rect width="16" height="16" rx="3" fill="#1d4ed8"/><text x="8" y="12" font-size="10" text-anchor="middle" fill="#fff" font-family="sans-serif">U</text></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
URLCode guide
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
version: "1"
|
|
2
|
+
routes:
|
|
3
|
+
/hello/{name}:
|
|
4
|
+
description: Validated input, named export, arguments, literal environment and middleware
|
|
5
|
+
parameters:
|
|
6
|
+
- name: name
|
|
7
|
+
in: path
|
|
8
|
+
required: true
|
|
9
|
+
schema: {type: string, minLength: 1, maxLength: 80}
|
|
10
|
+
- name: excited
|
|
11
|
+
in: query
|
|
12
|
+
schema: {type: boolean, default: false}
|
|
13
|
+
env:
|
|
14
|
+
GREETING: {value: Hello}
|
|
15
|
+
middleware:
|
|
16
|
+
- source: middleware/headers.mjs
|
|
17
|
+
export: decorate
|
|
18
|
+
function:
|
|
19
|
+
source: functions/hello.mjs
|
|
20
|
+
export: hello
|
|
21
|
+
args:
|
|
22
|
+
name: {from: path, name: name}
|
|
23
|
+
excited: {from: query, name: excited}
|
|
24
|
+
greeting: {env: GREETING}
|
|
25
|
+
punctuation: "!"
|
|
26
|
+
response:
|
|
27
|
+
headers:
|
|
28
|
+
X-App: cookbook
|
|
29
|
+
/echo:
|
|
30
|
+
methods: [POST]
|
|
31
|
+
request:
|
|
32
|
+
body:
|
|
33
|
+
required: true
|
|
34
|
+
maxBytes: 4096
|
|
35
|
+
contentTypes: [application/json]
|
|
36
|
+
format: json
|
|
37
|
+
function: {source: functions/echo.mjs}
|
|
38
|
+
/text:
|
|
39
|
+
methods: [POST]
|
|
40
|
+
request:
|
|
41
|
+
body:
|
|
42
|
+
required: true
|
|
43
|
+
maxBytes: 1024
|
|
44
|
+
contentTypes: [text/plain]
|
|
45
|
+
format: text
|
|
46
|
+
function: {source: functions/text.mjs}
|
|
47
|
+
/choice:
|
|
48
|
+
parameters:
|
|
49
|
+
- name: destination
|
|
50
|
+
in: query
|
|
51
|
+
schema: {type: string, enum: [docs, home], default: docs}
|
|
52
|
+
function:
|
|
53
|
+
source: functions/choice.mjs
|
|
54
|
+
args:
|
|
55
|
+
destination: {from: query, name: destination}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
version: "1"
|
|
2
|
+
routes:
|
|
3
|
+
/about:
|
|
4
|
+
page:
|
|
5
|
+
file: public/about.html
|
|
6
|
+
cacheControl: no-cache
|
|
7
|
+
/assets/*:
|
|
8
|
+
static:
|
|
9
|
+
directory: public/assets
|
|
10
|
+
index: index.html
|
|
11
|
+
cacheControl: public, max-age=3600
|
|
12
|
+
/download:
|
|
13
|
+
download:
|
|
14
|
+
file: public/guide.txt
|
|
15
|
+
filename: urlcode-guide.txt
|
|
16
|
+
contentType: text/plain
|
|
17
|
+
cacheControl: no-store
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
version: "1"
|
|
2
|
+
routes:
|
|
3
|
+
/secure:
|
|
4
|
+
description: OWASP Secure Headers profile on a declared response; explicit headers still win
|
|
5
|
+
respond: {text: Hardened response}
|
|
6
|
+
policies:
|
|
7
|
+
security: {headers: oshp, unset: [Cross-Origin-Embedder-Policy]}
|
|
8
|
+
response:
|
|
9
|
+
headers:
|
|
10
|
+
Referrer-Policy: no-referrer
|
|
11
|
+
/no-bots:
|
|
12
|
+
description: Deny the bundled AI-crawler list and any curl; allow one named crawler
|
|
13
|
+
redirect: {url: https://example.com/article}
|
|
14
|
+
policies:
|
|
15
|
+
agents:
|
|
16
|
+
deny: [ai-crawlers]
|
|
17
|
+
denyPatterns: ["^curl/"]
|
|
18
|
+
allowPatterns: ["^Mozilla/5\\.0 \\(compatible; Googlebot/"]
|
|
19
|
+
/cached:
|
|
20
|
+
description: Public caching with a named strategy; the origin does not cache
|
|
21
|
+
respond: {json: {cached: true}}
|
|
22
|
+
policies:
|
|
23
|
+
cache: {strategy: public, maxAge: 60}
|
|
24
|
+
/budget:
|
|
25
|
+
description: Per-route request budget with standard RateLimit headers
|
|
26
|
+
respond: {text: Budgeted}
|
|
27
|
+
policies:
|
|
28
|
+
throttle: {quota: 100, window: 60, partition: route}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
version: "1"
|
|
2
|
+
routes:
|
|
3
|
+
/go:
|
|
4
|
+
redirect: {url: 'https://example.com/'}
|
|
5
|
+
/moved:
|
|
6
|
+
redirect: {url: 'https://example.com/new', status: 308}
|
|
7
|
+
response:
|
|
8
|
+
headers:
|
|
9
|
+
Cache-Control: public, max-age=60
|
|
10
|
+
/product/{id}:
|
|
11
|
+
parameters:
|
|
12
|
+
- name: id
|
|
13
|
+
in: path
|
|
14
|
+
required: true
|
|
15
|
+
schema: {type: string, minLength: 1, maxLength: 64}
|
|
16
|
+
- name: page
|
|
17
|
+
in: query
|
|
18
|
+
schema: {type: integer, minimum: 1, maximum: 100, default: 1}
|
|
19
|
+
- name: tag
|
|
20
|
+
in: query
|
|
21
|
+
schema: {type: array, items: {type: string}, maxItems: 3}
|
|
22
|
+
- name: x-channel
|
|
23
|
+
in: header
|
|
24
|
+
schema: {type: string, enum: [web, email], default: web}
|
|
25
|
+
redirect:
|
|
26
|
+
url: https://example.com/products/{id}
|
|
27
|
+
query:
|
|
28
|
+
map:
|
|
29
|
+
page: {from: query, name: page}
|
|
30
|
+
label: {from: query, name: tag}
|
|
31
|
+
channel: {from: header, name: x-channel}
|
|
32
|
+
pass: [utm_source]
|
|
33
|
+
/paused:
|
|
34
|
+
enabled: false
|
|
35
|
+
redirect: {url: 'https://example.com/'}
|
|
36
|
+
/expired:
|
|
37
|
+
expires: "2020-01-01T00:00:00Z"
|
|
38
|
+
redirect: {url: 'https://example.com/'}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
version: "1"
|
|
2
|
+
routes:
|
|
3
|
+
/status:
|
|
4
|
+
respond: {json: {ok: true, service: cookbook}}
|
|
5
|
+
/notice:
|
|
6
|
+
respond: {text: Temporarily unavailable, status: 503}
|
|
7
|
+
response:
|
|
8
|
+
headers:
|
|
9
|
+
Retry-After: "60"
|
|
10
|
+
/empty:
|
|
11
|
+
respond: {status: 204}
|
|
12
|
+
/cookie-demo:
|
|
13
|
+
respond: {text: Non-secret preferences only}
|
|
14
|
+
response:
|
|
15
|
+
headers:
|
|
16
|
+
Set-Cookie:
|
|
17
|
+
- "theme=light; Path=/; Secure; SameSite=Lax"
|
|
18
|
+
- "notice=seen; Path=/; HttpOnly; Secure; SameSite=Lax"
|
|
19
|
+
/preflight:
|
|
20
|
+
methods: [OPTIONS]
|
|
21
|
+
respond: {status: 204}
|
|
22
|
+
response:
|
|
23
|
+
headers:
|
|
24
|
+
Access-Control-Allow-Origin: https://app.example.com
|
|
25
|
+
Access-Control-Allow-Methods: GET, HEAD
|
|
26
|
+
Access-Control-Allow-Headers: Content-Type
|