@tokentop/plugin-sdk 1.0.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 +121 -0
- package/dist/helpers/auth.d.ts +15 -0
- package/dist/helpers/auth.d.ts.map +1 -0
- package/dist/helpers/create.d.ts +11 -0
- package/dist/helpers/create.d.ts.map +1 -0
- package/dist/helpers/index.d.ts +4 -0
- package/dist/helpers/index.d.ts.map +1 -0
- package/dist/helpers/index.js +182 -0
- package/dist/helpers/version.d.ts +6 -0
- package/dist/helpers/version.d.ts.map +1 -0
- package/dist/index-y0tp0jk5.js +15 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/testing/harness.d.ts +49 -0
- package/dist/testing/harness.d.ts.map +1 -0
- package/dist/testing/index.d.ts +3 -0
- package/dist/testing/index.d.ts.map +1 -0
- package/dist/testing/index.js +134 -0
- package/dist/types/agent.d.ts +89 -0
- package/dist/types/agent.d.ts.map +1 -0
- package/dist/types/context.d.ts +93 -0
- package/dist/types/context.d.ts.map +1 -0
- package/dist/types/index.d.ts +21 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +8 -0
- package/dist/types/notification.d.ts +33 -0
- package/dist/types/notification.d.ts.map +1 -0
- package/dist/types/plugin.d.ts +167 -0
- package/dist/types/plugin.d.ts.map +1 -0
- package/dist/types/provider.d.ts +138 -0
- package/dist/types/provider.d.ts.map +1 -0
- package/dist/types/theme.d.ts +53 -0
- package/dist/types/theme.d.ts.map +1 -0
- package/package.json +70 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025-present Nigel Bazzeghin
|
|
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,121 @@
|
|
|
1
|
+
# @tokentop/plugin-sdk
|
|
2
|
+
|
|
3
|
+
[](https://www.typescriptlang.org/)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
SDK for building [tokentop](https://github.com/tokentopapp/tokentop) plugins. Types, helpers, and a test harness for provider, agent, theme, and notification plugins.
|
|
7
|
+
|
|
8
|
+
## Install
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
bun add @tokentop/plugin-sdk
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Quick Example
|
|
15
|
+
|
|
16
|
+
```typescript
|
|
17
|
+
import {
|
|
18
|
+
createProviderPlugin,
|
|
19
|
+
apiKeyCredential,
|
|
20
|
+
credentialFound,
|
|
21
|
+
credentialMissing,
|
|
22
|
+
} from '@tokentop/plugin-sdk';
|
|
23
|
+
|
|
24
|
+
export default createProviderPlugin({
|
|
25
|
+
id: 'my-provider',
|
|
26
|
+
type: 'provider',
|
|
27
|
+
name: 'My Provider',
|
|
28
|
+
version: '1.0.0',
|
|
29
|
+
meta: { brandColor: '#3b82f6' },
|
|
30
|
+
permissions: {
|
|
31
|
+
network: { enabled: true, allowedDomains: ['api.example.com'] },
|
|
32
|
+
env: { read: true, vars: ['MY_API_KEY'] },
|
|
33
|
+
},
|
|
34
|
+
capabilities: {
|
|
35
|
+
usageLimits: false,
|
|
36
|
+
apiRateLimits: false,
|
|
37
|
+
tokenUsage: false,
|
|
38
|
+
actualCosts: true,
|
|
39
|
+
},
|
|
40
|
+
auth: {
|
|
41
|
+
async discover(ctx) {
|
|
42
|
+
const key = ctx.authSources.env.get('MY_API_KEY');
|
|
43
|
+
return key ? credentialFound(apiKeyCredential(key)) : credentialMissing();
|
|
44
|
+
},
|
|
45
|
+
isConfigured: (creds) => !!creds.apiKey,
|
|
46
|
+
},
|
|
47
|
+
async fetchUsage(ctx) {
|
|
48
|
+
const resp = await ctx.http.fetch('https://api.example.com/usage', {
|
|
49
|
+
headers: { Authorization: `Bearer ${ctx.credentials.apiKey}` },
|
|
50
|
+
});
|
|
51
|
+
const data = await resp.json();
|
|
52
|
+
return { fetchedAt: Date.now(), cost: { total: data.total, currency: 'USD', source: 'api' } };
|
|
53
|
+
},
|
|
54
|
+
});
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Plugin Types
|
|
58
|
+
|
|
59
|
+
| Type | Interface | Purpose |
|
|
60
|
+
|------|-----------|---------|
|
|
61
|
+
| `provider` | `ProviderPlugin` | Fetch usage data from AI model providers |
|
|
62
|
+
| `agent` | `AgentPlugin` | Parse coding agent sessions for token tracking |
|
|
63
|
+
| `theme` | `ThemePlugin` | Color schemes for the TUI |
|
|
64
|
+
| `notification` | `NotificationPlugin` | Alert delivery (Slack, Discord, terminal bell) |
|
|
65
|
+
|
|
66
|
+
## Subpath Exports
|
|
67
|
+
|
|
68
|
+
| Import | Contents |
|
|
69
|
+
|--------|----------|
|
|
70
|
+
| `@tokentop/plugin-sdk` | Everything (types + helpers) |
|
|
71
|
+
| `@tokentop/plugin-sdk/types` | Type definitions only |
|
|
72
|
+
| `@tokentop/plugin-sdk/helpers` | `createPlugin` helpers, auth helpers, version utils |
|
|
73
|
+
| `@tokentop/plugin-sdk/testing` | Test harness and mock factories |
|
|
74
|
+
|
|
75
|
+
## Testing
|
|
76
|
+
|
|
77
|
+
Test plugins without running tokentop:
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { createTestContext } from '@tokentop/plugin-sdk/testing';
|
|
81
|
+
import plugin from './src/index.ts';
|
|
82
|
+
|
|
83
|
+
const ctx = createTestContext({
|
|
84
|
+
env: { MY_API_KEY: 'test-key' },
|
|
85
|
+
httpMocks: {
|
|
86
|
+
'https://api.example.com/usage': {
|
|
87
|
+
status: 200,
|
|
88
|
+
body: { total: 4.50 },
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
const creds = await plugin.auth.discover(ctx);
|
|
94
|
+
assert(creds.ok);
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Publishing
|
|
98
|
+
|
|
99
|
+
| Plugin type | npm package name |
|
|
100
|
+
|-------------|------------------|
|
|
101
|
+
| Provider | `@tokentop/provider-<name>` |
|
|
102
|
+
| Agent | `@tokentop/agent-<name>` |
|
|
103
|
+
| Theme | `@tokentop/theme-<name>` |
|
|
104
|
+
| Notification | `@tokentop/notification-<name>` |
|
|
105
|
+
|
|
106
|
+
## Versioning
|
|
107
|
+
|
|
108
|
+
| Version | What it is |
|
|
109
|
+
|---------|------------|
|
|
110
|
+
| SDK semver (`0.1.0`) | Package version on npm. Normal semver rules. |
|
|
111
|
+
| `apiVersion` (`2`) | Plugin contract version. Core checks at load time. Bumped rarely. |
|
|
112
|
+
|
|
113
|
+
Use `CURRENT_API_VERSION` and `isCompatible()` to check compatibility. The `createProviderPlugin()` / `createAgentPlugin()` / etc. helpers stamp `apiVersion` automatically.
|
|
114
|
+
|
|
115
|
+
## Documentation
|
|
116
|
+
|
|
117
|
+
See [docs/plugin-development.md](docs/plugin-development.md) for the full API reference covering all plugin types, credential discovery, lifecycle hooks, configuration schemas, and testing patterns.
|
|
118
|
+
|
|
119
|
+
## License
|
|
120
|
+
|
|
121
|
+
MIT
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Credentials, CredentialResult } from '../types/provider.ts';
|
|
2
|
+
export declare function apiKeyCredential(key: string, source?: Credentials['source']): Credentials;
|
|
3
|
+
export declare function oauthCredential(accessToken: string, options?: {
|
|
4
|
+
refreshToken?: string;
|
|
5
|
+
expiresAt?: number;
|
|
6
|
+
accountId?: string;
|
|
7
|
+
source?: Credentials['source'];
|
|
8
|
+
}): Credentials;
|
|
9
|
+
export declare function credentialFound(credentials: Credentials): CredentialResult;
|
|
10
|
+
export declare function credentialMissing(message?: string): CredentialResult;
|
|
11
|
+
export declare function credentialExpired(message?: string): CredentialResult;
|
|
12
|
+
export declare function credentialInvalid(message?: string): CredentialResult;
|
|
13
|
+
export declare function credentialError(message: string): CredentialResult;
|
|
14
|
+
export declare function isTokenExpired(expiresAt: number | undefined, bufferMs?: number): boolean;
|
|
15
|
+
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/helpers/auth.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAoB,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE5F,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,GAAE,WAAW,CAAC,QAAQ,CAAS,GAAG,WAAW,CAEhG;AAED,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,EACnB,OAAO,CAAC,EAAE;IACR,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAC;CAChC,GACA,WAAW,CAMb;AAED,wBAAgB,eAAe,CAAC,WAAW,EAAE,WAAW,GAAG,gBAAgB,CAE1E;AAED,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAEpE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAEpE;AAED,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAEpE;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,gBAAgB,CAEjE;AAED,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,SAAgB,GAAG,OAAO,CAG/F"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ProviderPlugin } from '../types/provider.ts';
|
|
2
|
+
import type { AgentPlugin } from '../types/agent.ts';
|
|
3
|
+
import type { ThemePlugin } from '../types/theme.ts';
|
|
4
|
+
import type { NotificationPlugin } from '../types/notification.ts';
|
|
5
|
+
type WithoutApiVersion<T> = Omit<T, 'apiVersion'>;
|
|
6
|
+
export declare function createProviderPlugin(def: WithoutApiVersion<ProviderPlugin>): ProviderPlugin;
|
|
7
|
+
export declare function createAgentPlugin(def: WithoutApiVersion<AgentPlugin>): AgentPlugin;
|
|
8
|
+
export declare function createThemePlugin(def: WithoutApiVersion<ThemePlugin>): ThemePlugin;
|
|
9
|
+
export declare function createNotificationPlugin(def: WithoutApiVersion<NotificationPlugin>): NotificationPlugin;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=create.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.d.ts","sourceRoot":"","sources":["../../src/helpers/create.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,KAAK,iBAAiB,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC;AAiBlD,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,iBAAiB,CAAC,cAAc,CAAC,GAAG,cAAc,CAM3F;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,iBAAiB,CAAC,WAAW,CAAC,GAAG,WAAW,CAMlF;AAED,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,iBAAiB,CAAC,WAAW,CAAC,GAAG,WAAW,CAMlF;AAED,wBAAgB,wBAAwB,CAAC,GAAG,EAAE,iBAAiB,CAAC,kBAAkB,CAAC,GAAG,kBAAkB,CAMvG"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { createProviderPlugin, createAgentPlugin, createThemePlugin, createNotificationPlugin, } from './create.ts';
|
|
2
|
+
export { apiKeyCredential, oauthCredential, credentialFound, credentialMissing, credentialExpired, credentialInvalid, credentialError, isTokenExpired, } from './auth.ts';
|
|
3
|
+
export { SDK_VERSION, CURRENT_API_VERSION, isCompatible, assertCompatible, } from './version.ts';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/helpers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,GACzB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,cAAc,GACf,MAAM,WAAW,CAAC;AAEnB,OAAO,EACL,WAAW,EACX,mBAAmB,EACnB,YAAY,EACZ,gBAAgB,GACjB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CURRENT_API_VERSION
|
|
3
|
+
} from "../index-y0tp0jk5.js";
|
|
4
|
+
|
|
5
|
+
// src/helpers/create.ts
|
|
6
|
+
function validateBase(plugin) {
|
|
7
|
+
if (!plugin.id || typeof plugin.id !== "string") {
|
|
8
|
+
throw new Error('Plugin must have a non-empty string "id"');
|
|
9
|
+
}
|
|
10
|
+
if (!/^[a-z][a-z0-9-]*$/.test(plugin.id)) {
|
|
11
|
+
throw new Error(`Plugin id "${plugin.id}" must be kebab-case (lowercase letters, numbers, hyphens)`);
|
|
12
|
+
}
|
|
13
|
+
if (!plugin.name || typeof plugin.name !== "string") {
|
|
14
|
+
throw new Error('Plugin must have a non-empty string "name"');
|
|
15
|
+
}
|
|
16
|
+
if (!plugin.version || !/^\d+\.\d+\.\d+/.test(plugin.version)) {
|
|
17
|
+
throw new Error('Plugin must have a valid semver version (e.g. "1.0.0")');
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function createProviderPlugin(def) {
|
|
21
|
+
validateBase(def);
|
|
22
|
+
if (def.type !== "provider") {
|
|
23
|
+
throw new Error('createProviderPlugin requires type: "provider"');
|
|
24
|
+
}
|
|
25
|
+
return { ...def, apiVersion: CURRENT_API_VERSION };
|
|
26
|
+
}
|
|
27
|
+
function createAgentPlugin(def) {
|
|
28
|
+
validateBase(def);
|
|
29
|
+
if (def.type !== "agent") {
|
|
30
|
+
throw new Error('createAgentPlugin requires type: "agent"');
|
|
31
|
+
}
|
|
32
|
+
return { ...def, apiVersion: CURRENT_API_VERSION };
|
|
33
|
+
}
|
|
34
|
+
function createThemePlugin(def) {
|
|
35
|
+
validateBase(def);
|
|
36
|
+
if (def.type !== "theme") {
|
|
37
|
+
throw new Error('createThemePlugin requires type: "theme"');
|
|
38
|
+
}
|
|
39
|
+
return { ...def, apiVersion: CURRENT_API_VERSION };
|
|
40
|
+
}
|
|
41
|
+
function createNotificationPlugin(def) {
|
|
42
|
+
validateBase(def);
|
|
43
|
+
if (def.type !== "notification") {
|
|
44
|
+
throw new Error('createNotificationPlugin requires type: "notification"');
|
|
45
|
+
}
|
|
46
|
+
return { ...def, apiVersion: CURRENT_API_VERSION };
|
|
47
|
+
}
|
|
48
|
+
// src/helpers/auth.ts
|
|
49
|
+
function apiKeyCredential(key, source = "env") {
|
|
50
|
+
return { apiKey: key, source };
|
|
51
|
+
}
|
|
52
|
+
function oauthCredential(accessToken, options) {
|
|
53
|
+
const oauth = { accessToken };
|
|
54
|
+
if (options?.refreshToken !== undefined)
|
|
55
|
+
oauth.refreshToken = options.refreshToken;
|
|
56
|
+
if (options?.expiresAt !== undefined)
|
|
57
|
+
oauth.expiresAt = options.expiresAt;
|
|
58
|
+
if (options?.accountId !== undefined)
|
|
59
|
+
oauth.accountId = options.accountId;
|
|
60
|
+
return { oauth, source: options?.source ?? "external" };
|
|
61
|
+
}
|
|
62
|
+
function credentialFound(credentials) {
|
|
63
|
+
return { ok: true, credentials };
|
|
64
|
+
}
|
|
65
|
+
function credentialMissing(message) {
|
|
66
|
+
return { ok: false, reason: "missing", message };
|
|
67
|
+
}
|
|
68
|
+
function credentialExpired(message) {
|
|
69
|
+
return { ok: false, reason: "expired", message };
|
|
70
|
+
}
|
|
71
|
+
function credentialInvalid(message) {
|
|
72
|
+
return { ok: false, reason: "invalid", message };
|
|
73
|
+
}
|
|
74
|
+
function credentialError(message) {
|
|
75
|
+
return { ok: false, reason: "error", message };
|
|
76
|
+
}
|
|
77
|
+
function isTokenExpired(expiresAt, bufferMs = 5 * 60 * 1000) {
|
|
78
|
+
if (expiresAt === undefined)
|
|
79
|
+
return false;
|
|
80
|
+
return expiresAt <= Date.now() + bufferMs;
|
|
81
|
+
}
|
|
82
|
+
// package.json
|
|
83
|
+
var package_default = {
|
|
84
|
+
name: "@tokentop/plugin-sdk",
|
|
85
|
+
version: "1.0.0",
|
|
86
|
+
description: "SDK for building tokentop plugins — providers, agents, themes, and notifications",
|
|
87
|
+
type: "module",
|
|
88
|
+
main: "dist/index.js",
|
|
89
|
+
types: "dist/index.d.ts",
|
|
90
|
+
exports: {
|
|
91
|
+
".": {
|
|
92
|
+
types: "./dist/index.d.ts",
|
|
93
|
+
import: "./dist/index.js"
|
|
94
|
+
},
|
|
95
|
+
"./types": {
|
|
96
|
+
types: "./dist/types/index.d.ts",
|
|
97
|
+
import: "./dist/types/index.js"
|
|
98
|
+
},
|
|
99
|
+
"./helpers": {
|
|
100
|
+
types: "./dist/helpers/index.d.ts",
|
|
101
|
+
import: "./dist/helpers/index.js"
|
|
102
|
+
},
|
|
103
|
+
"./testing": {
|
|
104
|
+
types: "./dist/testing/index.d.ts",
|
|
105
|
+
import: "./dist/testing/index.js"
|
|
106
|
+
}
|
|
107
|
+
},
|
|
108
|
+
files: [
|
|
109
|
+
"dist",
|
|
110
|
+
"LICENSE",
|
|
111
|
+
"README.md"
|
|
112
|
+
],
|
|
113
|
+
scripts: {
|
|
114
|
+
build: "bun run build:types && bun run build:js",
|
|
115
|
+
"build:types": "tsc --emitDeclarationOnly",
|
|
116
|
+
"build:js": "bun build src/index.ts src/types/index.ts src/helpers/index.ts src/testing/index.ts --outdir dist --target node --format esm --splitting",
|
|
117
|
+
typecheck: "tsc --noEmit",
|
|
118
|
+
test: "bun test",
|
|
119
|
+
clean: "rm -rf dist",
|
|
120
|
+
prepublishOnly: "bun run clean && bun run build"
|
|
121
|
+
},
|
|
122
|
+
keywords: [
|
|
123
|
+
"tokentop",
|
|
124
|
+
"plugin",
|
|
125
|
+
"sdk",
|
|
126
|
+
"ai",
|
|
127
|
+
"llm",
|
|
128
|
+
"token-usage",
|
|
129
|
+
"cost-monitoring"
|
|
130
|
+
],
|
|
131
|
+
author: "Nigel Bazzeghin <nbazzeghin@gmail.com>",
|
|
132
|
+
license: "MIT",
|
|
133
|
+
repository: {
|
|
134
|
+
type: "git",
|
|
135
|
+
url: "https://github.com/tokentopapp/plugin-sdk.git"
|
|
136
|
+
},
|
|
137
|
+
publishConfig: {
|
|
138
|
+
access: "public",
|
|
139
|
+
registry: "https://registry.npmjs.org/"
|
|
140
|
+
},
|
|
141
|
+
homepage: "https://github.com/tokentopapp/tokentop",
|
|
142
|
+
engines: {
|
|
143
|
+
bun: ">=1.0.0"
|
|
144
|
+
},
|
|
145
|
+
devDependencies: {
|
|
146
|
+
"@types/bun": "latest",
|
|
147
|
+
"semantic-release": "^25.0.3",
|
|
148
|
+
typescript: "^5.7.0"
|
|
149
|
+
},
|
|
150
|
+
peerDependencies: {},
|
|
151
|
+
dependencies: {}
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
// src/helpers/version.ts
|
|
155
|
+
var SDK_VERSION = package_default.version;
|
|
156
|
+
function isCompatible(pluginApiVersion) {
|
|
157
|
+
return pluginApiVersion === CURRENT_API_VERSION;
|
|
158
|
+
}
|
|
159
|
+
function assertCompatible(pluginId, pluginApiVersion) {
|
|
160
|
+
if (!isCompatible(pluginApiVersion)) {
|
|
161
|
+
throw new Error(`Plugin "${pluginId}" requires API version ${pluginApiVersion}, ` + `but this SDK supports version ${CURRENT_API_VERSION}. ` + (pluginApiVersion > CURRENT_API_VERSION ? "Update tokentop to use this plugin." : "Update the plugin to the latest SDK."));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
export {
|
|
165
|
+
oauthCredential,
|
|
166
|
+
isTokenExpired,
|
|
167
|
+
isCompatible,
|
|
168
|
+
credentialMissing,
|
|
169
|
+
credentialInvalid,
|
|
170
|
+
credentialFound,
|
|
171
|
+
credentialExpired,
|
|
172
|
+
credentialError,
|
|
173
|
+
createThemePlugin,
|
|
174
|
+
createProviderPlugin,
|
|
175
|
+
createNotificationPlugin,
|
|
176
|
+
createAgentPlugin,
|
|
177
|
+
assertCompatible,
|
|
178
|
+
apiKeyCredential,
|
|
179
|
+
SDK_VERSION,
|
|
180
|
+
CURRENT_API_VERSION
|
|
181
|
+
};
|
|
182
|
+
export { createProviderPlugin, createAgentPlugin, createThemePlugin, createNotificationPlugin, apiKeyCredential, oauthCredential, credentialFound, credentialMissing, credentialExpired, credentialInvalid, credentialError, isTokenExpired, SDK_VERSION, isCompatible, assertCompatible };
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { CURRENT_API_VERSION } from '../types/plugin.ts';
|
|
2
|
+
export declare const SDK_VERSION: string;
|
|
3
|
+
export { CURRENT_API_VERSION };
|
|
4
|
+
export declare function isCompatible(pluginApiVersion: number): boolean;
|
|
5
|
+
export declare function assertCompatible(pluginId: string, pluginApiVersion: number): void;
|
|
6
|
+
//# sourceMappingURL=version.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version.d.ts","sourceRoot":"","sources":["../../src/helpers/version.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAGzD,eAAO,MAAM,WAAW,EAAE,MAAoB,CAAC;AAE/C,OAAO,EAAE,mBAAmB,EAAE,CAAC;AAE/B,wBAAgB,YAAY,CAAC,gBAAgB,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAUjF"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// src/types/plugin.ts
|
|
2
|
+
var CURRENT_API_VERSION = 2;
|
|
3
|
+
|
|
4
|
+
class PluginPermissionError extends Error {
|
|
5
|
+
pluginId;
|
|
6
|
+
permission;
|
|
7
|
+
constructor(pluginId, permission, message) {
|
|
8
|
+
super(`Plugin "${pluginId}" permission denied: ${message}`);
|
|
9
|
+
this.pluginId = pluginId;
|
|
10
|
+
this.permission = permission;
|
|
11
|
+
this.name = "PluginPermissionError";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export { CURRENT_API_VERSION, PluginPermissionError };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export type { PluginId, PluginType, PluginPermissions, PluginMeta, ConfigField, BasePlugin, PluginLifecycleContext, PluginLogger, PluginHttpClient, AuthSources, OpenCodeAuthEntry, PluginStorage, PluginContext, CredentialSource, Credentials, OAuthCredentials, RefreshedCredentials, CredentialResult, ProviderAuth, ProviderCapabilities, ModelPricing, ProviderPricing, UsageLimit, CostBreakdown, ProviderUsageData, ProviderFetchContext, ProviderPlugin, AgentConfig, AgentCapabilities, AgentCredentials, AgentProviderConfig, SessionParseOptions, SessionUsageData, ActivityUpdate, ActivityCallback, AgentFetchContext, AgentPlugin, ThemeColors, GaugeColors, ThemeComponents, ThemePlugin, NotificationSeverity, NotificationEventType, NotificationEvent, NotificationContext, NotificationPlugin, AnyPlugin, PluginByType, PluginOfType, } from './types/index.ts';
|
|
2
|
+
export { CURRENT_API_VERSION, PluginPermissionError } from './types/index.ts';
|
|
3
|
+
export { createProviderPlugin, createAgentPlugin, createThemePlugin, createNotificationPlugin, apiKeyCredential, oauthCredential, credentialFound, credentialMissing, credentialExpired, credentialInvalid, credentialError, isTokenExpired, SDK_VERSION, isCompatible, assertCompatible, } from './helpers/index.ts';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,YAAY,EACV,QAAQ,EACR,UAAU,EACV,iBAAiB,EACjB,UAAU,EACV,WAAW,EACX,UAAU,EACV,sBAAsB,EACtB,YAAY,EACZ,gBAAgB,EAChB,WAAW,EACX,iBAAiB,EACjB,aAAa,EACb,aAAa,EACb,gBAAgB,EAChB,WAAW,EACX,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,eAAe,EACf,UAAU,EACV,aAAa,EACb,iBAAiB,EACjB,oBAAoB,EACpB,cAAc,EACd,WAAW,EACX,iBAAiB,EACjB,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,gBAAgB,EAChB,iBAAiB,EACjB,WAAW,EACX,WAAW,EACX,WAAW,EACX,eAAe,EACf,WAAW,EACX,oBAAoB,EACpB,qBAAqB,EACrB,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,SAAS,EACT,YAAY,EACZ,YAAY,GACb,MAAM,kBAAkB,CAAC;AAE1B,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,kBAAkB,CAAC;AAG9E,OAAO,EACL,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,wBAAwB,EACxB,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,WAAW,EACX,YAAY,EACZ,gBAAgB,GACjB,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CURRENT_API_VERSION,
|
|
3
|
+
PluginPermissionError
|
|
4
|
+
} from "./index-y0tp0jk5.js";
|
|
5
|
+
import"./types/index.js";
|
|
6
|
+
import {
|
|
7
|
+
SDK_VERSION,
|
|
8
|
+
apiKeyCredential,
|
|
9
|
+
assertCompatible,
|
|
10
|
+
createAgentPlugin,
|
|
11
|
+
createNotificationPlugin,
|
|
12
|
+
createProviderPlugin,
|
|
13
|
+
createThemePlugin,
|
|
14
|
+
credentialError,
|
|
15
|
+
credentialExpired,
|
|
16
|
+
credentialFound,
|
|
17
|
+
credentialInvalid,
|
|
18
|
+
credentialMissing,
|
|
19
|
+
isCompatible,
|
|
20
|
+
isTokenExpired,
|
|
21
|
+
oauthCredential
|
|
22
|
+
} from "./helpers/index.js";
|
|
23
|
+
export {
|
|
24
|
+
oauthCredential,
|
|
25
|
+
isTokenExpired,
|
|
26
|
+
isCompatible,
|
|
27
|
+
credentialMissing,
|
|
28
|
+
credentialInvalid,
|
|
29
|
+
credentialFound,
|
|
30
|
+
credentialExpired,
|
|
31
|
+
credentialError,
|
|
32
|
+
createThemePlugin,
|
|
33
|
+
createProviderPlugin,
|
|
34
|
+
createNotificationPlugin,
|
|
35
|
+
createAgentPlugin,
|
|
36
|
+
assertCompatible,
|
|
37
|
+
apiKeyCredential,
|
|
38
|
+
SDK_VERSION,
|
|
39
|
+
PluginPermissionError,
|
|
40
|
+
CURRENT_API_VERSION
|
|
41
|
+
};
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { PluginContext } from '../types/context.ts';
|
|
2
|
+
import type { PluginLogger } from '../types/plugin.ts';
|
|
3
|
+
import type { ProviderFetchContext } from '../types/provider.ts';
|
|
4
|
+
import type { AgentFetchContext } from '../types/agent.ts';
|
|
5
|
+
import type { Credentials } from '../types/provider.ts';
|
|
6
|
+
export interface MockLogEntry {
|
|
7
|
+
level: 'debug' | 'info' | 'warn' | 'error';
|
|
8
|
+
message: string;
|
|
9
|
+
data?: Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
export interface MockLogger extends PluginLogger {
|
|
12
|
+
entries: MockLogEntry[];
|
|
13
|
+
clear(): void;
|
|
14
|
+
}
|
|
15
|
+
export declare function createMockLogger(): MockLogger;
|
|
16
|
+
export interface HttpMock {
|
|
17
|
+
status: number;
|
|
18
|
+
body?: unknown;
|
|
19
|
+
headers?: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
export interface MockHttpClientOptions {
|
|
22
|
+
mocks?: Record<string, HttpMock>;
|
|
23
|
+
defaultStatus?: number;
|
|
24
|
+
}
|
|
25
|
+
export declare function createMockHttpClient(options?: MockHttpClientOptions): {
|
|
26
|
+
calls: {
|
|
27
|
+
url: string;
|
|
28
|
+
init?: RequestInit;
|
|
29
|
+
}[];
|
|
30
|
+
fetch(url: string, init?: RequestInit): Promise<Response>;
|
|
31
|
+
};
|
|
32
|
+
export declare function createMockStorage(initial?: Record<string, string>): {
|
|
33
|
+
store: Map<string, string>;
|
|
34
|
+
get(key: string): Promise<string | null>;
|
|
35
|
+
set(key: string, value: string): Promise<void>;
|
|
36
|
+
delete(key: string): Promise<void>;
|
|
37
|
+
has(key: string): Promise<boolean>;
|
|
38
|
+
};
|
|
39
|
+
export interface TestContextOptions {
|
|
40
|
+
env?: Record<string, string>;
|
|
41
|
+
files?: Record<string, string>;
|
|
42
|
+
httpMocks?: Record<string, HttpMock>;
|
|
43
|
+
config?: Record<string, unknown>;
|
|
44
|
+
storage?: Record<string, string>;
|
|
45
|
+
}
|
|
46
|
+
export declare function createTestContext(options?: TestContextOptions): PluginContext;
|
|
47
|
+
export declare function createTestProviderFetchContext(credentials: Credentials, options?: TestContextOptions): ProviderFetchContext;
|
|
48
|
+
export declare function createTestAgentFetchContext(options?: TestContextOptions): AgentFetchContext;
|
|
49
|
+
//# sourceMappingURL=harness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"harness.d.ts","sourceRoot":"","sources":["../../src/testing/harness.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAC3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAMxD,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC9C,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,KAAK,IAAI,IAAI,CAAC;CACf;AAED,wBAAgB,gBAAgB,IAAI,UAAU,CAU7C;AAMD,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,MAAM,WAAW,qBAAqB;IACpC,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACjC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,qBAA0B;;aAC5C,MAAM;eAAS,WAAW;;eAIjC,MAAM,SAAS,WAAW,GAAG,OAAO,CAAC,QAAQ,CAAC;EAelE;AAMD,wBAAgB,iBAAiB,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;;aAI/C,MAAM;aACN,MAAM,SAAS,MAAM;gBAClB,MAAM;aACT,MAAM;EAExB;AAMD,MAAM,WAAW,kBAAkB;IACjC,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACjC,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAClC;AAED,wBAAgB,iBAAiB,CAAC,OAAO,GAAE,kBAAuB,GAAG,aAAa,CAuCjF;AAED,wBAAgB,8BAA8B,CAC5C,WAAW,EAAE,WAAW,EACxB,OAAO,GAAE,kBAAuB,GAC/B,oBAAoB,CAStB;AAED,wBAAgB,2BAA2B,CACzC,OAAO,GAAE,kBAAuB,GAC/B,iBAAiB,CAQnB"}
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { createMockLogger, createMockHttpClient, createMockStorage, createTestContext, createTestProviderFetchContext, createTestAgentFetchContext, } from './harness.ts';
|
|
2
|
+
export type { MockLogEntry, MockLogger, HttpMock, MockHttpClientOptions, TestContextOptions, } from './harness.ts';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/testing/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,8BAA8B,EAC9B,2BAA2B,GAC5B,MAAM,cAAc,CAAC;AAEtB,YAAY,EACV,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,cAAc,CAAC"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// src/testing/harness.ts
|
|
2
|
+
function createMockLogger() {
|
|
3
|
+
const entries = [];
|
|
4
|
+
return {
|
|
5
|
+
entries,
|
|
6
|
+
debug(message, data) {
|
|
7
|
+
entries.push({ level: "debug", message, data });
|
|
8
|
+
},
|
|
9
|
+
info(message, data) {
|
|
10
|
+
entries.push({ level: "info", message, data });
|
|
11
|
+
},
|
|
12
|
+
warn(message, data) {
|
|
13
|
+
entries.push({ level: "warn", message, data });
|
|
14
|
+
},
|
|
15
|
+
error(message, data) {
|
|
16
|
+
entries.push({ level: "error", message, data });
|
|
17
|
+
},
|
|
18
|
+
clear() {
|
|
19
|
+
entries.length = 0;
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function createMockHttpClient(options = {}) {
|
|
24
|
+
const calls = [];
|
|
25
|
+
return {
|
|
26
|
+
calls,
|
|
27
|
+
async fetch(url, init) {
|
|
28
|
+
calls.push({ url, init });
|
|
29
|
+
const mock = options.mocks?.[url];
|
|
30
|
+
if (mock) {
|
|
31
|
+
return new Response(mock.body !== undefined ? JSON.stringify(mock.body) : null, {
|
|
32
|
+
status: mock.status,
|
|
33
|
+
headers: { "Content-Type": "application/json", ...mock.headers }
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return new Response(null, { status: options.defaultStatus ?? 404 });
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
function createMockStorage(initial) {
|
|
41
|
+
const store = new Map(Object.entries(initial ?? {}));
|
|
42
|
+
return {
|
|
43
|
+
store,
|
|
44
|
+
async get(key) {
|
|
45
|
+
return store.get(key) ?? null;
|
|
46
|
+
},
|
|
47
|
+
async set(key, value) {
|
|
48
|
+
store.set(key, value);
|
|
49
|
+
},
|
|
50
|
+
async delete(key) {
|
|
51
|
+
store.delete(key);
|
|
52
|
+
},
|
|
53
|
+
async has(key) {
|
|
54
|
+
return store.has(key);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function createTestContext(options = {}) {
|
|
59
|
+
const logger = createMockLogger();
|
|
60
|
+
const http = createMockHttpClient({ mocks: options.httpMocks });
|
|
61
|
+
const storage = createMockStorage(options.storage);
|
|
62
|
+
const controller = new AbortController;
|
|
63
|
+
const envMap = options.env ?? {};
|
|
64
|
+
const fileMap = options.files ?? {};
|
|
65
|
+
return {
|
|
66
|
+
config: options.config ?? {},
|
|
67
|
+
logger,
|
|
68
|
+
http,
|
|
69
|
+
storage,
|
|
70
|
+
signal: controller.signal,
|
|
71
|
+
authSources: {
|
|
72
|
+
env: {
|
|
73
|
+
get(name) {
|
|
74
|
+
return envMap[name];
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
files: {
|
|
78
|
+
async readText(path) {
|
|
79
|
+
return fileMap[path] ?? null;
|
|
80
|
+
},
|
|
81
|
+
async readJson(path) {
|
|
82
|
+
const text = fileMap[path];
|
|
83
|
+
if (!text)
|
|
84
|
+
return null;
|
|
85
|
+
try {
|
|
86
|
+
return JSON.parse(text);
|
|
87
|
+
} catch {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
},
|
|
91
|
+
async exists(path) {
|
|
92
|
+
return path in fileMap;
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
opencode: {
|
|
96
|
+
async getProviderEntry(_key) {
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
},
|
|
100
|
+
platform: {
|
|
101
|
+
os: process.platform,
|
|
102
|
+
homedir: process.env.HOME ?? "/home/test",
|
|
103
|
+
arch: process.arch
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
function createTestProviderFetchContext(credentials, options = {}) {
|
|
109
|
+
const ctx = createTestContext(options);
|
|
110
|
+
return {
|
|
111
|
+
credentials,
|
|
112
|
+
http: ctx.http,
|
|
113
|
+
logger: ctx.logger,
|
|
114
|
+
config: ctx.config,
|
|
115
|
+
signal: ctx.signal
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function createTestAgentFetchContext(options = {}) {
|
|
119
|
+
const ctx = createTestContext(options);
|
|
120
|
+
return {
|
|
121
|
+
http: ctx.http,
|
|
122
|
+
logger: ctx.logger,
|
|
123
|
+
config: ctx.config,
|
|
124
|
+
signal: ctx.signal
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
export {
|
|
128
|
+
createTestProviderFetchContext,
|
|
129
|
+
createTestContext,
|
|
130
|
+
createTestAgentFetchContext,
|
|
131
|
+
createMockStorage,
|
|
132
|
+
createMockLogger,
|
|
133
|
+
createMockHttpClient
|
|
134
|
+
};
|