@keemakr/operator-sdk 0.3.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/package.json +1 -1
- package/src/conformance/index.ts +9 -0
- package/src/index.ts +55 -0
- package/src/manifest.ts +21 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@keemakr/operator-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.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/conformance/index.ts
CHANGED
|
@@ -68,6 +68,15 @@ export async function runConformance(
|
|
|
68
68
|
!manifest.auth_kind || provider.authKind === manifest.auth_kind,
|
|
69
69
|
`code '${provider.authKind}' vs manifest '${manifest.auth_kind ?? '—'}'`,
|
|
70
70
|
);
|
|
71
|
+
// The credential alias is a reviewed dependency: when either side declares
|
|
72
|
+
// it, both must, and they must agree (a code-only alias would ride a
|
|
73
|
+
// connection reviewers never saw).
|
|
74
|
+
add(
|
|
75
|
+
'credential-alias',
|
|
76
|
+
'credential alias matches the manifest (when either declares it)',
|
|
77
|
+
(provider.credentialProvider ?? null) === (manifest.credential_provider ?? null),
|
|
78
|
+
`code '${provider.credentialProvider ?? '—'}' vs manifest '${manifest.credential_provider ?? '—'}'`,
|
|
79
|
+
);
|
|
71
80
|
|
|
72
81
|
// 6 — code may not claim MORE network than the reviewed manifest.
|
|
73
82
|
const undeclared = (provider.allowedDomains ?? []).filter(
|
package/src/index.ts
CHANGED
|
@@ -100,6 +100,24 @@ export interface ConnectField {
|
|
|
100
100
|
help?: string;
|
|
101
101
|
}
|
|
102
102
|
|
|
103
|
+
// Outcome of a connect-time (or on-demand) health probe. `status` is the user-
|
|
104
|
+
// facing vocabulary the Hub renders: 'connected' (probe passed), 'needs_rescope'
|
|
105
|
+
// (OAuth completed but the granted scopes can't run this provider's operations —
|
|
106
|
+
// e.g. Google's granular-consent checkboxes were left unticked), 'no_mailbox'
|
|
107
|
+
// (the account exists but has no mailbox/service behind it — a Workspace account
|
|
108
|
+
// on a Microsoft-mail domain), 'unusable' (probe failed for another reason).
|
|
109
|
+
export interface ProbeResult {
|
|
110
|
+
status: 'connected' | 'needs_rescope' | 'no_mailbox' | 'unusable';
|
|
111
|
+
/** One human-readable sentence for the Hub's status chip. */
|
|
112
|
+
detail?: string;
|
|
113
|
+
/** Scopes the credential actually carries, when the probe can read them. */
|
|
114
|
+
grantedScopes?: string[];
|
|
115
|
+
/** Probed account identity (e.g. the mailbox email) — becomes account_label. */
|
|
116
|
+
accountLabel?: string | null;
|
|
117
|
+
/** Extra provider facts worth persisting under meta.probe. */
|
|
118
|
+
meta?: Record<string, unknown>;
|
|
119
|
+
}
|
|
120
|
+
|
|
103
121
|
export interface ConnectionProvider {
|
|
104
122
|
provider: string;
|
|
105
123
|
displayName: string;
|
|
@@ -112,6 +130,29 @@ export interface ConnectionProvider {
|
|
|
112
130
|
// Connect-path maturity. Omitted ⇒ 'ready'. See Maturity above.
|
|
113
131
|
maturity?: Maturity;
|
|
114
132
|
|
|
133
|
+
// NOTE: a connection's scope (personal 'user' vs org-shared 'tenant') is NOT
|
|
134
|
+
// declared on the adapter. The live value is connections_registry.connection_mode
|
|
135
|
+
// (the platform-controlled overlay + rollback lever). Marketplace connectors
|
|
136
|
+
// seed it by declaring `connection_mode` in the MANIFEST (first publish only —
|
|
137
|
+
// the registry column is authoritative afterward, and reclassifying a live
|
|
138
|
+
// provider is a guarded staff console action). Built-ins still seed from
|
|
139
|
+
// registry-state's DEFAULT_USER_MODE_PROVIDERS, which stays the fail-closed
|
|
140
|
+
// fallback for unreadable registry reads.
|
|
141
|
+
|
|
142
|
+
// OAuth scopes this provider's operations actually NEED — unlike `scopes`
|
|
143
|
+
// (display-only), these are compared against the granted scope string by the
|
|
144
|
+
// connect-time probe; missing entries mark the connection 'needs_rescope'.
|
|
145
|
+
requiredScopes?: string[];
|
|
146
|
+
|
|
147
|
+
// Connect-time health probe: one cheap read (a profile fetch) that proves the
|
|
148
|
+
// credential can actually operate, run after the OAuth reports success and on
|
|
149
|
+
// demand from the Hub's "Check connection". Omitted ⇒ the connection is
|
|
150
|
+
// trusted as-is (status stays whatever the OAuth layer reported).
|
|
151
|
+
probe?(
|
|
152
|
+
cred: { accessToken: string; meta: Record<string, unknown> },
|
|
153
|
+
ctx?: OperationContext,
|
|
154
|
+
): Promise<ProbeResult>;
|
|
155
|
+
|
|
115
156
|
// Audience classification — see ConnectorSurface. Drives whether the end-user
|
|
116
157
|
// client surfaces this connector and how. Optional in the type for now so
|
|
117
158
|
// existing/external adapters compile through the SDK bump; defineProvider warns
|
|
@@ -130,6 +171,17 @@ export interface ConnectionProvider {
|
|
|
130
171
|
// omit it (first-party).
|
|
131
172
|
publisher?: string;
|
|
132
173
|
|
|
174
|
+
// Credential alias — the agent-tool chain's "one key opens many doors" seam.
|
|
175
|
+
// A connector that fronts one facet of a wider platform (an Apify actor, a
|
|
176
|
+
// Composio toolkit) declares the provider whose TENANT CONNECTION it rides:
|
|
177
|
+
// when a tenant has no row for THIS provider, getConnection falls back to the
|
|
178
|
+
// alias provider's row (tenant connects 'apify' once; every actor connector
|
|
179
|
+
// works). A tenant-pasted key for this provider still wins — the alias is the
|
|
180
|
+
// fallback, not the override. Refresh semantics follow the ALIAS provider's
|
|
181
|
+
// adapter. One hop only; the alias must name a concrete provider, never
|
|
182
|
+
// another aliased one.
|
|
183
|
+
credentialProvider?: string;
|
|
184
|
+
|
|
133
185
|
// Inline connect-form spec for api_key / app_password shapes. Omitted by pure
|
|
134
186
|
// oauth2 adapters (they render a Connect button instead). For a dual-mode
|
|
135
187
|
// provider (WordPress), this describes the NON-oauth fallback form; the UI
|
|
@@ -193,6 +245,9 @@ export interface ConnectionProvider {
|
|
|
193
245
|
// sees it. Keep `call` pure-ish: do the request, return JSON-serializable data.
|
|
194
246
|
export interface ConnectionOperation {
|
|
195
247
|
description?: string;
|
|
248
|
+
// Platform-only provider primitive. It remains available to trusted internal callers that
|
|
249
|
+
// invoke the adapter directly, but is omitted from catalogs and agent/user operation surfaces.
|
|
250
|
+
internal?: boolean;
|
|
196
251
|
// Access class, for grant scoping + install consent. Omitted ⇒ 'write' (the
|
|
197
252
|
// most restrictive assumption: unlabeled ops require the write scope and are
|
|
198
253
|
// listed as writes on the consent screen).
|
package/src/manifest.ts
CHANGED
|
@@ -46,6 +46,19 @@ export const connectorManifestSchema = z
|
|
|
46
46
|
// publish gate. Optional (the adapter is authoritative); declaring it lets
|
|
47
47
|
// the upload preview show it before any code runs.
|
|
48
48
|
auth_kind: z.enum(['oauth2', 'api_key', 'app_password']).optional(),
|
|
49
|
+
// OWNERSHIP axis (orthogonal to `surface`): 'user' = each member connects
|
|
50
|
+
// their OWN account (one row per member, invisible to everyone else — a
|
|
51
|
+
// personal mailbox/drive/calendar); 'tenant' = one org-shared connection.
|
|
52
|
+
// Declare 'user' whenever the credential is one person's own account.
|
|
53
|
+
//
|
|
54
|
+
// Contract: this value SEEDS connections_registry.connection_mode at FIRST
|
|
55
|
+
// publish only — the platform column is authoritative afterward. Changing
|
|
56
|
+
// it in a later version raises a publish-diff warning and does NOT apply;
|
|
57
|
+
// live reclassification is a guarded staff console action (adopt/clean-cut).
|
|
58
|
+
// NEVER make this required, and never make the schema strict: stored
|
|
59
|
+
// manifests of already-published versions are re-parsed with the current
|
|
60
|
+
// schema at every publish, and only a defaulted optional field survives that.
|
|
61
|
+
connection_mode: z.enum(['tenant', 'user']).default('tenant'),
|
|
49
62
|
// The operator-sdk contract version the connector targets (semver).
|
|
50
63
|
sdk_version: z.string().regex(/^\d+\.\d+\.\d+$/, 'sdk_version must be exact semver'),
|
|
51
64
|
// Module (relative path inside the bundle) whose named export is the
|
|
@@ -92,6 +105,14 @@ export const connectorManifestSchema = z
|
|
|
92
105
|
allowed_domains: z
|
|
93
106
|
.array(z.string().regex(domainPattern, 'each entry is a bare host or *.host, optional :port'))
|
|
94
107
|
.min(1, 'declare at least one allowed domain'),
|
|
108
|
+
// Credential alias (see ConnectionProvider.credentialProvider): the provider
|
|
109
|
+
// whose tenant connection this connector rides when the tenant has not
|
|
110
|
+
// connected THIS provider directly. Declared here so reviewers see the
|
|
111
|
+
// dependency; the adapter's copy is authoritative at runtime.
|
|
112
|
+
credential_provider: z
|
|
113
|
+
.string()
|
|
114
|
+
.regex(kebab, 'credential_provider must be a lowercase-kebab provider key')
|
|
115
|
+
.optional(),
|
|
95
116
|
// Connector-level config keys the platform must supply (resolved from the
|
|
96
117
|
// encrypted config store — values are set by staff at publish, never bundled).
|
|
97
118
|
env: z
|