Keep the release at v0.1.0 — nothing consumed the old contract
This commit is contained in:
@@ -47,7 +47,7 @@ folder under `plugins/` goes live after a restart. Create `plugins/hello/plugin.
|
|||||||
import { definePlugin } from "@plainpages/plugin-api";
|
import { definePlugin } from "@plainpages/plugin-api";
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
apiVersion: "0.2.0",
|
apiVersion: "0.1.0",
|
||||||
nav: [{ href: "/hello", id: "hello", label: "Hello", public: true }],
|
nav: [{ href: "/hello", id: "hello", label: "Hello", public: true }],
|
||||||
routes: [
|
routes: [
|
||||||
{ method: "GET", path: "/", public: true, handler: () => ({ html: "<h1>Hello from my plugin</h1>" }) },
|
{ method: "GET", path: "/", public: true, handler: () => ({ html: "<h1>Hello from my plugin</h1>" }) },
|
||||||
@@ -348,7 +348,7 @@ import { definePlugin } from "@plainpages/plugin-api";
|
|||||||
import { listThings, createThings } from "./handlers.ts";
|
import { listThings, createThings } from "./handlers.ts";
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
apiVersion: "0.2.0", // semver string of the host contract this plugin was built against (see Versioning)
|
apiVersion: "0.1.0", // semver string of the host contract this plugin was built against (see Versioning)
|
||||||
|
|
||||||
// Nav fragment, merged into the global menu and permission-filtered per user.
|
// Nav fragment, merged into the global menu and permission-filtered per user.
|
||||||
// `icon` is a Lucide icon by its sprite id (src/ui/icons.ts).
|
// `icon` is a Lucide icon by its sprite id (src/ui/icons.ts).
|
||||||
@@ -468,7 +468,7 @@ import { definePlugin } from "@plainpages/plugin-api";
|
|||||||
import { landing, board } from "./pages.ts";
|
import { landing, board } from "./pages.ts";
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
apiVersion: "0.2.0",
|
apiVersion: "0.1.0",
|
||||||
home: landing, // owns "/" — the public front page
|
home: landing, // owns "/" — the public front page
|
||||||
dashboard: board, // owns "/dashboard" — the post-login app home
|
dashboard: board, // owns "/dashboard" — the post-login app home
|
||||||
});
|
});
|
||||||
@@ -751,7 +751,7 @@ import { definePlugin } from "@plainpages/plugin-api";
|
|||||||
let sql: ReturnType<typeof postgres>;
|
let sql: ReturnType<typeof postgres>;
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
apiVersion: "0.2.0",
|
apiVersion: "0.1.0",
|
||||||
storage: true,
|
storage: true,
|
||||||
hooks: {
|
hooks: {
|
||||||
onBoot: async (boot) => {
|
onBoot: async (boot) => {
|
||||||
@@ -1513,21 +1513,6 @@ box. The web app waits for Kratos + Keto healthy *and* the bootstrap to finish b
|
|||||||
|
|
||||||
## Upgrading
|
## Upgrading
|
||||||
|
|
||||||
### 0.1.x → 0.2.0: `apiVersion` now names the Plainpages release
|
|
||||||
|
|
||||||
`0.1.0` shipped a host reporting contract version `1.0.0` — a second number that tracked the plugin
|
|
||||||
contract separately from the release. There is only one number now, and it is the release: a host on
|
|
||||||
`0.2.0` reports `0.2.0`. Every plugin must say so, or discovery refuses it by version and **aborts
|
|
||||||
boot**:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// plugins/<your-plugin>/plugin.ts
|
|
||||||
apiVersion: "0.2.0", // was "1.0.0"
|
|
||||||
```
|
|
||||||
|
|
||||||
Re-copy anything taken from `examples/` (below) to pick this up. Nothing else in the contract
|
|
||||||
changed, so a plugin that boots after the edit needs no further work.
|
|
||||||
|
|
||||||
**Re-copy your drop-in plugins.** Anything under `plugins/` is *your* copy — the host never updates
|
**Re-copy your drop-in plugins.** Anything under `plugins/` is *your* copy — the host never updates
|
||||||
it. A plugin copied from `examples/` is still the old one after you pull, and the host may have
|
it. A plugin copied from `examples/` is still the old one after you pull, and the host may have
|
||||||
tightened a manifest rule since. Discovery fails loud at boot rather than running a plugin it can't
|
tightened a manifest rule since. Discovery fails loud at boot rather than running a plugin it can't
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const groups = on("groups");
|
|||||||
const clients = on("oauth2-clients");
|
const clients = on("oauth2-clients");
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
apiVersion: "0.2.0", // the host contract this was built against — a literal, never HOST_API_VERSION
|
apiVersion: "0.1.0", // the host contract this was built against — a literal, never HOST_API_VERSION
|
||||||
|
|
||||||
nav: [ADMIN_NAV],
|
nav: [ADMIN_NAV],
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ const upstreamUrl = process.env["SCHEDULING_UPSTREAM"] ?? "http://shifts-upstrea
|
|||||||
const upstream = createUpstream(upstreamUrl);
|
const upstream = createUpstream(upstreamUrl);
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
apiVersion: "0.2.0", // the host contract this was built against — a literal, never HOST_API_VERSION
|
apiVersion: "0.1.0", // the host contract this was built against — a literal, never HOST_API_VERSION
|
||||||
|
|
||||||
// onBoot runs after discovery, before the server listens: validate the plugin's own config so a
|
// onBoot runs after discovery, before the server listens: validate the plugin's own config so a
|
||||||
// typo'd SCHEDULING_UPSTREAM fails the boot loudly instead of degrading every request later.
|
// typo'd SCHEDULING_UPSTREAM fails the boot loudly instead of degrading every request later.
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ test("readHostApiVersion pulls the constant out of the real source, and returns
|
|||||||
test("bumping HOST_API_VERSION is a deliberate act, so pin the shipped value", () => {
|
test("bumping HOST_API_VERSION is a deliberate act, so pin the shipped value", () => {
|
||||||
// Not a substitute for the release gate — this test cannot see a tag. It is the tripwire that
|
// Not a substitute for the release gate — this test cannot see a tag. It is the tripwire that
|
||||||
// makes an accidental edit fail here rather than at release time.
|
// makes an accidental edit fail here rather than at release time.
|
||||||
assert.equal(readHostApiVersion(readFileSync("src/plugin-host/plugin.ts", "utf8")), "0.2.0");
|
assert.equal(readHostApiVersion(readFileSync("src/plugin-host/plugin.ts", "utf8")), "0.1.0");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("every author-facing apiVersion sample matches the shipped contract", () => {
|
test("every author-facing apiVersion sample matches the shipped contract", () => {
|
||||||
@@ -38,22 +38,21 @@ test("every author-facing apiVersion sample matches the shipped contract", () =>
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("checkTagMatchesContract: major.minor must agree, patch may lag", () => {
|
test("checkTagMatchesContract: major.minor must agree, patch may lag", () => {
|
||||||
assert.equal(checkTagMatchesContract("v0.2.0", "0.2.0").ok, true);
|
assert.equal(checkTagMatchesContract("v0.1.0", "0.1.0").ok, true);
|
||||||
assert.equal(checkTagMatchesContract("v0.2.7", "0.2.0").ok, true); // auto-release cut patches
|
assert.equal(checkTagMatchesContract("v0.1.7", "0.1.0").ok, true); // auto-release cut patches
|
||||||
assert.equal(checkTagMatchesContract("0.2.0", "0.2.0").ok, true); // bare tag, no v
|
assert.equal(checkTagMatchesContract("0.1.0", "0.1.0").ok, true); // bare tag, no v
|
||||||
assert.equal(checkTagMatchesContract("v0.3.0", "0.2.0").ok, false); // plugin-visible, needs a bump
|
assert.equal(checkTagMatchesContract("v0.2.0", "0.1.0").ok, false); // plugin-visible, needs a bump
|
||||||
assert.equal(checkTagMatchesContract("v0.1.0", "0.2.0").ok, false); // the previously released line
|
assert.equal(checkTagMatchesContract("v1.0.0", "0.1.0").ok, false);
|
||||||
assert.equal(checkTagMatchesContract("v1.0.0", "0.2.0").ok, false);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test("checkTagMatchesContract names what to fix rather than just failing", () => {
|
test("checkTagMatchesContract names what to fix rather than just failing", () => {
|
||||||
const res = checkTagMatchesContract("v0.3.0", "0.2.0");
|
const res = checkTagMatchesContract("v0.2.0", "0.1.0");
|
||||||
assert.equal(res.ok, false);
|
assert.equal(res.ok, false);
|
||||||
assert.match(res.ok === false ? res.error : "", /HOST_API_VERSION to 0\.3\.0/);
|
assert.match(res.ok === false ? res.error : "", /HOST_API_VERSION to 0\.2\.0/);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("checkTagMatchesContract rejects junk on either side without throwing", () => {
|
test("checkTagMatchesContract rejects junk on either side without throwing", () => {
|
||||||
assert.equal(checkTagMatchesContract("v0.2.0", null).ok, false); // constant not found
|
assert.equal(checkTagMatchesContract("v0.1.0", null).ok, false); // constant not found
|
||||||
assert.equal(checkTagMatchesContract("nope", "0.2.0").ok, false);
|
assert.equal(checkTagMatchesContract("nope", "0.1.0").ok, false);
|
||||||
assert.equal(checkTagMatchesContract("v0.2.0", "1.0").ok, false);
|
assert.equal(checkTagMatchesContract("v0.1.0", "1.0").ok, false);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ into the app. Create `plugins/hello/plugin.ts`:
|
|||||||
import { definePlugin } from "@plainpages/plugin-api";
|
import { definePlugin } from "@plainpages/plugin-api";
|
||||||
|
|
||||||
export default definePlugin({
|
export default definePlugin({
|
||||||
apiVersion: "0.2.0",
|
apiVersion: "0.1.0",
|
||||||
nav: [{ href: "/hello", id: "hello", label: "Hello", public: true }],
|
nav: [{ href: "/hello", id: "hello", label: "Hello", public: true }],
|
||||||
routes: [
|
routes: [
|
||||||
{ method: "GET", path: "/", public: true, handler: () => ({ html: "<h1>Hello from my plugin</h1>" }) },
|
{ method: "GET", path: "/", public: true, handler: () => ({ html: "<h1>Hello from my plugin</h1>" }) },
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import { AUTH_FLOWS } from "../auth/flow-view.ts";
|
|||||||
// HOST_API_VERSION would always equal the host and defeat the check. No `id`/`basePath` — the
|
// HOST_API_VERSION would always equal the host and defeat the check. No `id`/`basePath` — the
|
||||||
// host derives both from the plugin's folder name.
|
// host derives both from the plugin's folder name.
|
||||||
const scheduling: PluginManifest = definePlugin({
|
const scheduling: PluginManifest = definePlugin({
|
||||||
apiVersion: "0.2.0",
|
apiVersion: "0.1.0",
|
||||||
hooks: { onBoot: () => {} },
|
hooks: { onBoot: () => {} },
|
||||||
nav: [{
|
nav: [{
|
||||||
children: [{ href: "/scheduling/shifts", id: "scheduling:shifts", label: "Shifts", permission: "scheduling:read" }],
|
children: [{ href: "/scheduling/shifts", id: "scheduling:shifts", label: "Shifts", permission: "scheduling:read" }],
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import type { StorageCredentials } from "./storage.ts";
|
|||||||
// The Plainpages release this contract ships in — one version, not a second one to track. Its
|
// The Plainpages release this contract ships in — one version, not a second one to track. Its
|
||||||
// major.minor must equal the release tag's; `release.yml` refuses to promote a tag that disagrees.
|
// major.minor must equal the release tag's; `release.yml` refuses to promote a tag that disagrees.
|
||||||
// The patch digit may lag, since checkApiVersion ignores patch and auto-release cuts patches itself.
|
// The patch digit may lag, since checkApiVersion ignores patch and auto-release cuts patches itself.
|
||||||
export const HOST_API_VERSION = "0.2.0";
|
export const HOST_API_VERSION = "0.1.0";
|
||||||
|
|
||||||
export type HttpMethod = "DELETE" | "GET" | "HEAD" | "PATCH" | "POST" | "PUT";
|
export type HttpMethod = "DELETE" | "GET" | "HEAD" | "PATCH" | "POST" | "PUT";
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@
|
|||||||
<p>${t("dashboard.starter.intro")}</p>
|
<p>${t("dashboard.starter.intro")}</p>
|
||||||
<p>${t("dashboard.starter.replace")}</p>
|
<p>${t("dashboard.starter.replace")}</p>
|
||||||
<pre class="code-block"><code>export default definePlugin({
|
<pre class="code-block"><code>export default definePlugin({
|
||||||
apiVersion: "0.2.0",
|
apiVersion: "0.1.0",
|
||||||
// view names plugins/<id>/views/<view>.ejs, rendered in this same shell
|
// view names plugins/<id>/views/<view>.ejs, rendered in this same shell
|
||||||
dashboard: (ctx) => ({ view: "dashboard", data: { /* … */ } }),
|
dashboard: (ctx) => ({ view: "dashboard", data: { /* … */ } }),
|
||||||
});</code></pre>
|
});</code></pre>
|
||||||
|
|||||||
Reference in New Issue
Block a user