@browxai/plugin-example 0.1.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/LICENSE +21 -0
- package/README.md +33 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.js +81 -0
- package/package.json +56 -0
- package/schema.d.ts +34 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Kalebtec
|
|
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,33 @@
|
|
|
1
|
+
# @browxai/plugin-example
|
|
2
|
+
|
|
3
|
+
The canonical browxai reference plugin. Exercises every primitive of
|
|
4
|
+
the v1 plugin-runtime contract — a `register(api)` entry module,
|
|
5
|
+
namespaced tool registration, an empty `capabilities` array (runs on a
|
|
6
|
+
server with the default capability set), an empty `dependsOn` graph, a
|
|
7
|
+
unit-test file, and a typed `schema.d.ts` SDK overlay. It is the
|
|
8
|
+
fixture the plugin-runtime keystone test loads end-to-end, and the
|
|
9
|
+
layout plugin authors copy to start their own plugin (see
|
|
10
|
+
`docs/plugin-authoring.md` in the browxai repo).
|
|
11
|
+
|
|
12
|
+
Three tools:
|
|
13
|
+
|
|
14
|
+
- `example.echo({msg})` → `{ok, result}` — round-trip primitive.
|
|
15
|
+
- `example.add({a, b})` → `{ok, sum}` — typed-arg demonstration.
|
|
16
|
+
- `example.now()` → `{ok, iso, epochMs}` — argless tool shape.
|
|
17
|
+
|
|
18
|
+
## Install
|
|
19
|
+
|
|
20
|
+
```sh
|
|
21
|
+
$ browxai plugin install @browxai/plugin-example
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
No extra capabilities required. Restart the browxai server after
|
|
25
|
+
install (plugin lifecycle is resolved-once-at-server-start). The tools
|
|
26
|
+
surface as `example.echo` (etc.) on MCP `tools/list`, and on the SDK as
|
|
27
|
+
`client.plugins.example.echo(...)`.
|
|
28
|
+
|
|
29
|
+
## Full reference
|
|
30
|
+
|
|
31
|
+
The first-party plugin reference — tool tables, error envelopes, and a
|
|
32
|
+
usage walkthrough for this plugin and the three canvas adapters — lives
|
|
33
|
+
at <https://browxai.com/plugins/first-party/>.
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
interface ToolResponse {
|
|
2
|
+
readonly content: ReadonlyArray<{
|
|
3
|
+
type: "text";
|
|
4
|
+
text: string;
|
|
5
|
+
} | {
|
|
6
|
+
type: "image";
|
|
7
|
+
data: string;
|
|
8
|
+
mimeType: string;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
interface PluginApi {
|
|
12
|
+
readonly namespace: string;
|
|
13
|
+
readonly declaredCapabilities: ReadonlyArray<string>;
|
|
14
|
+
registerTool(name: string, def: {
|
|
15
|
+
description: string;
|
|
16
|
+
inputSchema?: Record<string, any> | undefined;
|
|
17
|
+
}, handler: (args: unknown) => Promise<ToolResponse>): void;
|
|
18
|
+
callTool(name: string, args?: Record<string, unknown>): Promise<ToolResponse>;
|
|
19
|
+
log: {
|
|
20
|
+
info(msg: string, meta?: Record<string, unknown>): void;
|
|
21
|
+
warn(msg: string, meta?: Record<string, unknown>): void;
|
|
22
|
+
error(msg: string, meta?: Record<string, unknown>): void;
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Build the per-tool handlers as plain functions so the plugin's
|
|
27
|
+
* unit-test suite can exercise them WITHOUT spinning up the full
|
|
28
|
+
* runtime — the test file imports these directly.
|
|
29
|
+
*/
|
|
30
|
+
export declare const handlers: {
|
|
31
|
+
/** `example.echo({ msg })` → `{ ok: true, result: msg }`. The
|
|
32
|
+
* classic round-trip primitive — used by the keystone to assert
|
|
33
|
+
* end-to-end MCP dispatch through the plugin runtime. */
|
|
34
|
+
echo: (args: unknown) => Promise<ToolResponse>;
|
|
35
|
+
/** `example.add({ a, b })` → `{ ok: true, sum: a + b }`. Trivial
|
|
36
|
+
* math primitive — demonstrates the handler's typed-arg pattern. */
|
|
37
|
+
add: (args: unknown) => Promise<ToolResponse>;
|
|
38
|
+
/** `example.now()` → `{ ok: true, iso, epochMs }`. Argless tool
|
|
39
|
+
* shape; demonstrates that an empty input schema is fine. */
|
|
40
|
+
now: () => Promise<ToolResponse>;
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* Plugin entry. The runtime imports this module via
|
|
44
|
+
* `await import(<entryPath>)` and calls `register(api)`. The named
|
|
45
|
+
* export takes precedence over a default export.
|
|
46
|
+
*/
|
|
47
|
+
export declare function register(api: PluginApi): void;
|
|
48
|
+
export default register;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
// @browxai/plugin-example — the canonical reference plugin.
|
|
2
|
+
//
|
|
3
|
+
// Exercises every primitive of the v1 plugin-runtime contract:
|
|
4
|
+
// - `register(api)` entry point as a named export.
|
|
5
|
+
// - Three tools, all under the declared namespace `example.`.
|
|
6
|
+
// - No declared capabilities (the simplest case — runs on a server
|
|
7
|
+
// with the default capability set).
|
|
8
|
+
// - Empty `dependsOn` (no inter-plugin composition).
|
|
9
|
+
//
|
|
10
|
+
// Plugin authors: copy this layout, change `package.json#browxai`,
|
|
11
|
+
// add your own tools in `register(api)`. See `docs/plugin-authoring.md`.
|
|
12
|
+
//
|
|
13
|
+
// The `PluginApi` shape is documented in the host's plugin-authoring
|
|
14
|
+
// guide. We inline a minimal type here so the plugin doesn't import
|
|
15
|
+
// from a host-internal module — once `@browxai/plugin-types`
|
|
16
|
+
// ships, plugins will import the interface from there.
|
|
17
|
+
const json = (obj) => ({
|
|
18
|
+
content: [{ type: "text", text: JSON.stringify(obj, null, 2) }],
|
|
19
|
+
});
|
|
20
|
+
/**
|
|
21
|
+
* Build the per-tool handlers as plain functions so the plugin's
|
|
22
|
+
* unit-test suite can exercise them WITHOUT spinning up the full
|
|
23
|
+
* runtime — the test file imports these directly.
|
|
24
|
+
*/
|
|
25
|
+
// Arrow-property form (not method-syntax) so call sites can pass
|
|
26
|
+
// `handlers.echo` as a value without tripping `unbound-method`. Bodies
|
|
27
|
+
// are sync — they return `Promise.resolve(...)` to honour the
|
|
28
|
+
// `Promise<ToolResponse>` handler contract without an empty `async`.
|
|
29
|
+
export const handlers = {
|
|
30
|
+
/** `example.echo({ msg })` → `{ ok: true, result: msg }`. The
|
|
31
|
+
* classic round-trip primitive — used by the keystone to assert
|
|
32
|
+
* end-to-end MCP dispatch through the plugin runtime. */
|
|
33
|
+
echo: (args) => {
|
|
34
|
+
const a = (args ?? {});
|
|
35
|
+
const msg = typeof a.msg === "string" ? a.msg : "";
|
|
36
|
+
return Promise.resolve(json({ ok: true, result: msg }));
|
|
37
|
+
},
|
|
38
|
+
/** `example.add({ a, b })` → `{ ok: true, sum: a + b }`. Trivial
|
|
39
|
+
* math primitive — demonstrates the handler's typed-arg pattern. */
|
|
40
|
+
add: (args) => {
|
|
41
|
+
const a = (args ?? {});
|
|
42
|
+
const left = typeof a.a === "number" ? a.a : 0;
|
|
43
|
+
const right = typeof a.b === "number" ? a.b : 0;
|
|
44
|
+
return Promise.resolve(json({ ok: true, sum: left + right }));
|
|
45
|
+
},
|
|
46
|
+
/** `example.now()` → `{ ok: true, iso, epochMs }`. Argless tool
|
|
47
|
+
* shape; demonstrates that an empty input schema is fine. */
|
|
48
|
+
now: () => {
|
|
49
|
+
const ms = Date.now();
|
|
50
|
+
return Promise.resolve(json({ ok: true, iso: new Date(ms).toISOString(), epochMs: ms }));
|
|
51
|
+
},
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Plugin entry. The runtime imports this module via
|
|
55
|
+
* `await import(<entryPath>)` and calls `register(api)`. The named
|
|
56
|
+
* export takes precedence over a default export.
|
|
57
|
+
*/
|
|
58
|
+
export function register(api) {
|
|
59
|
+
api.log.info("example plugin: registering tools", { namespace: api.namespace });
|
|
60
|
+
// Tool names MUST be prefixed with the plugin's namespace. The
|
|
61
|
+
// runtime throws synchronously if a registration violates this.
|
|
62
|
+
// The Zod schema is the same shape host tools use; the plugin
|
|
63
|
+
// doesn't have to import Zod itself if the inputSchema is an
|
|
64
|
+
// empty object — the schema is consulted by MCP's `tools/list` and
|
|
65
|
+
// is purely informational at the plugin layer.
|
|
66
|
+
api.registerTool(`${api.namespace}.echo`, {
|
|
67
|
+
description: "Round-trip primitive — returns whatever `msg` was passed. Useful for proving the plugin runtime is reachable end-to-end (keystone uses this).",
|
|
68
|
+
inputSchema: {},
|
|
69
|
+
}, handlers.echo);
|
|
70
|
+
api.registerTool(`${api.namespace}.add`, {
|
|
71
|
+
description: "Sums two numeric args. Trivial demonstration of the handler's typed-arg pattern.",
|
|
72
|
+
inputSchema: {},
|
|
73
|
+
}, handlers.add);
|
|
74
|
+
api.registerTool(`${api.namespace}.now`, {
|
|
75
|
+
description: "Returns the current ISO timestamp + epoch milliseconds. No args.",
|
|
76
|
+
inputSchema: {},
|
|
77
|
+
}, handlers.now);
|
|
78
|
+
}
|
|
79
|
+
// Also export as default for the "default export is the register fn"
|
|
80
|
+
// alternative loading path (the runtime accepts either).
|
|
81
|
+
export default register;
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@browxai/plugin-example",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Reference browxai plugin — exercises every registry feature (tool registration, capability declaration, dependency declaration). Canonical source for plugin authors.",
|
|
5
|
+
"author": "Kalebtec",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"browxai",
|
|
10
|
+
"browxai-plugin",
|
|
11
|
+
"mcp",
|
|
12
|
+
"browser-automation",
|
|
13
|
+
"ai-agent"
|
|
14
|
+
],
|
|
15
|
+
"homepage": "https://browxai.com/plugins/first-party/",
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/kalebteccom/browxai.git",
|
|
19
|
+
"directory": "packages/plugins/example"
|
|
20
|
+
},
|
|
21
|
+
"bugs": {
|
|
22
|
+
"url": "https://github.com/kalebteccom/browxai/issues"
|
|
23
|
+
},
|
|
24
|
+
"main": "dist/index.js",
|
|
25
|
+
"types": "dist/index.d.ts",
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"schema.d.ts",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public",
|
|
33
|
+
"provenance": true
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"build": "tsc -p tsconfig.json",
|
|
37
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
38
|
+
"test": "vitest run"
|
|
39
|
+
},
|
|
40
|
+
"browxai": {
|
|
41
|
+
"apiVersion": "1.0.0",
|
|
42
|
+
"browxaiVersion": "^0.7.0",
|
|
43
|
+
"namespace": "example",
|
|
44
|
+
"register": "dist/index.js",
|
|
45
|
+
"capabilities": [],
|
|
46
|
+
"trust": "kalebtec",
|
|
47
|
+
"dependsOn": []
|
|
48
|
+
},
|
|
49
|
+
"engines": {
|
|
50
|
+
"node": ">=20"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"typescript": "^5.5.0",
|
|
54
|
+
"vitest": "^2.0.0"
|
|
55
|
+
}
|
|
56
|
+
}
|
package/schema.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
// Typed SDK overlay for `@browxai/plugin-example` consumers.
|
|
2
|
+
//
|
|
3
|
+
// SDK consumers import the schema type + compose it via the host's
|
|
4
|
+
// `BrowxaiClientWithPlugins` helper to get autocomplete on every
|
|
5
|
+
// example tool — `client.plugins.example.echo({msg:"hi"})` — with full
|
|
6
|
+
// argument typing.
|
|
7
|
+
//
|
|
8
|
+
// import type { ExamplePluginSchema } from "@browxai/plugin-example/schema";
|
|
9
|
+
// import type { BrowxaiClientWithPlugins } from "browxai";
|
|
10
|
+
//
|
|
11
|
+
// const client = (await createBrowxai({...})) as BrowxaiClientWithPlugins<ExamplePluginSchema>;
|
|
12
|
+
// await client.plugins.example.echo({msg: "hello"});
|
|
13
|
+
|
|
14
|
+
// We declare the relevant subset of the BrowxaiResult envelope here
|
|
15
|
+
// rather than importing it — keeps the schema declaration free of
|
|
16
|
+
// runtime deps. Adopters who want the structured payload can also
|
|
17
|
+
// import the host's `BrowxaiResult` type and substitute it.
|
|
18
|
+
interface ExampleBrowxaiResult {
|
|
19
|
+
readonly content: ReadonlyArray<
|
|
20
|
+
{ type: "text"; text: string } | { type: "image"; data: string; mimeType: string }
|
|
21
|
+
>;
|
|
22
|
+
readonly data?: Record<string, unknown>;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export interface ExamplePluginSchema {
|
|
26
|
+
readonly example: {
|
|
27
|
+
/** Round-trip primitive — returns `{ok:true, result:msg}`. */
|
|
28
|
+
echo(args: { msg: string }): Promise<ExampleBrowxaiResult>;
|
|
29
|
+
/** Sums two numeric args — returns `{ok:true, sum: a+b}`. */
|
|
30
|
+
add(args: { a: number; b: number }): Promise<ExampleBrowxaiResult>;
|
|
31
|
+
/** Argless tool — returns `{ok:true, iso, epochMs}`. */
|
|
32
|
+
now(args?: Record<string, never>): Promise<ExampleBrowxaiResult>;
|
|
33
|
+
};
|
|
34
|
+
}
|