@clawnify/connections 0.1.0 → 0.1.2

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/dist/index.d.ts CHANGED
@@ -30,6 +30,23 @@ interface CredentialBinding {
30
30
  successful: boolean;
31
31
  }>;
32
32
  listConnected(orgId: string): Promise<string[]>;
33
+ searchActions(query: string, service: string | null, limit: number): Promise<ActionMatch[]>;
34
+ }
35
+ /**
36
+ * One action from the broker catalog. The `slug` feeds `connect(service).run(slug, body)`;
37
+ * `inputSchema` is the JSON Schema for `body`. Returned best-first — `[0]` is the
38
+ * canonical match. Discovery is broker-agnostic (Composio today; Arcade/Nango
39
+ * expose the same search shape) and separable from execution. See docs §16.
40
+ */
41
+ interface ActionMatch {
42
+ /** Toolkit/integration slug — pass to connect(service). */
43
+ service: string;
44
+ /** Action slug — pass to connect(service).run(slug, body). */
45
+ slug: string;
46
+ name: string;
47
+ description: string;
48
+ /** JSON Schema for the request body, or null if the catalog omits it. */
49
+ inputSchema: Record<string, unknown> | null;
33
50
  }
34
51
  /** The slice of a worker's `env` the SDK reads. */
35
52
  interface ConnectionsEnv {
@@ -90,6 +107,24 @@ interface GenericClient {
90
107
  */
91
108
  declare function connect<K extends keyof ServiceClients>(service: K, env: ConnectionsEnv, orgId?: string): ServiceClients[K];
92
109
  declare function connect(service: string, env: ConnectionsEnv, orgId?: string): GenericClient;
110
+ /**
111
+ * Search the broker action catalog for the right action to call, returned
112
+ * best-first with each action's input schema (the request body). The default
113
+ * way to use the long tail of integrations: search → read `inputSchema` →
114
+ * `connect(service).run(slug, body)`, with no per-integration package code.
115
+ *
116
+ * Broker-agnostic — the active broker's own search backs it (Composio today).
117
+ * `[0]` is the canonical match. Catalog metadata, so it works without an org
118
+ * id; needs the in-process CREDENTIALS binding or CLAWNIFY_TOKEN. See docs §16.
119
+ *
120
+ * @example
121
+ * const [best] = await searchActions("post a message to slack", env);
122
+ * if (best) await connect(best.service, env).run(best.slug, { channel, text });
123
+ */
124
+ declare function searchActions(query: string, env: ConnectionsEnv, opts?: {
125
+ service?: string;
126
+ limit?: number;
127
+ }): Promise<ActionMatch[]>;
93
128
  /** Read an injected provider key / secret env var. Returns null when absent. */
94
129
  declare function secret(name: string, env: ConnectionsEnv): string | null;
95
130
  /** True when a usable credential exists for this service right now. */
@@ -126,4 +161,4 @@ interface DescribeEntry {
126
161
  */
127
162
  declare function describe(env: ConnectionsEnv, orgId?: string, requires?: RequireSpec[]): Promise<DescribeEntry[]>;
128
163
 
129
- export { type ConnectionsEnv, type CredentialBinding, type DescribeEntry, type GenericClient, type RequireSpec, clawnifyBinding, connect, describe, isConnected, secret };
164
+ export { type ActionMatch, type ConnectionsEnv, type CredentialBinding, type DescribeEntry, type GenericClient, type RequireSpec, clawnifyBinding, connect, describe, isConnected, searchActions, secret };
package/dist/index.js CHANGED
@@ -38,6 +38,16 @@ function clawnifyBinding(opts) {
38
38
  if (!res.ok) return [];
39
39
  const j = await res.json();
40
40
  return j.services ?? [];
41
+ },
42
+ async searchActions(query, service, limit) {
43
+ const res = await fetch(`${base}/v1/connections/actions`, {
44
+ method: "POST",
45
+ headers,
46
+ body: JSON.stringify({ query, service, limit })
47
+ });
48
+ if (!res.ok) return [];
49
+ const j = await res.json();
50
+ return j.actions ?? [];
41
51
  }
42
52
  };
43
53
  }
@@ -92,6 +102,15 @@ function connect(service, env, orgId) {
92
102
  }
93
103
  return { token: ctx.token, run: ctx.run };
94
104
  }
