Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 0 additions & 155 deletions ASSETS-TOML.md

This file was deleted.

8 changes: 0 additions & 8 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,5 @@ serde_bytes = "0.11.5"
serde_json = "1.0"
serde_cbor = "0.11.1"
sha2 = "0.11.0"
toml = "0.8"
wit-bindgen = "0.57.1"
tempfile = "3.27.0"
43 changes: 12 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,40 +57,21 @@ The canister also honours a Netlify-style `_headers` file at the root of the pro
X-Robots-Tag: noindex
```

`<pattern>` is an absolute path with optional `*` wildcards — `/about` is exact, `/_astro/*` is a subtree, `/*.md` matches any `.md` file at any depth. A single `*` matches any sequence including `/` and empty; `**` is not supported (redundant) and neither is `:placeholder`. All matching rules apply per the Cloudflare Pages / Netlify semantics — same-name values across rules concatenate with `, ` (RFC 7230), with `Set-Cookie` carved out (RFC 6265). The file is parsed by the plugin and lowered to per-asset header lists; `Content-Type` is reserved (set via `assets.toml`, see below). See [`plugin/README.md`](plugin/README.md#headers) for the full reference and reject list.

## Per-glob content-type overrides

`Content-Type` is intentionally not a `_headers` field — the canister derives it from the asset's media type and certifies it as part of the response. To override what `mime_guess::from_path` picks (or to add a `charset` parameter), declare blocks in an `assets.toml` passed to the plugin via the manifest's `files:` field:

```yaml
# icp.yaml (excerpt)
canisters:
- name: frontend
sync:
steps:
- type: plugin
path: ./plugins/assets-sync.wasm
dirs:
- dist
files:
- assets.toml
```
`<pattern>` is an absolute path with optional `*` wildcards — `/about` is exact, `/_astro/*` is a subtree, `/*.md` matches any `.md` file at any depth. A single `*` matches any sequence including `/` and empty; `**` is not supported (redundant) and neither is `:placeholder`. All matching rules apply per the Cloudflare Pages / Netlify semantics — same-name values across rules concatenate with `, ` (RFC 7230), with `Set-Cookie` carved out (RFC 6265). `Content-Type` is recognised but routed to the asset's stored media type instead of the appended response headers — see below. See [`plugin/README.md`](plugin/README.md#headers) for the full reference and reject list.

### `Content-Type` overrides

```toml
# assets.toml
The canister derives a `Content-Type` for every asset from its media type and certifies it as part of the response. To override what `mime_guess::from_path` picks (or to add a `charset` parameter), set `Content-Type:` inside any `_headers` block:

[[asset]]
match = "/*.md"
content_type = "text/markdown; charset=utf-8"
```text
/*.md
Content-Type: text/markdown; charset=utf-8

[[asset]]
match = "/*.did"
content_type = "text/plain; charset=utf-8"
/*.did
Content-Type: text/plain; charset=utf-8

[[asset]]
match = "/llms.txt"
content_type = "text/plain; charset=utf-8"
/llms.txt
Content-Type: text/plain; charset=utf-8
```

`match` uses the same glob dialect as `_headers`. Blocks are walked in declaration order; the first matching `content_type` wins, with `mime_guess` as the fallback. The override feeds `CreateAssetArguments.content_type`, so the canister emits exactly one `Content-Type` per responseno duplicates from layering with response headers. See [`ASSETS-TOML.md`](ASSETS-TOML.md) for the full design and validation rules.
The plugin extracts `Content-Type` and feeds it into `CreateAssetArguments.content_type` rather than appending it as a response header — so the canister emits exactly one `Content-Type` per response, no duplicates. Other headers in the same block continue to flow through `headers` as usual. `Content-Type` is single-valued, so when multiple blocks match the same asset the first matching `Content-Type` wins (other matching rules still contribute their non-`Content-Type` headers as normal).
1 change: 0 additions & 1 deletion assets-sync/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ mime_guess.workspace = true
serde.workspace = true
serde_bytes.workspace = true
sha2.workspace = true
toml.workspace = true
url = "2"

[dev-dependencies]
Expand Down
Loading
Loading