Serve every /public/ asset under a content-versioned URL with an immutable Cache-Control #193
@@ -246,7 +246,8 @@ Revisit only if the stated reason stops holding.
|
|||||||
- **`locale` is a host-owned query param** — in `parseListQuery`'s reserved set, so a localized list
|
- **`locale` is a host-owned query param** — in `parseListQuery`'s reserved set, so a localized list
|
||||||
page doesn't hand a plugin a phantom `locale` filter. The i18n view locals (`t`, `locale`, `locales`,
|
page doesn't hand a plugin a phantom `locale` filter. The i18n view locals (`t`, `locale`, `locales`,
|
||||||
`localeHref`, `localeParam`, `localeSwitch`, `dir`) are likewise reserved, merged after a handler's
|
`localeHref`, `localeParam`, `localeSwitch`, `dir`) are likewise reserved, merged after a handler's
|
||||||
`data` so a collision loses the key instead of breaking the shell.
|
`data` so a collision loses the key instead of breaking the shell — as is `assetHref`
|
||||||
|
(`src/http/static.ts`), which stays undocumented for plugins because calling it is not yet contract.
|
||||||
- **Catalogs are checked at boot, not at render.** Every locale is compared against its set's `en-US`
|
- **Catalogs are checked at boot, not at render.** Every locale is compared against its set's `en-US`
|
||||||
— keys, string-vs-plural kind, and the plural categories `Intl.PluralRules` requires — and a
|
— keys, string-vs-plural kind, and the plural categories `Intl.PluralRules` requires — and a
|
||||||
mismatch stops startup. A plugin may ship fewer locales than the host (its strings fall back to
|
mismatch stops startup. A plugin may ship fewer locales than the host (its strings fall back to
|
||||||
|
|||||||
@@ -511,8 +511,8 @@ export async function listThings(ctx: RequestContext) {
|
|||||||
`include()` the core building-block partials and its own. To load the plugin's own CSS, pass its
|
`include()` the core building-block partials and its own. To load the plugin's own CSS, pass its
|
||||||
`/public/<id>/x.css` href in the shell's `styles` slot — see the reference's `views/shifts.ejs`.
|
`/public/<id>/x.css` href in the shell's `styles` slot — see the reference's `views/shifts.ejs`.
|
||||||
The host adds the file's content hash to every `/public/` href the shell renders, so browsers and
|
The host adds the file's content hash to every `/public/` href the shell renders, so browsers and
|
||||||
any cache in front of Plainpages keep it for a year; a `/public/` URL your own markup writes is
|
any cache in front of Plainpages keep the file for a year; a `/public/` URL your own markup writes
|
||||||
kept for five minutes, then revalidated.
|
is kept for five minutes, then revalidated.
|
||||||
- **Finer authorization than the route `permission`** uses the guards from `@plainpages/plugin-api`:
|
- **Finer authorization than the route `permission`** uses the guards from `@plainpages/plugin-api`:
|
||||||
`requireSession(ctx)`, `can(ctx, permission)` (coarse JWT-claim check, zero I/O), and
|
`requireSession(ctx)`, `can(ctx, permission)` (coarse JWT-claim check, zero I/O), and
|
||||||
`check(keto, ctx, {namespace, object, relation})` (a live Keto check; anonymous ⇒ denied). Throw
|
`check(keto, ctx, {namespace, object, relation})` (a live Keto check; anonymous ⇒ denied). Throw
|
||||||
@@ -1175,7 +1175,7 @@ Rules worth knowing:
|
|||||||
edit/new/remove/save`, `filter.*`, `pagination.*`, `table.*` — and a plugin's lookup falls through
|
edit/new/remove/save`, `filter.*`, `pagination.*`, `table.*` — and a plugin's lookup falls through
|
||||||
to them. Keep your catalog for your domain words.
|
to them. Keep your catalog for your domain words.
|
||||||
- **Reserved view locals:** `t`, `locale`, `locales`, `localeHref`, `localeParam`, `localeSwitch`,
|
- **Reserved view locals:** `t`, `locale`, `locales`, `localeHref`, `localeParam`, `localeSwitch`,
|
||||||
`dir`. They are merged after your `data`, so a colliding key of yours is ignored rather than
|
`dir`, and the host-internal `assetHref`. They are merged after your `data`, so a colliding key of yours is ignored rather than
|
||||||
breaking the shell. `locale` is likewise reserved in `parseListQuery`, never returned as a filter.
|
breaking the shell. `locale` is likewise reserved in `parseListQuery`, never returned as a filter.
|
||||||
|
|
||||||
**Kratos writes the auth flow's own text** (field labels, validation errors), tagging each string
|
**Kratos writes the auth flow's own text** (field labels, validation errors), tagging each string
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
`Bar = 1`
|
`Bar = 1`
|
||||||
|
|
||||||
`Next ID = 43`
|
`Next ID = 44`
|
||||||
|
|
||||||
## Items
|
## Items
|
||||||
|
|
||||||
@@ -22,6 +22,7 @@
|
|||||||
| 16 | 0.5.0 | | question | **Decide whether the single Keto `Resource` namespace splits into per-domain namespaces.** | 3 | 2 | 3 | 6 | 6 | 7 by 2 | 0.5 |
|
| 16 | 0.5.0 | | question | **Decide whether the single Keto `Resource` namespace splits into per-domain namespaces.** | 3 | 2 | 3 | 6 | 6 | 7 by 2 | 0.5 |
|
||||||
| 6 | 0.5.0 | | | **Warn at discovery when a route or nav node gates on a permission no plugin declares.** | 2 | 1 | 1 | 2 | 2 | 7 by 3, 9 by 3 | 8.0 |
|
| 6 | 0.5.0 | | | **Warn at discovery when a route or nav node gates on a permission no plugin declares.** | 2 | 1 | 1 | 2 | 2 | 7 by 3, 9 by 3 | 8.0 |
|
||||||
| 23 | 0.5.0 | | | **Give list pages one view-model helper from query to pagination, instead of ~40 hand-written lines each.** | 3 | 1 | 2 | 4 | 5 | 1 by 4, 9 by 2, code health by 3 | 7.9 |
|
| 23 | 0.5.0 | | | **Give list pages one view-model helper from query to pagination, instead of ~40 hand-written lines each.** | 3 | 1 | 2 | 4 | 5 | 1 by 4, 9 by 2, code health by 3 | 7.9 |
|
||||||
|
| 43 | 0.5.0 | | | **Let a plugin version the scripts and other `/public/` files its own markup links, so they are cached as immutable too.** | 2 | 2 | 1 | 3 | 3 | 8 by 3, 7 by 2 | 5.0 |
|
||||||
| 28 | 0.5.0 | | | **Let a plugin add entries to the profile menu through the plugin API.** | 2 | 2 | 2 | 4 | 4 | 7 by 4, 1 by 2 | 4.2 |
|
| 28 | 0.5.0 | | | **Let a plugin add entries to the profile menu through the plugin API.** | 2 | 2 | 2 | 4 | 4 | 7 by 4, 1 by 2 | 4.2 |
|
||||||
| 2 | 0.5.0 | | | **Rename the admin example plugin to a name that says what it administers.** | 3 | 1 | 2 | 4 | 6 | 9 by 3, code health by 2 | 2.6 |
|
| 2 | 0.5.0 | | | **Rename the admin example plugin to a name that says what it administers.** | 3 | 1 | 2 | 4 | 6 | 9 by 3, code health by 2 | 2.6 |
|
||||||
| 5 | 0.5.0 | | | **List grants that no installed plugin declares, with a remove action.** | 2 | 2 | 2 | 4 | 4 | 2 by 3 | 2.1 |
|
| 5 | 0.5.0 | | | **List grants that no installed plugin declares, with a remove action.** | 2 | 2 | 2 | 4 | 4 | 2 by 3 | 2.1 |
|
||||||
@@ -104,6 +105,15 @@ is ungrantable from the GUI and answers a permanent 403. A warning, not an error
|
|||||||
Every list screen bridges `parseListQuery`/`paginate` to the partials by hand. At minimum a
|
Every list screen bridges `parseListQuery`/`paginate` to the partials by hand. At minimum a
|
||||||
`buildPaginationModel(page, hrefFor)`. Exported through the barrel, so it is contract surface.
|
`buildPaginationModel(page, hrefFor)`. Exported through the barrel, so it is contract surface.
|
||||||
|
|
||||||
|
### 43. Let a plugin version the scripts and other `/public/` files its own markup links, so they are cached as immutable too.
|
||||||
|
|
||||||
|
The host versions every `/public/` href it renders (`src/http/static.ts`): the shell's stylesheets,
|
||||||
|
favicon and logo, and a plugin's `styles`. A file a plugin's own markup links, such as fastjira's
|
||||||
|
`board-drag.js`, keeps an unversioned URL and is revalidated every five minutes. Offering a way —
|
||||||
|
`assetHref` documented as a view local, a `ctx.assetHref`, or a `scripts` slot in the shell — adds to
|
||||||
|
the plugin API, hence a minor. Pick one with the plugin authors' panel, then document it in README →
|
||||||
|
Reserved view locals.
|
||||||
|
|
||||||
### 28. Let a plugin add entries to the profile menu through the plugin API.
|
### 28. Let a plugin add entries to the profile menu through the plugin API.
|
||||||
|
|
||||||
The profile dropdown stays a dropdown: Sign out is its only entry today, and it will gain more.
|
The profile dropdown stays a dropdown: Sign out is its only entry today, and it will gain more.
|
||||||
|
|||||||
Reference in New Issue
Block a user