105
+ async function searchActions(query, env, opts = {}) {
106
+ const { binding } = resolveBinding(env);
107
+ if (!binding) return [];
108
+ try {
109
+ return await binding.searchActions(query, opts.service ?? null, opts.limit ?? 10);
110
+ } catch {
111
+ return [];
112
+ }
113
+ }
95
114
  function secret(name, env) {
96
115
  const v = env[name];
97
116
  return typeof v === "string" && v.length > 0 ? v : null;
@@ -150,6 +169,7 @@ export {
150
169
  connect,
151
170
  describe,
152
171
  isConnected,
172
+ searchActions,
153
173
  secret
154
174
  };
155
175
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @clawnify/connections — the accessor SDK.\n *\n * Three calls cover every credential an app needs:\n *\n * connect(\"googleads\", env) → a typed client (oauth or managed alike)\n * secret(\"OPENROUTER_API_KEY\", env)→ an injected provider key / secret\n * describe(env, orgId, requires) → agent-legible \"what's wired\" snapshot\n *\n * App code is identical whether a connection is managed or self-served, OAuth or\n * API key, dynamic or static. The broker that actually holds a credential lives\n * behind the Clawnify credentials binding and is never named here — `describe()`\n * speaks only in capabilities (`oauth`/`managed`/`key`/`secret`).\n */\n\nimport {\n getDescriptor,\n allDescriptors,\n type ServiceClients,\n type ConnectionDescriptor,\n type ConnectionKind,\n type AccessContext,\n} from \"@clawnify/integrations\";\n\n// Re-export the descriptor layer so consumers get client types (MetaAdsClient,\n// GoogleAdsRow, …) and descriptor types from one import.\nexport * from \"@clawnify/integrations\";\n\n/**\n * The credentials broker RPC contract — the Clawnify `CREDENTIALS` service\n * binding injected into every app. These method names are Clawnify-internal;\n * the provider behind them (managed or self-configured) is not part of the\n * contract.\n */\nexport interface CredentialBinding {\n getToken(service: string, orgId: string): Promise<string | null>;\n executeTool(\n service: string,\n toolSlug: string,\n args: Record<string, unknown>,\n orgId: string,\n ): Promise<{ data: unknown; error: string | null; successful: boolean }>;\n listConnected(orgId: string): Promise<string[]>;\n}\n\n/** The slice of a worker's `env` the SDK reads. */\nexport interface ConnectionsEnv {\n /** The in-process credentials binding. Present in deployed apps. */\n CREDENTIALS?: CredentialBinding;\n /** The org the app is serving, injected by the Clawnify builder. */\n CLAWNIFY_ORG_ID?: string;\n /**\n * A Clawnify token: either the OAuth bearer `clawnify login` holds, or a\n * long-lived org service token (clw_…). When set and no in-process\n * CREDENTIALS binding exists, the SDK resolves connections over HTTP via the\n * Clawnify API — so local `pnpm dev` / scripts reach real org connections\n * with no per-service secrets. With an OAuth bearer spanning several orgs,\n * CLAWNIFY_ORG_ID picks one; a service token fixes the org itself.\n */\n CLAWNIFY_TOKEN?: string;\n /** Override the Clawnify API base for the HTTP binding (defaults to prod). */\n CLAWNIFY_API_URL?: string;\n /** Injected provider keys / secrets / local-dev token fallbacks. */\n [key: string]: unknown;\n}\n\nconst DEFAULT_API_BASE = \"https://provision.clawnify.com\";\n\n/**\n * An HTTP-backed {@link CredentialBinding} for environments without the\n * in-process binding (local `pnpm dev`, scripts, Claude Code).\n *\n * `token` is either a Clawnify OAuth bearer (the session `clawnify login`\n * holds) or a long-lived org service token (clw_…). With an OAuth bearer that\n * belongs to several orgs, pass `orgId` to target one (sent as `x-org-id`);\n * with a service token the org is fixed and `orgId` is ignored. Managed\n * credentials stay server-side — only `getToken` returns a bearer.\n */\nexport function clawnifyBinding(opts: { token: string; baseUrl?: string; orgId?: string }): CredentialBinding {\n const base = (opts.baseUrl ?? DEFAULT_API_BASE).replace(/\\/+$/, \"\");\n const headers: Record<string, string> = {\n Authorization: `Bearer ${opts.token}`,\n \"Content-Type\": \"application/json\",\n ...(opts.orgId ? { \"x-org-id\": opts.orgId } : {}),\n };\n return {\n async getToken(service) {\n const res = await fetch(`${base}/v1/connections/token`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ service }),\n });\n if (!res.ok) return null;\n const j = (await res.json()) as { token?: string | null };\n return j.token ?? null;\n },\n async executeTool(service, toolSlug, args) {\n const res = await fetch(`${base}/v1/connections/execute`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ service, action: toolSlug, args }),\n });\n const j = (await res.json().catch(() => ({}))) as {\n data?: unknown;\n error?: string | null;\n successful?: boolean;\n };\n if (!res.ok) return { data: null, error: j.error ?? `connections ${res.status}`, successful: false };\n return { data: j.data ?? null, error: j.error ?? null, successful: j.successful ?? true };\n },\n async listConnected() {\n const res = await fetch(`${base}/v1/connections/connected`, { headers });\n if (!res.ok) return [];\n const j = (await res.json()) as { services?: string[] };\n return j.services ?? [];\n },\n };\n}\n\n/**\n * The binding to use this request: the in-process one if present, else an HTTP\n * binding built from CLAWNIFY_TOKEN. `remote` binding resolves the org from the\n * token, so it works without a local org id.\n */\nfunction resolveBinding(env: ConnectionsEnv): { binding?: CredentialBinding; remote: boolean } {\n if (env.CREDENTIALS) return { binding: env.CREDENTIALS, remote: false };\n const token = typeof env.CLAWNIFY_TOKEN === \"string\" ? env.CLAWNIFY_TOKEN : \"\";\n if (token) {\n const baseUrl = typeof env.CLAWNIFY_API_URL === \"string\" ? env.CLAWNIFY_API_URL : undefined;\n const orgId = typeof env.CLAWNIFY_ORG_ID === \"string\" ? env.CLAWNIFY_ORG_ID : undefined;\n return { binding: clawnifyBinding({ token, baseUrl, orgId }), remote: true };\n }\n return { remote: false };\n}\n\nfunction resolveOrg(env: ConnectionsEnv, orgId?: string): string | null {\n return orgId ?? env.CLAWNIFY_ORG_ID ?? null;\n}\n\nfunction buildContext(service: string, env: ConnectionsEnv, orgId: string | null): AccessContext {\n const { binding, remote } = resolveBinding(env);\n // A remote binding derives the org from the token, so it works without a\n // local org id; an in-process binding needs one.\n const canBroker = !!binding && (remote || !!orgId);\n return {\n orgId,\n managed: canBroker,\n env: env as Record<string, string | undefined>,\n async token() {\n if (binding && canBroker) {\n try {\n return await binding.getToken(service, orgId ?? \"\");\n } catch {\n return null;\n }\n }\n // Local-dev fallback: a bare token in env, e.g. METAADS_BEARER_TOKEN.\n const up = service.toUpperCase();\n const local = env[`${up}_BEARER_TOKEN`] ?? env[`${up}_ACCESS_TOKEN`];\n return typeof local === \"string\" ? local : null;\n },\n async run(action, args = {}) {\n if (!binding || !canBroker) {\n throw new Error(`\"${service}\" needs the Clawnify credentials binding or CLAWNIFY_TOKEN`);\n }\n const r = await binding.executeTool(service, action, args, orgId ?? \"\");\n if (!r.successful) throw new Error(r.error ?? `${service} action \"${action}\" failed`);\n return r.data;\n },\n };\n}\n\n/**\n * Low-level client returned for any integration without a bespoke descriptor.\n * Every integration supports these two operations, so a new dashboard\n * integration is usable immediately — no descriptor, no package release.\n */\nexport interface GenericClient {\n /** Current access token (OAuth / API key) for this integration. */\n token(): Promise<string | null>;\n /** Run a managed action scoped to the org; returns its data, throws on failure. */\n run(action: string, args?: Record<string, unknown>): Promise<unknown>;\n}\n\n/**\n * Get a client for an integration.\n *\n * - Registered integrations return their typed client — `connect(\"googleads\",\n * env)` is a GoogleAdsClient, no casting.\n * - Any other (e.g. a toolkit just added in the dashboard) returns a\n * {@link GenericClient} with `token()` + `run()`. The registry is an\n * ergonomics layer, never a gate: functionality never depends on a release.\n *\n * @throws only when the service is a known key/secret — read those with secret().\n */\nexport function connect<K extends keyof ServiceClients>(service: K, env: ConnectionsEnv, orgId?: string): ServiceClients[K];\nexport function connect(service: string, env: ConnectionsEnv, orgId?: string): GenericClient;\nexport function connect(service: string, env: ConnectionsEnv, orgId?: string): unknown {\n const ctx = buildContext(service, env, resolveOrg(env, orgId));\n const desc = getDescriptor(service);\n if (desc?.client) return desc.client(ctx);\n if (desc && (desc.kind === \"key\" || desc.kind === \"secret\")) {\n throw new Error(`\"${service}\" is a ${desc.kind}; read it with secret(\"${desc.envName ?? service}\")`);\n }\n return { token: ctx.token, run: ctx.run } satisfies GenericClient;\n}\n\n/** Read an injected provider key / secret env var. Returns null when absent. */\nexport function secret(name: string, env: ConnectionsEnv): string | null {\n const v = env[name];\n return typeof v === \"string\" && v.length > 0 ? v : null;\n}\n\n/** True when a usable credential exists for this service right now. */\nexport async function isConnected(service: string, env: ConnectionsEnv, orgId?: string): Promise<boolean> {\n const desc = getDescriptor(service);\n if (!desc) return false;\n const org = resolveOrg(env, orgId);\n if (desc.kind === \"key\" || desc.kind === \"secret\") {\n return !!secret(desc.envName ?? service, env);\n }\n const { binding, remote } = resolveBinding(env);\n if (binding && (remote || org)) {\n try {\n if ((await binding.listConnected(org ?? \"\")).includes(service)) return true;\n } catch {\n /* fall through to token probe */\n }\n }\n return !!(await buildContext(service, env, org).token());\n}\n\n/** One entry in clawnify.json's `requires` block. */\nexport type RequireSpec =\n | { service: string; as: \"integration\" }\n | { name: string; as: \"key\" | \"secret\" };\n\n/** Per-capability readiness, written for an agent to read before wiring code. */\nexport interface DescribeEntry {\n /** Service id (integrations) or env var name (keys/secrets). */\n id: string;\n label: string;\n kind: ConnectionKind;\n /** Whether a credential is present for this capability. */\n connected: boolean;\n /** Whether app code can use it right now (same as connected today). */\n ready: boolean;\n /** One-line snippet showing how to access it in app code. */\n accessor: string;\n /** What to do when it isn't ready — always dashboard-driven. */\n hint?: string;\n}\n\n/**\n * Report what's wired for an org. Pass the app's `requires` to report exactly\n * those capabilities (the agent-facing case); omit it to report every known\n * integration's status for the org.\n *\n * Never names the underlying broker — only `kind` and readiness.\n */\nexport async function describe(\n env: ConnectionsEnv,\n orgId?: string,\n requires?: RequireSpec[],\n): Promise<DescribeEntry[]> {\n const org = resolveOrg(env, orgId);\n\n // Normalize the work list. A required service with no descriptor is reported\n // generically (still fully usable via connect()'s GenericClient) — the\n // registry enriches, it never gates.\n type Item = { id: string; label: string; kind: ConnectionKind; accessor: string; isKey: boolean };\n const fromDescriptor = (d: ConnectionDescriptor): Item => {\n const isKey = d.kind === \"key\" || d.kind === \"secret\";\n return { id: isKey ? d.envName ?? d.service : d.service, label: d.label, kind: d.kind, accessor: d.accessor, isKey };\n };\n\n let items: Item[];\n if (requires?.length) {\n items = requires.map((r) => {\n if (\"name\" in r) {\n const d = getDescriptor(r.name);\n return d ? fromDescriptor(d) : { id: r.name, label: r.name, kind: r.as, accessor: `secret(\"${r.name}\")`, isKey: true };\n }\n const d = getDescriptor(r.service);\n // Unknown integration: kind is genuinely unknown without a descriptor;\n // \"managed\" is the broadest accessor (token() + run() both work).\n return d ? fromDescriptor(d) : { id: r.service, label: r.service, kind: \"managed\" as ConnectionKind, accessor: `connect(\"${r.service}\")`, isKey: false };\n });\n } else {\n items = allDescriptors().map(fromDescriptor);\n }\n\n // One broker round-trip for all integration kinds.\n let connectedList: string[] = [];\n const { binding, remote } = resolveBinding(env);\n if (binding && (remote || org) && items.some((i) => !i.isKey)) {\n try {\n connectedList = await binding.listConnected(org ?? \"\");\n } catch {\n /* leave empty — everything reports not-connected */\n }\n }\n\n return items.map((i) => {\n const has = i.isKey ? !!secret(i.id, env) : connectedList.includes(i.id);\n const hint = has\n ? undefined\n : i.isKey\n ? `Add ${i.id} in the dashboard → API Keys / Environment Variables.`\n : `Connect ${i.label} in the dashboard → Integrations.`;\n return { id: i.id, label: i.label, kind: i.kind, connected: has, ready: has, accessor: i.accessor, hint };\n });\n}\n"],"mappings":"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","names":["d"]}
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\n * @clawnify/connections — the accessor SDK.\n *\n * Three calls cover every credential an app needs:\n *\n * connect(\"googleads\", env) → a typed client (oauth or managed alike)\n * secret(\"OPENROUTER_API_KEY\", env)→ an injected provider key / secret\n * describe(env, orgId, requires) → agent-legible \"what's wired\" snapshot\n *\n * App code is identical whether a connection is managed or self-served, OAuth or\n * API key, dynamic or static. The broker that actually holds a credential lives\n * behind the Clawnify credentials binding and is never named here — `describe()`\n * speaks only in capabilities (`oauth`/`managed`/`key`/`secret`).\n */\n\nimport {\n getDescriptor,\n allDescriptors,\n type ServiceClients,\n type ConnectionDescriptor,\n type ConnectionKind,\n type AccessContext,\n} from \"@clawnify/integrations\";\n\n// Re-export the descriptor layer so consumers get client types (MetaAdsClient,\n// GoogleAdsRow, …) and descriptor types from one import.\nexport * from \"@clawnify/integrations\";\n\n/**\n * The credentials broker RPC contract — the Clawnify `CREDENTIALS` service\n * binding injected into every app. These method names are Clawnify-internal;\n * the provider behind them (managed or self-configured) is not part of the\n * contract.\n */\nexport interface CredentialBinding {\n getToken(service: string, orgId: string): Promise<string | null>;\n executeTool(\n service: string,\n toolSlug: string,\n args: Record<string, unknown>,\n orgId: string,\n ): Promise<{ data: unknown; error: string | null; successful: boolean }>;\n listConnected(orgId: string): Promise<string[]>;\n searchActions(query: string, service: string | null, limit: number): Promise<ActionMatch[]>;\n}\n\n/**\n * One action from the broker catalog. The `slug` feeds `connect(service).run(slug, body)`;\n * `inputSchema` is the JSON Schema for `body`. Returned best-first — `[0]` is the\n * canonical match. Discovery is broker-agnostic (Composio today; Arcade/Nango\n * expose the same search shape) and separable from execution. See docs §16.\n */\nexport interface ActionMatch {\n /** Toolkit/integration slug — pass to connect(service). */\n service: string;\n /** Action slug — pass to connect(service).run(slug, body). */\n slug: string;\n name: string;\n description: string;\n /** JSON Schema for the request body, or null if the catalog omits it. */\n inputSchema: Record<string, unknown> | null;\n}\n\n/** The slice of a worker's `env` the SDK reads. */\nexport interface ConnectionsEnv {\n /** The in-process credentials binding. Present in deployed apps. */\n CREDENTIALS?: CredentialBinding;\n /** The org the app is serving, injected by the Clawnify builder. */\n CLAWNIFY_ORG_ID?: string;\n /**\n * A Clawnify token: either the OAuth bearer `clawnify login` holds, or a\n * long-lived org service token (clw_…). When set and no in-process\n * CREDENTIALS binding exists, the SDK resolves connections over HTTP via the\n * Clawnify API — so local `pnpm dev` / scripts reach real org connections\n * with no per-service secrets. With an OAuth bearer spanning several orgs,\n * CLAWNIFY_ORG_ID picks one; a service token fixes the org itself.\n */\n CLAWNIFY_TOKEN?: string;\n /** Override the Clawnify API base for the HTTP binding (defaults to prod). */\n CLAWNIFY_API_URL?: string;\n /** Injected provider keys / secrets / local-dev token fallbacks. */\n [key: string]: unknown;\n}\n\nconst DEFAULT_API_BASE = \"https://provision.clawnify.com\";\n\n/**\n * An HTTP-backed {@link CredentialBinding} for environments without the\n * in-process binding (local `pnpm dev`, scripts, Claude Code).\n *\n * `token` is either a Clawnify OAuth bearer (the session `clawnify login`\n * holds) or a long-lived org service token (clw_…). With an OAuth bearer that\n * belongs to several orgs, pass `orgId` to target one (sent as `x-org-id`);\n * with a service token the org is fixed and `orgId` is ignored. Managed\n * credentials stay server-side — only `getToken` returns a bearer.\n */\nexport function clawnifyBinding(opts: { token: string; baseUrl?: string; orgId?: string }): CredentialBinding {\n const base = (opts.baseUrl ?? DEFAULT_API_BASE).replace(/\\/+$/, \"\");\n const headers: Record<string, string> = {\n Authorization: `Bearer ${opts.token}`,\n \"Content-Type\": \"application/json\",\n ...(opts.orgId ? { \"x-org-id\": opts.orgId } : {}),\n };\n return {\n async getToken(service) {\n const res = await fetch(`${base}/v1/connections/token`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ service }),\n });\n if (!res.ok) return null;\n const j = (await res.json()) as { token?: string | null };\n return j.token ?? null;\n },\n async executeTool(service, toolSlug, args) {\n const res = await fetch(`${base}/v1/connections/execute`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ service, action: toolSlug, args }),\n });\n const j = (await res.json().catch(() => ({}))) as {\n data?: unknown;\n error?: string | null;\n successful?: boolean;\n };\n if (!res.ok) return { data: null, error: j.error ?? `connections ${res.status}`, successful: false };\n return { data: j.data ?? null, error: j.error ?? null, successful: j.successful ?? true };\n },\n async listConnected() {\n const res = await fetch(`${base}/v1/connections/connected`, { headers });\n if (!res.ok) return [];\n const j = (await res.json()) as { services?: string[] };\n return j.services ?? [];\n },\n async searchActions(query, service, limit) {\n const res = await fetch(`${base}/v1/connections/actions`, {\n method: \"POST\",\n headers,\n body: JSON.stringify({ query, service, limit }),\n });\n if (!res.ok) return [];\n const j = (await res.json()) as { actions?: ActionMatch[] };\n return j.actions ?? [];\n },\n };\n}\n\n/**\n * The binding to use this request: the in-process one if present, else an HTTP\n * binding built from CLAWNIFY_TOKEN. `remote` binding resolves the org from the\n * token, so it works without a local org id.\n */\nfunction resolveBinding(env: ConnectionsEnv): { binding?: CredentialBinding; remote: boolean } {\n if (env.CREDENTIALS) return { binding: env.CREDENTIALS, remote: false };\n const token = typeof env.CLAWNIFY_TOKEN === \"string\" ? env.CLAWNIFY_TOKEN : \"\";\n if (token) {\n const baseUrl = typeof env.CLAWNIFY_API_URL === \"string\" ? env.CLAWNIFY_API_URL : undefined;\n const orgId = typeof env.CLAWNIFY_ORG_ID === \"string\" ? env.CLAWNIFY_ORG_ID : undefined;\n return { binding: clawnifyBinding({ token, baseUrl, orgId }), remote: true };\n }\n return { remote: false };\n}\n\nfunction resolveOrg(env: ConnectionsEnv, orgId?: string): string | null {\n return orgId ?? env.CLAWNIFY_ORG_ID ?? null;\n}\n\nfunction buildContext(service: string, env: ConnectionsEnv, orgId: string | null): AccessContext {\n const { binding, remote } = resolveBinding(env);\n // A remote binding derives the org from the token, so it works without a\n // local org id; an in-process binding needs one.\n const canBroker = !!binding && (remote || !!orgId);\n return {\n orgId,\n managed: canBroker,\n env: env as Record<string, string | undefined>,\n async token() {\n if (binding && canBroker) {\n try {\n return await binding.getToken(service, orgId ?? \"\");\n } catch {\n return null;\n }\n }\n // Local-dev fallback: a bare token in env, e.g. METAADS_BEARER_TOKEN.\n const up = service.toUpperCase();\n const local = env[`${up}_BEARER_TOKEN`] ?? env[`${up}_ACCESS_TOKEN`];\n return typeof local === \"string\" ? local : null;\n },\n async run(action, args = {}) {\n if (!binding || !canBroker) {\n throw new Error(`\"${service}\" needs the Clawnify credentials binding or CLAWNIFY_TOKEN`);\n }\n const r = await binding.executeTool(service, action, args, orgId ?? \"\");\n if (!r.successful) throw new Error(r.error ?? `${service} action \"${action}\" failed`);\n return r.data;\n },\n };\n}\n\n/**\n * Low-level client returned for any integration without a bespoke descriptor.\n * Every integration supports these two operations, so a new dashboard\n * integration is usable immediately — no descriptor, no package release.\n */\nexport interface GenericClient {\n /** Current access token (OAuth / API key) for this integration. */\n token(): Promise<string | null>;\n /** Run a managed action scoped to the org; returns its data, throws on failure. */\n run(action: string, args?: Record<string, unknown>): Promise<unknown>;\n}\n\n/**\n * Get a client for an integration.\n *\n * - Registered integrations return their typed client — `connect(\"googleads\",\n * env)` is a GoogleAdsClient, no casting.\n * - Any other (e.g. a toolkit just added in the dashboard) returns a\n * {@link GenericClient} with `token()` + `run()`. The registry is an\n * ergonomics layer, never a gate: functionality never depends on a release.\n *\n * @throws only when the service is a known key/secret — read those with secret().\n */\nexport function connect<K extends keyof ServiceClients>(service: K, env: ConnectionsEnv, orgId?: string): ServiceClients[K];\nexport function connect(service: string, env: ConnectionsEnv, orgId?: string): GenericClient;\nexport function connect(service: string, env: ConnectionsEnv, orgId?: string): unknown {\n const ctx = buildContext(service, env, resolveOrg(env, orgId));\n const desc = getDescriptor(service);\n if (desc?.client) return desc.client(ctx);\n if (desc && (desc.kind === \"key\" || desc.kind === \"secret\")) {\n throw new Error(`\"${service}\" is a ${desc.kind}; read it with secret(\"${desc.envName ?? service}\")`);\n }\n return { token: ctx.token, run: ctx.run } satisfies GenericClient;\n}\n\n/**\n * Search the broker action catalog for the right action to call, returned\n * best-first with each action's input schema (the request body). The default\n * way to use the long tail of integrations: search → read `inputSchema` →\n * `connect(service).run(slug, body)`, with no per-integration package code.\n *\n * Broker-agnostic — the active broker's own search backs it (Composio today).\n * `[0]` is the canonical match. Catalog metadata, so it works without an org\n * id; needs the in-process CREDENTIALS binding or CLAWNIFY_TOKEN. See docs §16.\n *\n * @example\n * const [best] = await searchActions(\"post a message to slack\", env);\n * if (best) await connect(best.service, env).run(best.slug, { channel, text });\n */\nexport async function searchActions(\n query: string,\n env: ConnectionsEnv,\n opts: { service?: string; limit?: number } = {},\n): Promise<ActionMatch[]> {\n const { binding } = resolveBinding(env);\n if (!binding) return [];\n try {\n return await binding.searchActions(query, opts.service ?? null, opts.limit ?? 10);\n } catch {\n return [];\n }\n}\n\n/** Read an injected provider key / secret env var. Returns null when absent. */\nexport function secret(name: string, env: ConnectionsEnv): string | null {\n const v = env[name];\n return typeof v === \"string\" && v.length > 0 ? v : null;\n}\n\n/** True when a usable credential exists for this service right now. */\nexport async function isConnected(service: string, env: ConnectionsEnv, orgId?: string): Promise<boolean> {\n const desc = getDescriptor(service);\n if (!desc) return false;\n const org = resolveOrg(env, orgId);\n if (desc.kind === \"key\" || desc.kind === \"secret\") {\n return !!secret(desc.envName ?? service, env);\n }\n const { binding, remote } = resolveBinding(env);\n if (binding && (remote || org)) {\n try {\n if ((await binding.listConnected(org ?? \"\")).includes(service)) return true;\n } catch {\n /* fall through to token probe */\n }\n }\n return !!(await buildContext(service, env, org).token());\n}\n\n/** One entry in clawnify.json's `requires` block. */\nexport type RequireSpec =\n | { service: string; as: \"integration\" }\n | { name: string; as: \"key\" | \"secret\" };\n\n/** Per-capability readiness, written for an agent to read before wiring code. */\nexport interface DescribeEntry {\n /** Service id (integrations) or env var name (keys/secrets). */\n id: string;\n label: string;\n kind: ConnectionKind;\n /** Whether a credential is present for this capability. */\n connected: boolean;\n /** Whether app code can use it right now (same as connected today). */\n ready: boolean;\n /** One-line snippet showing how to access it in app code. */\n accessor: string;\n /** What to do when it isn't ready — always dashboard-driven. */\n hint?: string;\n}\n\n/**\n * Report what's wired for an org. Pass the app's `requires` to report exactly\n * those capabilities (the agent-facing case); omit it to report every known\n * integration's status for the org.\n *\n * Never names the underlying broker — only `kind` and readiness.\n */\nexport async function describe(\n env: ConnectionsEnv,\n orgId?: string,\n requires?: RequireSpec[],\n): Promise<DescribeEntry[]> {\n const org = resolveOrg(env, orgId);\n\n // Normalize the work list. A required service with no descriptor is reported\n // generically (still fully usable via connect()'s GenericClient) — the\n // registry enriches, it never gates.\n type Item = { id: string; label: string; kind: ConnectionKind; accessor: string; isKey: boolean };\n const fromDescriptor = (d: ConnectionDescriptor): Item => {\n const isKey = d.kind === \"key\" || d.kind === \"secret\";\n return { id: isKey ? d.envName ?? d.service : d.service, label: d.label, kind: d.kind, accessor: d.accessor, isKey };\n };\n\n let items: Item[];\n if (requires?.length) {\n items = requires.map((r) => {\n if (\"name\" in r) {\n const d = getDescriptor(r.name);\n return d ? fromDescriptor(d) : { id: r.name, label: r.name, kind: r.as, accessor: `secret(\"${r.name}\")`, isKey: true };\n }\n const d = getDescriptor(r.service);\n // Unknown integration: kind is genuinely unknown without a descriptor;\n // \"managed\" is the broadest accessor (token() + run() both work).\n return d ? fromDescriptor(d) : { id: r.service, label: r.service, kind: \"managed\" as ConnectionKind, accessor: `connect(\"${r.service}\")`, isKey: false };\n });\n } else {\n items = allDescriptors().map(fromDescriptor);\n }\n\n // One broker round-trip for all integration kinds.\n let connectedList: string[] = [];\n const { binding, remote } = resolveBinding(env);\n if (binding && (remote || org) && items.some((i) => !i.isKey)) {\n try {\n connectedList = await binding.listConnected(org ?? \"\");\n } catch {\n /* leave empty — everything reports not-connected */\n }\n }\n\n return items.map((i) => {\n const has = i.isKey ? !!secret(i.id, env) : connectedList.includes(i.id);\n const hint = has\n ? undefined\n : i.isKey\n ? `Add ${i.id} in the dashboard → API Keys / Environment Variables.`\n : `Connect ${i.label} in the dashboard → Integrations.`;\n return { id: i.id, label: i.label, kind: i.kind, connected: has, ready: has, accessor: i.accessor, hint };\n });\n}\n"],"mappings":"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","names":["d"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawnify/connections",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "One-declaration, one-accessor credentials SDK for Clawnify apps. connect(service) returns a typed client, secret(name) reads an injected key, and describe(org) tells an agent what's wired — all over the Clawnify credentials binding, with the broker kept invisible.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -18,7 +18,7 @@
18
18
  "dist"
19
19
  ],
20
20
  "dependencies": {
21
- "@clawnify/integrations": "0.1.0"
21
+ "@clawnify/integrations": "0.1.1"
22
22
  },
23
23
  "devDependencies": {
24
24
  "@cloudflare/workers-types": "^4.20260405.1",