@mosaicast/plugin-sdk 0.4.0 → 0.5.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/README.md +30 -7
- package/dist/index.d.ts +84 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,8 +31,8 @@ The contract version is a **single SemVer anchor** mirrored in four places that
|
|
|
31
31
|
(CI enforces it): `build.gradle.kts` · `package.json` · `PlatformApi.VERSION` · `PLATFORM_API_VERSION`.
|
|
32
32
|
|
|
33
33
|
**How the host matches it:** core compares `major.minor` **exactly**. A plugin declaring `0.3.x` is
|
|
34
|
-
rejected the moment the host runs `0.
|
|
35
|
-
is pre-1.0 a breaking change is therefore a **minor** bump (`0.
|
|
34
|
+
rejected the moment the host runs `0.5.0` — with the reason shown in the admin log viewer. While the SDK
|
|
35
|
+
is pre-1.0 a breaking change is therefore a **minor** bump (`0.4.0` → `0.5.0`), not a major one; from
|
|
36
36
|
`1.0.0` on, normal SemVer applies and breaking means major.
|
|
37
37
|
|
|
38
38
|
## Build & test
|
|
@@ -49,8 +49,8 @@ npm ci && npm run build # TypeScript: src → dist (.js + .d.ts)
|
|
|
49
49
|
- Released: from **GitHub Packages** (see below).
|
|
50
50
|
```kotlin
|
|
51
51
|
dependencies {
|
|
52
|
-
compileOnly("dev.mosaicast:plugin-api:0.
|
|
53
|
-
testImplementation("dev.mosaicast:plugin-testkit:0.
|
|
52
|
+
compileOnly("dev.mosaicast:plugin-api:0.5.0") // contract, provided by the host
|
|
53
|
+
testImplementation("dev.mosaicast:plugin-testkit:0.5.0") // test doubles only
|
|
54
54
|
}
|
|
55
55
|
```
|
|
56
56
|
Sources + Javadoc JARs give IDE hover docs automatically.
|
|
@@ -99,16 +99,39 @@ DELETE /api/plugins/{id}/data/{scopeType}/{scopeId}/{key}
|
|
|
99
99
|
| upsert | `store().put(scope, key, value)` | `ctx.api.put('data/…/{key}', value)` |
|
|
100
100
|
| remove | `store().delete(scope, key)` → `boolean` | `ctx.api.delete('data/…/{key}')` |
|
|
101
101
|
|
|
102
|
-
- `scopeType` is `site | feed | season | episode` and `scopeId` is that entity's id — mirroring `Scope`/`ScopeType`, the same addressing the backend uses.
|
|
103
|
-
- `key` must match `DocStore.KEY_PATTERN` = `^[A-Za-z0-9._:-]{1,200}$` and is the final path segment, verbatim — no `/`, and no percent-encoded slash either (servlet containers reject `%2F` there). Structure keys with `:` / `.` / `-` instead, e.g. `mark:
|
|
102
|
+
- `scopeType` is `site | feed | season | episode | user` and `scopeId` is that entity's id — mirroring `Scope`/`ScopeType`, the same addressing the backend uses. Two are **singletons** whose id the SDK and the host both pin: `site`'s is always `main` (`Scope.SITE_ID`, one site) and `user`'s always `me` (`Scope.SELF_ID`, the calling user). So `Scope.site()` and `…/data/site/main/{key}` address the same document, and the path always has four non-empty segments.
|
|
103
|
+
- `key` must match `DocStore.KEY_PATTERN` = `^[A-Za-z0-9._:-]{1,200}$` and is the final path segment, verbatim — no `/`, and no percent-encoded slash either (servlet containers reject `%2F` there). Structure keys with `:` / `.` / `-` instead, e.g. `mark:s2e04:b3` (entity ids are slugs, not UUIDs). The host answers 400 on a bad key, and `InMemoryDocStore` throws `IllegalArgumentException` — so it fails in your tests, not in production.
|
|
104
104
|
- The list is **paginated** (core's standard `PagedResponse` envelope) and **carries keys** (`DocEntry`), because neither end can address a doc without one.
|
|
105
105
|
- `delete` is **idempotent**: removing an absent doc is not an error. The Java call returns whether anything was actually removed.
|
|
106
106
|
|
|
107
|
+
### Per-user data — the `user` scope (since 0.5.0)
|
|
108
|
+
|
|
109
|
+
**Per-user data belongs in the `user` scope, never in the key.** A key is client-supplied, so the convention this README used to suggest — `mark:<userId>:cell` under an episode scope — was an access-control decision the host could not enforce: any caller past the plugin's read floor could address someone else's key directly, and scope ids are public slugs, so nothing had to be guessed.
|
|
110
|
+
|
|
111
|
+
`Scope.user()` / `…/data/user/me/{key}` fixes that by construction:
|
|
112
|
+
|
|
113
|
+
- The id is always the sentinel `me` (`Scope.SELF_ID`), resolved **server-side from the session**. The canonical `Scope` constructor normalizes any `USER` id to it, so there is no expression in the Java API that names another person's partition — and there is deliberately **no `Scope.user(String)` overload**.
|
|
114
|
+
- Naming any other `user` id over HTTP is a **400**, never a silent substitution. An anonymous `user` request is a **401** whatever the read floor says: no session, no partition.
|
|
115
|
+
- The partition is **flat** — one per user, not one per user and entity — so the entity goes in the key: `mark:<episodeSlug>:cell`.
|
|
116
|
+
- `readableBy` does not apply to it. No floor makes someone else's partition readable.
|
|
117
|
+
|
|
118
|
+
**A backend has no calling user**, so every `DocStore` method throws `UnsupportedOperationException` for a `USER` scope — reads included, since resolving "me" without a caller would have to pick someone. Aggregate instead:
|
|
119
|
+
|
|
120
|
+
```java
|
|
121
|
+
// Backend-only, read-only, and no HTTP surface: no visitor's request can reach another's data.
|
|
122
|
+
List<OwnedDocEntry> marks = ctx.store().queryAcrossUsers("mark:");
|
|
123
|
+
// record OwnedDocEntry(UUID userId, String key, JsonNode value) — the owner is host-resolved, never
|
|
124
|
+
// a value the browser supplied, which is what makes a leaderboard built from it true.
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Write the aggregate back to an entity scope (`…/data/episode/s2e04/leaderboard`) and let the component read it there. In tests, `InMemoryDocStore.asUser(uuid)` stands in for the host resolving `me`, so you can seed what a frontend would have written and then assert on `queryAcrossUsers`.
|
|
128
|
+
|
|
107
129
|
**The two ends see one store.** The doc a backend writes with `ctx.store().put(scope, key, value)` is exactly what the frontend reads at `GET /api/plugins/{id}/data/{scopeType}/{scopeId}/{key}`.
|
|
108
130
|
|
|
109
131
|
**What the host enforces**, so a plugin doesn't have to:
|
|
110
132
|
- Data is **hard-scoped to the plugin id** — a plugin can only ever see its own data.
|
|
111
|
-
- **
|
|
133
|
+
- **Access is what the manifest declares**, not what the slots imply: `"data": { "readableBy": "fan", "writableBy": "podcaster" }`. Values are `anonymous | fan | podcaster | admin`; `writableBy` may not be `anonymous`, and an absent block defaults `readableBy` to the **write** floor rather than to anonymous — saying nothing gets the safe answer. A slot's `visibleTo` governs **rendering only**; deriving the data floor from unrelated UI slots is what once let a plugin with one anonymous slot expose its whole store.
|
|
134
|
+
- The host validates that the scope exists (and that the feed is enabled). `ctx.api` carries the user's auth (session or personal access token).
|
|
112
135
|
|
|
113
136
|
**No request-time server logic.** A write is plain persistence — no plugin code runs on the request. Anything derived, validated or aggregated server-side is **precomputed** in `register`/`onSchedule` and read back from the store.
|
|
114
137
|
|
package/dist/index.d.ts
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* rejects a mismatch at startup (ARCHITECTURE §7.2). While the SDK is pre-1.0 a breaking change is
|
|
18
18
|
* therefore a *minor* bump; from `1.0.0` on, breaking means major.
|
|
19
19
|
*/
|
|
20
|
-
export declare const PLATFORM_API_VERSION: '0.
|
|
20
|
+
export declare const PLATFORM_API_VERSION: '0.5.0';
|
|
21
21
|
/** A user's role (ARCHITECTURE §8.5). Anonymous visitors have no role (`user` is `null`). */
|
|
22
22
|
export type Role = 'admin' | 'podcaster' | 'fan';
|
|
23
23
|
/**
|
|
@@ -35,13 +35,41 @@ export type LogLevel = 'debug' | 'info' | 'warn' | 'error';
|
|
|
35
35
|
* reference to a detached DOM tree and keeps firing into it.
|
|
36
36
|
*/
|
|
37
37
|
export type Unsubscribe = () => void;
|
|
38
|
-
/**
|
|
38
|
+
/**
|
|
39
|
+
* The level plus concrete entity a view is scoped to (ARCHITECTURE §6.1).
|
|
40
|
+
*
|
|
41
|
+
* This is the **slot** scope — the page your component was mounted on. It never carries the `user` level
|
|
42
|
+
* of {@link DataScopeType}: a slot lives in a named region of a page, and there is no user page. A
|
|
43
|
+
* component reading per-user data addresses `data/user/me/…` explicitly while `ctx.scope` stays whatever
|
|
44
|
+
* page it is on.
|
|
45
|
+
*/
|
|
39
46
|
export interface Scope {
|
|
40
47
|
/** The scope level. */
|
|
41
48
|
type: 'site' | 'feed' | 'season' | 'episode';
|
|
42
|
-
/** The id of the entity at that level (e.g. the `EpisodeRef`
|
|
49
|
+
/** The id of the entity at that level (e.g. the `EpisodeRef` slug for `episode`). */
|
|
43
50
|
id: string;
|
|
44
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* The scope levels the host's **data** surface addresses — the four page levels of {@link Scope} plus
|
|
54
|
+
* `user`, the caller's own private partition (`ScopeType` in the Java SDK).
|
|
55
|
+
*
|
|
56
|
+
* Deliberately a second type: `user` is a storage partition, never a slot scope, so it can appear in a
|
|
57
|
+
* `data/{scopeType}/{scopeId}/…` path but never in `ctx.scope`.
|
|
58
|
+
*
|
|
59
|
+
* @since 0.5.0
|
|
60
|
+
*/
|
|
61
|
+
export type DataScopeType = Scope['type'] | 'user';
|
|
62
|
+
/**
|
|
63
|
+
* The id every `user` data path carries: the literal `me`, mirroring the Java `Scope.SELF_ID`.
|
|
64
|
+
*
|
|
65
|
+
* The host resolves it from the session, so `data/user/me/{key}` reaches the calling user's partition and
|
|
66
|
+
* no one else's. **Any other `user` id is a 400**, never a silent substitution, and an anonymous request
|
|
67
|
+
* to a `user` path is a 401 — with no session there is no partition. Per-user data belongs here rather
|
|
68
|
+
* than in a key like `mark:<userId>:cell`, which the host cannot enforce because the client supplies it.
|
|
69
|
+
*
|
|
70
|
+
* @since 0.5.0
|
|
71
|
+
*/
|
|
72
|
+
export declare const SELF_SCOPE_ID: 'me';
|
|
45
73
|
/**
|
|
46
74
|
* The host-owned filter axes for the current view (ARCHITECTURE §6.1).
|
|
47
75
|
*
|
|
@@ -135,38 +163,73 @@ export interface PagedDocs<T = unknown> {
|
|
|
135
163
|
* → remove; idempotent
|
|
136
164
|
* ```
|
|
137
165
|
*
|
|
138
|
-
* `scopeType` is
|
|
139
|
-
*
|
|
140
|
-
*
|
|
166
|
+
* `scopeType` is a {@link DataScopeType} and `scopeId` the id of that entity — i.e. the `Scope` the
|
|
167
|
+
* backend addresses with. Two of them are singletons whose id is fixed: `site` is always the literal
|
|
168
|
+
* `main` (one site), and `user` always {@link SELF_SCOPE_ID} (`me`), which the host resolves to the
|
|
169
|
+
* calling user. So the path always has four non-empty segments. `key` must match
|
|
141
170
|
* `^[A-Za-z0-9._:-]{1,200}$` — the host answers 400 otherwise — and is the final path segment verbatim:
|
|
142
|
-
* no `/`, so structure keys with `:` / `.` / `-` (e.g. `mark:
|
|
143
|
-
* ({@link PagedDocs}) and carries each doc's key ({@link DocEntry}), since you cannot
|
|
144
|
-
* without it.
|
|
171
|
+
* no `/`, so structure keys with `:` / `.` / `-` (e.g. `mark:s2e04:b3`; entity ids are slugs). The list
|
|
172
|
+
* is paginated ({@link PagedDocs}) and carries each doc's key ({@link DocEntry}), since you cannot
|
|
173
|
+
* address a doc without it.
|
|
145
174
|
*
|
|
146
175
|
* The doc a backend writes with `ctx.store().put(scope, key, value)` is the one read here at
|
|
147
|
-
* `GET /api/plugins/{id}/data/{scopeType}/{scopeId}/{key}`: one store, two ends.
|
|
176
|
+
* `GET /api/plugins/{id}/data/{scopeType}/{scopeId}/{key}`: one store, two ends. The `user` scope is the
|
|
177
|
+
* exception — it exists only here. A backend has no calling user, so it cannot write a user partition at
|
|
178
|
+
* all and reads them only in aggregate, through the Java `DocStore.queryAcrossUsers(prefix)`.
|
|
179
|
+
*
|
|
180
|
+
* ## Where per-user data goes
|
|
181
|
+
*
|
|
182
|
+
* **In the `user` scope, not in the key.** A key is client-supplied, so the older convention
|
|
183
|
+
* `mark:<userId>:cell` under an episode scope was an access-control decision the host could not check:
|
|
184
|
+
* any caller past the plugin's read floor could address someone else's key, and scope ids are public
|
|
185
|
+
* slugs, so nothing had to be guessed. `data/user/me/…` is resolved from the session instead — the only
|
|
186
|
+
* partition a caller can name is their own. Any other `user` id is a **400**; an anonymous `user` request
|
|
187
|
+
* is a **401**, whatever the read floor says. The partition is flat, so the entity goes in the key:
|
|
188
|
+
* `mark:<episodeSlug>:cell`.
|
|
148
189
|
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
152
|
-
*
|
|
153
|
-
*
|
|
190
|
+
* ## What the host enforces
|
|
191
|
+
*
|
|
192
|
+
* Data is hard-scoped to the plugin id — a plugin only ever sees its own — and the host validates that the
|
|
193
|
+
* scope exists. Access is what your **manifest** declares:
|
|
194
|
+
*
|
|
195
|
+
* ```json
|
|
196
|
+
* "data": { "readableBy": "fan", "writableBy": "podcaster" }
|
|
197
|
+
* ```
|
|
198
|
+
*
|
|
199
|
+
* Values are `anonymous | fan | podcaster | admin` ({@link Role} plus `anonymous`, the absence of one);
|
|
200
|
+
* `writableBy` may not be `anonymous`, and if the block is absent `readableBy` falls back to the *write*
|
|
201
|
+
* floor rather than to anonymous — saying nothing gets the safe answer. A slot's `visibleTo` governs
|
|
202
|
+
* **rendering only**; it never governed data access, and inferring the data floor from unrelated UI slots
|
|
203
|
+
* is exactly what once let a plugin with one anonymous slot expose its whole store. Watch the default: a
|
|
204
|
+
* plugin with an anonymous slot and no `data` block loses its anonymous reads (403) until it declares
|
|
205
|
+
* `"readableBy": "anonymous"`. **Neither floor applies to the `user` scope:** no floor makes someone
|
|
206
|
+
* else's partition readable, none stands between a caller and their own, and `writableBy` does not gate it
|
|
207
|
+
* either — a write floor protects the *shared* surface, and a user partition is unshared. Any
|
|
208
|
+
* authenticated caller reads and writes their own `data/user/me/…` whatever the manifest declares.
|
|
209
|
+
*
|
|
210
|
+
* A write is plain persistence: no plugin code runs at request time, so anything derived or validated
|
|
211
|
+
* server-side must be precomputed in the backend's `register`/`onSchedule` and read back from the store.
|
|
154
212
|
*
|
|
155
213
|
* Custom plugin-defined server routes may arrive in a later `platformApi` version; v1 plugins use the
|
|
156
214
|
* doc store.
|
|
157
215
|
*
|
|
158
216
|
* @example Read, list, write and remove docs from a Web Component
|
|
159
217
|
* ```ts
|
|
160
|
-
* const
|
|
161
|
-
* const
|
|
218
|
+
* const mine = `data/user/${SELF_SCOPE_ID}`; // the caller's own partition
|
|
219
|
+
* const shared = `data/${ctx.scope.type}/${ctx.scope.id}`; // scope.id is `main` on the site scope
|
|
220
|
+
* const key = `mark:${ctx.scope.id}`; // no `/` in keys
|
|
162
221
|
*
|
|
163
|
-
* const
|
|
164
|
-
* await ctx.api.put(`${
|
|
222
|
+
* const marks = await ctx.api.get<Marks>(`${mine}/${key}`); // rejects with a 404 problem if absent
|
|
223
|
+
* await ctx.api.put(`${mine}/${key}`, { ...marks, b3: true }); // upsert, last-write-wins
|
|
165
224
|
*
|
|
166
|
-
* const page = await ctx.api.get<PagedDocs<
|
|
225
|
+
* const page = await ctx.api.get<PagedDocs<Marks>>(`${mine}?prefix=mark:&page=0&size=50`);
|
|
167
226
|
* page.items.forEach(({ key, value }) => render(key, value));
|
|
168
227
|
*
|
|
169
|
-
* await ctx.api.delete(`${
|
|
228
|
+
* await ctx.api.delete(`${mine}/${key}`); // idempotent
|
|
229
|
+
*
|
|
230
|
+
* // A leaderboard is not built here: the backend aggregates every user's marks with
|
|
231
|
+
* // queryAcrossUsers(...) and writes the result to `${shared}/leaderboard` for this component to read.
|
|
232
|
+
* const board = await ctx.api.get<Leaderboard>(`${shared}/leaderboard`);
|
|
170
233
|
* ```
|
|
171
234
|
*/
|
|
172
235
|
export interface PluginApiClient {
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA;;;;;;;;GAQG;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,EAAG,OAAgB,CAAC;AAErD,6FAA6F;AAC7F,MAAM,MAAM,IAAI,GAAG,OAAO,GAAG,WAAW,GAAG,KAAK,CAAC;AAEjD;;;;;GAKG;AACH,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAE3D;;;;;;GAMG;AACH,MAAM,MAAM,WAAW,GAAG,MAAM,IAAI,CAAC;AAErC
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -19,7 +19,18 @@
|
|
|
19
19
|
* rejects a mismatch at startup (ARCHITECTURE §7.2). While the SDK is pre-1.0 a breaking change is
|
|
20
20
|
* therefore a *minor* bump; from `1.0.0` on, breaking means major.
|
|
21
21
|
*/
|
|
22
|
-
export const PLATFORM_API_VERSION = '0.
|
|
22
|
+
export const PLATFORM_API_VERSION = '0.5.0';
|
|
23
|
+
/**
|
|
24
|
+
* The id every `user` data path carries: the literal `me`, mirroring the Java `Scope.SELF_ID`.
|
|
25
|
+
*
|
|
26
|
+
* The host resolves it from the session, so `data/user/me/{key}` reaches the calling user's partition and
|
|
27
|
+
* no one else's. **Any other `user` id is a 400**, never a silent substitution, and an anonymous request
|
|
28
|
+
* to a `user` path is a 401 — with no session there is no partition. Per-user data belongs here rather
|
|
29
|
+
* than in a key like `mark:<userId>:cell`, which the host cannot enforce because the client supplies it.
|
|
30
|
+
*
|
|
31
|
+
* @since 0.5.0
|
|
32
|
+
*/
|
|
33
|
+
export const SELF_SCOPE_ID = 'me';
|
|
23
34
|
/**
|
|
24
35
|
* The artwork to display for an episode: its own {@link DisplaySnapshot.imageUrl} if present, otherwise
|
|
25
36
|
* the {@link DisplaySnapshot.feedImageUrl feed cover}, otherwise `undefined`.
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,qDAAqD;AAErD;;;;;;;;GAQG;AAEH;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,oBAAoB,GAAG,OAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mosaicast/plugin-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Versioned plugin contract for Mosaicast: the frontend PluginContext types, a Web Component base helper, an i18n helper, plus a test kit under the /testing subpath.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"repository": {
|