@keemakr/operator-sdk 0.2.0 → 0.3.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/package.json +1 -1
- package/src/index.ts +33 -0
- package/src/manifest.ts +46 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keemakr/operator-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "The keemakr connector contract: defineProvider + ConnectionProvider/ConnectionOperation types + OperationContext (governed fetch) + the connector manifest schema, shared by keemakr-core's built-in adapters and external connector repos. One shape, two consumers.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/src/index.ts
CHANGED
|
@@ -22,6 +22,23 @@ export type AuthKind = 'oauth2' | 'api_key' | 'app_password';
|
|
|
22
22
|
// to 'ready'), so legacy adapters stay connectable until told otherwise.
|
|
23
23
|
export type Maturity = 'ready' | 'coming_soon';
|
|
24
24
|
|
|
25
|
+
// Who a connector is FOR — the audience axis the end-user client uses to decide
|
|
26
|
+
// whether to surface it, and how. Classify EVERY connector (defineProvider will
|
|
27
|
+
// enforce this) so the client catalog never conflates the three kinds:
|
|
28
|
+
// 'user-account' → the tenant's OWN account; connect/disconnect is the point.
|
|
29
|
+
// Shown in the end-user connections hub (Gmail, Slack, Stripe,
|
|
30
|
+
// HubSpot, social channels).
|
|
31
|
+
// 'agent-tool' → infrastructure an AGENT uses to do a task, not a personal
|
|
32
|
+
// account. The platform may hold a shared key; a tenant may
|
|
33
|
+
// override with their own. NEVER a standalone hub card — it
|
|
34
|
+
// surfaces only via the install card of an agent that declares
|
|
35
|
+
// it (Apollo, Hunter, Clearbit — enrichment/analytics/scraping).
|
|
36
|
+
// 'internal' → platform plumbing, or a dormant connector with no operations
|
|
37
|
+
// and no consumer. Never shown to end users (e.g. agent-sessions;
|
|
38
|
+
// op-less stubs — also keep those at maturity:'coming_soon').
|
|
39
|
+
// See docs/architecture/05 + 15 and the AGENTS.md "Connectors" convention.
|
|
40
|
+
export type ConnectorSurface = 'user-account' | 'agent-tool' | 'internal';
|
|
41
|
+
|
|
25
42
|
export interface TokenSet {
|
|
26
43
|
accessToken: string;
|
|
27
44
|
refreshToken?: string | null;
|
|
@@ -95,6 +112,12 @@ export interface ConnectionProvider {
|
|
|
95
112
|
// Connect-path maturity. Omitted ⇒ 'ready'. See Maturity above.
|
|
96
113
|
maturity?: Maturity;
|
|
97
114
|
|
|
115
|
+
// Audience classification — see ConnectorSurface. Drives whether the end-user
|
|
116
|
+
// client surfaces this connector and how. Optional in the type for now so
|
|
117
|
+
// existing/external adapters compile through the SDK bump; defineProvider warns
|
|
118
|
+
// when omitted and this tightens to required once every built-in declares it.
|
|
119
|
+
surface?: ConnectorSurface;
|
|
120
|
+
|
|
98
121
|
// Egress allowlist: the ONLY hosts this connector's operations/test may reach
|
|
99
122
|
// through ctx.fetch. Bare hostname for an exact match ('api.acme.com') or a
|
|
100
123
|
// wildcard for subdomains ('*.acme.com' — does NOT match the apex; list it
|
|
@@ -267,6 +290,16 @@ export function defineProvider(p: ConnectionProvider): ConnectionProvider {
|
|
|
267
290
|
if (typeof p.test !== 'function') {
|
|
268
291
|
throw new Error(`connections: provider '${p.provider}' must implement test()`);
|
|
269
292
|
}
|
|
293
|
+
if (!p.surface) {
|
|
294
|
+
// Nudge, not throw (yet): the built-ins all declare `surface`, but external/marketplace
|
|
295
|
+
// connectors (separate repos) haven't adopted it. Tightening to a hard throw + a required
|
|
296
|
+
// field is gated on adding `surface` to the connector manifest schema.
|
|
297
|
+
console.warn(
|
|
298
|
+
`connections: provider '${p.provider}' does not declare surface ` +
|
|
299
|
+
`('user-account' | 'agent-tool' | 'internal') — classify it so the client catalog knows ` +
|
|
300
|
+
`whether and how to show it. See the AGENTS.md "Connectors" convention.`,
|
|
301
|
+
);
|
|
302
|
+
}
|
|
270
303
|
if (p.operations && Object.keys(p.operations).length > 0 && !p.allowedDomains?.length) {
|
|
271
304
|
// Warn, don't throw: built-ins are grandfathered on ambient fetch. The
|
|
272
305
|
// marketplace publish gate REQUIRES allowed_domains in the manifest, so
|
package/src/manifest.ts
CHANGED
|
@@ -59,9 +59,24 @@ export const connectorManifestSchema = z
|
|
|
59
59
|
// tenant's credential — which is why remote connectors require explicit
|
|
60
60
|
// per-connection consent before any call.
|
|
61
61
|
runtime_url: z.string().url().max(500).optional(),
|
|
62
|
+
// Lane 'mcp': the author points at a remote Model Context Protocol server
|
|
63
|
+
// instead of writing operation bodies. Each declared operation forwards to
|
|
64
|
+
// that server's `tools/call` over Streamable HTTP, driven through the same
|
|
65
|
+
// governed fetch as Lane B. `url` is https-only and author-declared (never
|
|
66
|
+
// tenant-supplied); `auth` is 'injected' only in v1 — core vaults the
|
|
67
|
+
// tenant's credential and rides it on a transport header, never in the tool
|
|
68
|
+
// args. ('server_managed', where the MCP server holds its own upstream
|
|
69
|
+
// OAuth, is reserved for a later, higher-tier release.)
|
|
70
|
+
mcp: z
|
|
71
|
+
.object({
|
|
72
|
+
url: z.string().url().max(500),
|
|
73
|
+
auth: z.enum(['injected']),
|
|
74
|
+
})
|
|
75
|
+
.optional(),
|
|
62
76
|
// Remote connectors have no adapter code in core, so their connect form is
|
|
63
77
|
// declared HERE (vendored connectors keep connectFields in code — the
|
|
64
|
-
// adapter stays the single source of truth for Lane A).
|
|
78
|
+
// adapter stays the single source of truth for Lane A). MCP connectors are
|
|
79
|
+
// the same: no adapter code, so the form lives here too.
|
|
65
80
|
connect_fields: z
|
|
66
81
|
.array(
|
|
67
82
|
z.object({
|
|
@@ -91,10 +106,19 @@ export const connectorManifestSchema = z
|
|
|
91
106
|
changelog: z.string().max(5000).optional(),
|
|
92
107
|
})
|
|
93
108
|
.superRefine((m, ctx) => {
|
|
94
|
-
|
|
109
|
+
const lanes = [m.entrypoint, m.runtime_url, m.mcp].filter((v) => v != null).length;
|
|
110
|
+
if (lanes === 0) {
|
|
111
|
+
ctx.addIssue({
|
|
112
|
+
code: 'custom',
|
|
113
|
+
message:
|
|
114
|
+
'declare exactly one lane: an entrypoint (vendored, Lane A), a runtime_url (remote, Lane B), or an mcp endpoint (remote MCP)',
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
if (lanes > 1) {
|
|
95
118
|
ctx.addIssue({
|
|
96
119
|
code: 'custom',
|
|
97
|
-
message:
|
|
120
|
+
message:
|
|
121
|
+
'declare exactly one lane — entrypoint, runtime_url, and mcp are mutually exclusive',
|
|
98
122
|
});
|
|
99
123
|
}
|
|
100
124
|
if (m.runtime_url && !m.runtime_url.startsWith('https://')) {
|
|
@@ -116,6 +140,25 @@ export const connectorManifestSchema = z
|
|
|
116
140
|
'remote connectors must declare connect_fields (there is no adapter code to own the form)',
|
|
117
141
|
});
|
|
118
142
|
}
|
|
143
|
+
if (m.mcp && !m.mcp.url.startsWith('https://')) {
|
|
144
|
+
ctx.addIssue({ code: 'custom', path: ['mcp', 'url'], message: 'mcp.url must be https' });
|
|
145
|
+
}
|
|
146
|
+
if (m.mcp && m.auth_kind === 'oauth2') {
|
|
147
|
+
ctx.addIssue({
|
|
148
|
+
code: 'custom',
|
|
149
|
+
path: ['auth_kind'],
|
|
150
|
+
message:
|
|
151
|
+
'mcp connectors are api_key/app_password only — core injects the vaulted credential on a transport header, it does not broker an author-owned OAuth dance',
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
if (m.mcp && (!m.connect_fields || m.connect_fields.length === 0)) {
|
|
155
|
+
ctx.addIssue({
|
|
156
|
+
code: 'custom',
|
|
157
|
+
path: ['connect_fields'],
|
|
158
|
+
message:
|
|
159
|
+
'mcp connectors must declare connect_fields (there is no adapter code to own the form)',
|
|
160
|
+
});
|
|
161
|
+
}
|
|
119
162
|
});
|
|
120
163
|
|
|
121
164
|
export type ConnectorOperationDeclaration = z.infer<typeof connectorOperationDeclaration>;
|