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
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,16 @@ for how the document, manifest, and per-plugin versions relate.

## [Unreleased]

### Fixed
- **Route-prefix examples now match the Host.** Every illustrative route prefix said
`/api/plugin/<id>/…` (singular) in §7.3, twice in `best-practices.md`, and throughout
`examples/full-plugin` (`routes.py`, `screen.js`, `settings.html`), while the feedBack Host
serves plugin routes under **`/api/plugins/…`** (plural) — and the rest of
`best-practices.md` already used the plural form. All examples and prose now use
`/api/plugins/<id>/…`. The normative rule (§7.4: derive every route path from the plugin
`id`) is unchanged — the singular form only ever appeared in examples, never as a
requirement. Closes [#20](https://github.com/got-feedBack/feedBack-plugin-spec/issues/20).

### Added
- **Module `script` entries.** §3 (Anatomy), §4.1/§4.3, new §6.8 (Splitting client code), and
`schemas/plugin.schema.json` document the optional **`scriptType`** manifest key: `"module"` loads
Expand Down
4 changes: 2 additions & 2 deletions examples/full-plugin/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@ def _read() -> dict:
return dict(_DEFAULTS)

# Everything below only runs after the plugin has validated its own state.
@app.get(f"/api/plugin/{PLUGIN_ID}/settings")
@app.get(f"/api/plugins/{PLUGIN_ID}/settings")
def get_settings() -> JSONResponse:
return JSONResponse(_read())

@app.post(f"/api/plugin/{PLUGIN_ID}/settings")
@app.post(f"/api/plugins/{PLUGIN_ID}/settings")
async def set_settings(request: Request) -> JSONResponse:
incoming = await request.json()
if not isinstance(incoming, dict):
Expand Down
4 changes: 2 additions & 2 deletions examples/full-plugin/screen.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// The exact runtime API the Host exposes to a plugin screen is Host-provided and
// out of scope for spec v0.1.0 (see spec §6.1). This file shows the *shape* of a
// screen module: it renders into its own root element and talks only to its own
// namespaced routes (/api/plugin/full-plugin/...). Keep all DOM and CSS scoped to
// namespaced routes (/api/plugins/full-plugin/...). Keep all DOM and CSS scoped to
// the plugin's root so nothing leaks into the rest of the app.

const PLUGIN_ID = "full-plugin";
Expand All @@ -17,7 +17,7 @@ export async function mount(root) {
`;

try {
const res = await fetch(`/api/plugin/${PLUGIN_ID}/settings`);
const res = await fetch(`/api/plugins/${PLUGIN_ID}/settings`);
const settings = await res.json();
root.querySelector('[data-role="color"]').textContent = settings.color;
} catch (err) {
Expand Down
2 changes: 1 addition & 1 deletion examples/full-plugin/settings.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Settings panel for the full-plugin example. The Host renders this markup in the
plugin's settings slot, grouped under settings.category ("graphics"). Scope any
styles/scripts to the panel; persist values through the plugin's own routes
(/api/plugin/full-plugin/settings), not by writing files directly from the client.
(/api/plugins/full-plugin/settings), not by writing files directly from the client.
-->
<div class="full-plugin-settings">
<label>
Expand Down
4 changes: 2 additions & 2 deletions spec/best-practices.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ disabled), so a collision there is especially sticky.

**Namespace what the `id` doesn't namespace for you.** Because every plugin shares one `window` and
one document, prefix anything you put in a shared space with your `id`: `localStorage` keys, any
`window` globals you must expose, your routes (`/api/plugin/<id>/…`, rule 7), and your CSS (rule 10).
`window` globals you must expose, your routes (`/api/plugins/<id>/…`, rule 7), and your CSS (rule 10).
Two plugins writing `window.state` or `localStorage["theme"]` clobber each other silently.

### 3. Keep the manifest declarative
Expand Down Expand Up @@ -107,7 +107,7 @@ mounts two routes and then throws leaves two half-working endpoints behind perma

### 7. Namespace everything under your `id`

- Routes: `"/api/plugin/my-plugin/state"`, not `"/state"`.
- Routes: `"/api/plugins/my-plugin/state"`, not `"/state"`.
- CSS: scope selectors to your screen's root element, don't style bare `body`/`h1`.
- Persisted files: write under the `config_dir` the Host hands you, in a file named for your
plugin (`config_dir / "my_plugin.json"`).
Expand Down
2 changes: 1 addition & 1 deletion spec/plugin-spec-v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ Because partially-registered routes cannot always be removed (see [§5.4](#54-pa
a `setup` SHOULD:

- validate its configuration and inputs *before* registering any route;
- namespace its routes under a path derived from the plugin `id` (e.g. `/api/plugin/<id>/...`) to
- namespace its routes under a path derived from the plugin `id` (e.g. `/api/plugins/<id>/...`) to
avoid colliding with the Host or other plugins;
- never raise after the first route is registered, if it can be avoided.

Expand Down
Loading