@clovnet/plugin-sdk 0.1.4
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/LICENSE +21 -0
- package/README.md +114 -0
- package/dist/chunk-XRSKWL3A.js +1872 -0
- package/dist/chunk-XRSKWL3A.js.map +1 -0
- package/dist/index.d.ts +3658 -0
- package/dist/index.js +561 -0
- package/dist/index.js.map +1 -0
- package/dist/testing.d.ts +275 -0
- package/dist/testing.js +1010 -0
- package/dist/testing.js.map +1 -0
- package/package.json +75 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Clovnet
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# @clovnet/plugin-sdk
|
|
2
|
+
|
|
3
|
+
The official SDK for building **CasinoWebEngine (CWE) plugins** — the complete, contract-only
|
|
4
|
+
surface a plugin may touch, plus a full in-memory test harness under `./testing`. You never see
|
|
5
|
+
(or need) the platform's core: no database, no message bus, no wallet internals.
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @clovnet/plugin-sdk zod
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`zod` is a **peer dependency** — your plugin and the host share one instance.
|
|
12
|
+
|
|
13
|
+
## Quickstart
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { definePlugin, settingsField, type PluginManifest } from "@clovnet/plugin-sdk";
|
|
17
|
+
import { z } from "zod";
|
|
18
|
+
|
|
19
|
+
const manifest: PluginManifest = {
|
|
20
|
+
key: "my-plugin",
|
|
21
|
+
name: "My Plugin",
|
|
22
|
+
author: "me",
|
|
23
|
+
version: "0.1.0",
|
|
24
|
+
kind: "integration",
|
|
25
|
+
runtimeCompat: ">=0.1.0 <0.2.0",
|
|
26
|
+
permissions: {
|
|
27
|
+
commands: [], // command allowlist (fail-closed)
|
|
28
|
+
events: { subscribe: [], emit: ["plugin.my-plugin.something_happened"] },
|
|
29
|
+
},
|
|
30
|
+
settings: { fields: { greeting: settingsField.string({ label: "Greeting" }) } },
|
|
31
|
+
datasets: {
|
|
32
|
+
notes: { schema: z.object({ noteKey: z.string(), text: z.string() }), keyField: "noteKey" },
|
|
33
|
+
},
|
|
34
|
+
routes: [{ method: "GET", path: "/notes", surface: "player", handler: "list-notes" }],
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export default definePlugin({
|
|
38
|
+
manifest,
|
|
39
|
+
handlers: {
|
|
40
|
+
routes: {
|
|
41
|
+
"list-notes": async (req, ctx) => {
|
|
42
|
+
const notes = ctx.datasets.collection("notes");
|
|
43
|
+
const page = await notes.query({ limit: 50 });
|
|
44
|
+
return { body: { notes: page.records, player: req.player!.id } };
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Everything a plugin can do flows through the `PluginContext` (`ctx`):
|
|
52
|
+
|
|
53
|
+
| Capability | Surface | Gate |
|
|
54
|
+
|---|---|---|
|
|
55
|
+
| change core state | `ctx.commands.execute` | manifest command allowlist |
|
|
56
|
+
| read core data | `ctx.data.query` | manifest `dataScopes` (PII is a separate grant) |
|
|
57
|
+
| own data | `ctx.datasets` | declared datasets; schema-validated, quota-capped |
|
|
58
|
+
| events out | `ctx.events.emit` | namespaced `plugin.<key>.*`, declared |
|
|
59
|
+
| events in | `ctx.events.on` | declared subscriptions |
|
|
60
|
+
| call external APIs | `ctx.http.fetch` | `network.allowedHosts`, HTTPS only, secrets injected host-side |
|
|
61
|
+
| background work | `ctx.tasks.start` | task handlers, checkpoint-resumable |
|
|
62
|
+
| config / credentials | `ctx.settings` / `ctx.secrets` | typed schema; secrets write-only, never logged |
|
|
63
|
+
|
|
64
|
+
Everything not declared in the manifest is denied — at runtime **and** in your tests.
|
|
65
|
+
|
|
66
|
+
## Testing (`/testing`)
|
|
67
|
+
|
|
68
|
+
```ts
|
|
69
|
+
import { createTestContext, validateManifest } from "@clovnet/plugin-sdk/testing";
|
|
70
|
+
import plugin from "./src/index.js";
|
|
71
|
+
|
|
72
|
+
const { ctx, harness } = createTestContext({
|
|
73
|
+
definition: plugin,
|
|
74
|
+
settings: { greeting: "hi" },
|
|
75
|
+
secrets: { apiKey: "test-key" },
|
|
76
|
+
commandResults: { "wallet.bet.place": { transactionId: "t1", legs: [] } },
|
|
77
|
+
httpMock: () => ({ status: 200, json: { ok: true } }),
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
await harness.invokeRoute("POST /notes", { player: { id: "p1" }, body: { text: "gg" } });
|
|
81
|
+
harness.commands; // every command the plugin dispatched
|
|
82
|
+
harness.events; // every event it emitted
|
|
83
|
+
harness.httpExchanges; // outbound calls — secret headers shown as <redacted:name>
|
|
84
|
+
await harness.runJob("cleanup");
|
|
85
|
+
await harness.runMigration("0.2.0");
|
|
86
|
+
validateManifest(plugin); // doctor-lite: handler refs, cron, datasets, surfaces
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
The mock enforces exactly what the real host enforces (same error names/codes); the platform runs
|
|
90
|
+
a conformance suite against both on every change.
|
|
91
|
+
|
|
92
|
+
## Versioning — the runtime contract
|
|
93
|
+
|
|
94
|
+
The SDK's **major.minor is the platform's `RUNTIME_API_VERSION`** (patch releases are free). Your
|
|
95
|
+
manifest's `runtimeCompat` range must include the SDK minor you compiled against:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
SDK 0.1.x → runtimeCompat: ">=0.1.0 <0.2.0"
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
npm dist-tags mirror the platform's release channels: `latest` = stable, `next` = beta,
|
|
102
|
+
`dev` = dev.
|
|
103
|
+
|
|
104
|
+
## Dev loop
|
|
105
|
+
|
|
106
|
+
Start from the **plugin template** (a working `player-favorites` example with tests), then:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
docker compose -f docker-compose.plugindev.yml up # local CWE runtime (from the platform repo)
|
|
110
|
+
npx @clovnet/plugin-cli dev # watch → build → hot-reload sideload
|
|
111
|
+
npx @clovnet/plugin-cli validate # full plugin doctor on the runtime
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
MIT © CasinoWebEngine
|