@agentforge-io/sdk-server 4.1.0 → 4.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/dist/index.d.ts +1 -1
- package/dist/resources/connectors.d.ts +173 -1
- package/dist/resources/connectors.js +245 -3
- package/dist/types.d.ts +15 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export { AgentForgeClient } from './client';
|
|
|
2
2
|
export type { AgentForgeClientOptions, RequestOptions } from './client';
|
|
3
3
|
export { AgentForgeError, AgentForgeAuthError, AgentForgeNotFoundError, AgentForgeNetworkError, } from './errors';
|
|
4
4
|
export { TOOL_CALLBACK_HEADERS, ToolCallbackSignatureError, signToolCallbackPayload, verifyToolCallbackSignature, } from './webhooks';
|
|
5
|
-
export type { AgentMe, AgentSummary, ApprovalCopyBundle, ChatStreamChunk, ChatStreamEvent, ChatTokenRecord, ConnectorDefaultsResult, ConnectorDefaultsSource, ConnectorResourceItem, ConnectorStatus, ConnectorToolInfo, ConversationHistory, ConversationStatus, CreateAgentInput, CreateClickupTaskInput, CreateClickupTaskResult, ExternalToolSummary, IssueChatTokenInput, ListAgentsResult, ListConnectorResourcesResult, McpServerConfig, MessageRecord, MessageRole, PublicAppBranding, AppSelf, AppSelfConnector, AppSelfConnectors, RegisterToolInput, RegisterToolsInput, RegisterToolsResult, ToolCallbackPayload, ToolCallRecord, ToolPermission, ToolPermissionMode, TokenUsage, TenantSecretEntry, UpdateAgentInput, } from './types';
|
|
5
|
+
export type { AgentMe, AgentSummary, AppUserConnectorStatus, ApprovalCopyBundle, ChatStreamChunk, ChatStreamEvent, ChatTokenRecord, ConnectorDefaultsResult, ConnectorDefaultsSource, ConnectorResourceItem, ConnectorStatus, ConnectorToolInfo, ConversationHistory, ConversationStatus, CreateAgentInput, CreateClickupTaskInput, CreateClickupTaskResult, ExternalToolSummary, IssueChatTokenInput, ListAgentsResult, ListConnectorResourcesResult, McpServerConfig, MessageRecord, MessageRole, PublicAppBranding, AppSelf, AppSelfConnector, AppSelfConnectors, RegisterToolInput, RegisterToolsInput, RegisterToolsResult, ToolCallbackPayload, ToolCallRecord, ToolPermission, ToolPermissionMode, TokenUsage, TenantSecretEntry, UpdateAgentInput, } from './types';
|
|
6
6
|
export { AgentsResource } from './resources/agents';
|
|
7
7
|
export { AppsResource } from './resources/apps';
|
|
8
8
|
export { ChatResource } from './resources/chat';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { AgentForgeClient } from '../client';
|
|
2
|
-
import type { ConnectorDefaultsResult, ConnectorStatus, CreateClickupTaskInput, CreateClickupTaskResult, ListConnectorResourcesResult, ToolPermission } from '../types';
|
|
2
|
+
import type { AppUserConnectorStatus, ConnectorDefaultsResult, ConnectorStatus, CreateClickupTaskInput, CreateClickupTaskResult, ListConnectorResourcesResult, ToolPermission } from '../types';
|
|
3
3
|
export declare class ConnectorsResource {
|
|
4
4
|
private readonly client;
|
|
5
5
|
constructor(client: AgentForgeClient);
|
|
@@ -196,6 +196,178 @@ export declare class ConnectorsResource {
|
|
|
196
196
|
* desconecta un canal del inbox omnicanal.
|
|
197
197
|
*/
|
|
198
198
|
destroyInboxChannel(agentId: string, channelId: string): Promise<void>;
|
|
199
|
+
/**
|
|
200
|
+
* `POST /connectors/oauth/:id/authorize-for-app-user` — starts the
|
|
201
|
+
* connector OAuth flow on behalf of ONE end user of the `sk_live_`/
|
|
202
|
+
* `sk_test_` App (`appId` resolved from the secret, `externalUserId`
|
|
203
|
+
* explicit). App-user counterpart of `authorizeForTenant()` above — same
|
|
204
|
+
* response shape (`{ url }`, open it e.g. via `window.open` in the
|
|
205
|
+
* consumer app), same callback flow end-to-end on the platform.
|
|
206
|
+
*
|
|
207
|
+
* Requires the `AgentForgeClient` to have been constructed with
|
|
208
|
+
* `appSecret` — throws early otherwise (this surface authenticates AS the
|
|
209
|
+
* App, not via ak_live_/ChatToken).
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* const af = new AgentForgeClient({ baseURL, appSecret: 'sk_live_...' });
|
|
213
|
+
* const { url } = await af.connectors.authorizeForAppUser('slack', {
|
|
214
|
+
* externalUserId: 'scrappydoc-user-42',
|
|
215
|
+
* postAuthRedirect: 'https://myapp.com/settings',
|
|
216
|
+
* });
|
|
217
|
+
*/
|
|
218
|
+
authorizeForAppUser(connectorId: string, input: {
|
|
219
|
+
externalUserId: string;
|
|
220
|
+
postAuthRedirect?: string;
|
|
221
|
+
}): Promise<{
|
|
222
|
+
url: string;
|
|
223
|
+
}>;
|
|
224
|
+
/**
|
|
225
|
+
* `GET /connectors/oauth/app-user/directory` — the given end user's
|
|
226
|
+
* connectors + connection status (App-user counterpart of
|
|
227
|
+
* `listConnected()`, which is the ak_live_ tenant-wide picker). Returns
|
|
228
|
+
* the SAME rich shape `listForTenant`/`listForUser` produce server-side
|
|
229
|
+
* (`AppUserConnectorStatus`: name/description/category/iconUrl/configured/
|
|
230
|
+
* accountLabel/connectedAt) — NOT the narrow `ConnectorStatus` the
|
|
231
|
+
* tenant-picker methods above use.
|
|
232
|
+
*
|
|
233
|
+
* Requires `appSecret` — throws early otherwise, same as
|
|
234
|
+
* `authorizeForAppUser`.
|
|
235
|
+
*
|
|
236
|
+
* @example
|
|
237
|
+
* const { items } = await af.connectors.listConnectorsForAppUser({
|
|
238
|
+
* externalUserId: 'scrappydoc-user-42',
|
|
239
|
+
* });
|
|
240
|
+
* const unconnected = items.filter((c) => c.configured && !c.connected);
|
|
241
|
+
*/
|
|
242
|
+
listConnectorsForAppUser(input: {
|
|
243
|
+
externalUserId: string;
|
|
244
|
+
}): Promise<{
|
|
245
|
+
items: AppUserConnectorStatus[];
|
|
246
|
+
}>;
|
|
247
|
+
/**
|
|
248
|
+
* `DELETE /connectors/oauth/:id/app-user` — disconnects `connectorId` for
|
|
249
|
+
* the given end user. App-user counterpart of `disconnect()` above.
|
|
250
|
+
* Mirrors the platform's `disconnectForAppUser` 404-on-missing behavior
|
|
251
|
+
* (`ConnectorError('not_connected', ...)` → `AgentForgeNotFoundError`).
|
|
252
|
+
*
|
|
253
|
+
* Requires `appSecret` — throws early otherwise, same as
|
|
254
|
+
* `authorizeForAppUser`.
|
|
255
|
+
*
|
|
256
|
+
* @example
|
|
257
|
+
* await af.connectors.disconnectForAppUser('google-drive', {
|
|
258
|
+
* externalUserId: 'scrappydoc-user-42',
|
|
259
|
+
* });
|
|
260
|
+
*/
|
|
261
|
+
disconnectForAppUser(connectorId: string, input: {
|
|
262
|
+
externalUserId: string;
|
|
263
|
+
}): Promise<{
|
|
264
|
+
ok: true;
|
|
265
|
+
}>;
|
|
266
|
+
/**
|
|
267
|
+
* `GET /app-user/connector-resources/:connectorId?externalUserId=...` —
|
|
268
|
+
* real resource browsing (Slack channels, GitHub repos, ClickUp lists…)
|
|
269
|
+
* scoped to ONE end user's OWN grant. App-user counterpart of
|
|
270
|
+
* `listResources()` above — same return shape, same `unsupported: true`
|
|
271
|
+
* behavior for connectors without a resource selector implemented yet.
|
|
272
|
+
*
|
|
273
|
+
* Requires `appSecret` — throws early otherwise, same as
|
|
274
|
+
* `authorizeForAppUser`.
|
|
275
|
+
*
|
|
276
|
+
* @example
|
|
277
|
+
* const { items } = await af.connectors.listResourcesForAppUser('slack', {
|
|
278
|
+
* externalUserId: 'scrappydoc-user-42',
|
|
279
|
+
* });
|
|
280
|
+
*/
|
|
281
|
+
listResourcesForAppUser(connectorId: string, input: {
|
|
282
|
+
externalUserId: string;
|
|
283
|
+
}): Promise<ListConnectorResourcesResult>;
|
|
284
|
+
/**
|
|
285
|
+
* `GET /app-user/connector-resources/:connectorId/defaults?externalUserId=...`
|
|
286
|
+
* — tool permissions for this connector, resolved with the App's own
|
|
287
|
+
* override always live (tier 0, `af_app_connectors`) since `appId` comes
|
|
288
|
+
* from the secret. App-user counterpart of `getDefaults()` above.
|
|
289
|
+
* `externalUserId` doesn't affect resolution (defaults are per-App, not
|
|
290
|
+
* per-end-user) — still required because the platform route always reads
|
|
291
|
+
* it off the scope helper shared by this controller's other routes.
|
|
292
|
+
*
|
|
293
|
+
* Requires `appSecret` — throws early otherwise, same as
|
|
294
|
+
* `authorizeForAppUser`.
|
|
295
|
+
*/
|
|
296
|
+
getDefaultsForAppUser(connectorId: string, input: {
|
|
297
|
+
externalUserId: string;
|
|
298
|
+
}): Promise<ConnectorDefaultsResult>;
|
|
299
|
+
/**
|
|
300
|
+
* `PUT /app-user/connector-resources/:connectorId/defaults?externalUserId=...`
|
|
301
|
+
* — overwrites the connector's tool permissions. App-user counterpart of
|
|
302
|
+
* `updateDefaults()` above. NOTE (mirrors the platform controller's own
|
|
303
|
+
* doc comment): this write lands on the tenant-level row
|
|
304
|
+
* (`af_connector_tool_defaults`), same as the ak_live_ route — there's no
|
|
305
|
+
* App-scoped-only override write today. `externalUserId` travels as a
|
|
306
|
+
* query param (matching `getDefaultsForAppUser`); the platform route also
|
|
307
|
+
* accepts it in the body but query is canonical for this SDK's GET/PUT
|
|
308
|
+
* pair.
|
|
309
|
+
*
|
|
310
|
+
* Requires `appSecret` — throws early otherwise, same as
|
|
311
|
+
* `authorizeForAppUser`.
|
|
312
|
+
*/
|
|
313
|
+
updateDefaultsForAppUser(connectorId: string, permissions: ToolPermission[], input: {
|
|
314
|
+
externalUserId: string;
|
|
315
|
+
}): Promise<{
|
|
316
|
+
ok: true;
|
|
317
|
+
}>;
|
|
318
|
+
/**
|
|
319
|
+
* `POST /app-user/connector-resources/clickup/tasks` — creates a REAL
|
|
320
|
+
* ClickUp task using the end user's OWN grant. App-user counterpart of
|
|
321
|
+
* `createClickupTask()` above. Unlike the GET/PUT methods above,
|
|
322
|
+
* `externalUserId` travels in the BODY here — the platform route reads it
|
|
323
|
+
* off `body.externalUserId` for this action endpoint (not a query param).
|
|
324
|
+
*
|
|
325
|
+
* Requires `appSecret` — throws early otherwise, same as
|
|
326
|
+
* `authorizeForAppUser`.
|
|
327
|
+
*/
|
|
328
|
+
createClickupTaskForAppUser(input: CreateClickupTaskInput & {
|
|
329
|
+
externalUserId: string;
|
|
330
|
+
}): Promise<CreateClickupTaskResult>;
|
|
331
|
+
/**
|
|
332
|
+
* `POST /app-user/connector-resources/slack/messages` — posts a REAL
|
|
333
|
+
* Slack message using the end user's OWN grant. App-user counterpart of
|
|
334
|
+
* `postSlackMessage()` above. `externalUserId` travels in the BODY, same
|
|
335
|
+
* as `createClickupTaskForAppUser` (the platform route reads
|
|
336
|
+
* `body.externalUserId` for both action endpoints).
|
|
337
|
+
*
|
|
338
|
+
* Requires `appSecret` — throws early otherwise, same as
|
|
339
|
+
* `authorizeForAppUser`.
|
|
340
|
+
*/
|
|
341
|
+
postSlackMessageForAppUser(input: {
|
|
342
|
+
channelId: string;
|
|
343
|
+
text: string;
|
|
344
|
+
externalUserId: string;
|
|
345
|
+
}): Promise<{
|
|
346
|
+
ok: true;
|
|
347
|
+
ts?: string;
|
|
348
|
+
permalink?: string;
|
|
349
|
+
}>;
|
|
350
|
+
/**
|
|
351
|
+
* `POST /app-user/connector-resources/:connectorId/api-key` — guarda un
|
|
352
|
+
* API key pegado por el end user, para SU PROPIO grant (no el tenant del
|
|
353
|
+
* App). App-user counterpart of `saveApiKeyForTenant()` above, para
|
|
354
|
+
* connectors que NO usan OAuth (Granola, Mapbox). `externalUserId` viaja
|
|
355
|
+
* en el BODY, mismo patrón que `createClickupTaskForAppUser`/
|
|
356
|
+
* `postSlackMessageForAppUser`.
|
|
357
|
+
*
|
|
358
|
+
* Requires `appSecret` — throws early otherwise, same as
|
|
359
|
+
* `authorizeForAppUser`.
|
|
360
|
+
*
|
|
361
|
+
* @example
|
|
362
|
+
* await af.connectors.saveApiKeyForAppUser('granola', 'grn_xxxxx', {
|
|
363
|
+
* externalUserId: 'scrappydoc-user-42',
|
|
364
|
+
* });
|
|
365
|
+
*/
|
|
366
|
+
saveApiKeyForAppUser(connectorId: string, apiKey: string, input: {
|
|
367
|
+
externalUserId: string;
|
|
368
|
+
}): Promise<{
|
|
369
|
+
connectorId: string;
|
|
370
|
+
}>;
|
|
199
371
|
}
|
|
200
372
|
export interface InboxChannelView {
|
|
201
373
|
id: string;
|
|
@@ -5,9 +5,13 @@
|
|
|
5
5
|
// reales de uno conectado (canales de Slack, repos de GitHub, etc), y arranca
|
|
6
6
|
// el OAuth authorize para uno que falte conectar.
|
|
7
7
|
//
|
|
8
|
-
// Auth:
|
|
9
|
-
// en el server y rechazan ChatToken de plano, aunque el
|
|
10
|
-
// también tenga uno configurado (ver `requestWithApiKey`).
|
|
8
|
+
// Auth: la mayoría de los métodos son ak_live_ tenant-wide — usan
|
|
9
|
+
// `ApiKeyGuard` en el server y rechazan ChatToken de plano, aunque el
|
|
10
|
+
// `AgentForgeClient` también tenga uno configurado (ver `requestWithApiKey`).
|
|
11
|
+
// EXCEPCIÓN (AGF-072, sección "App-user scope" al final del archivo): los
|
|
12
|
+
// métodos `*ForAppUser` (Plane B — un end user del App conectando SU PROPIA
|
|
13
|
+
// cuenta) usan `appSecret` (sk_live_/sk_test_) en vez de ak_live_, y por eso
|
|
14
|
+
// llaman `this.client.request()` directo en lugar de `requestWithApiKey()`.
|
|
11
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
16
|
exports.ConnectorsResource = void 0;
|
|
13
17
|
class ConnectorsResource {
|
|
@@ -203,5 +207,243 @@ class ConnectorsResource {
|
|
|
203
207
|
async destroyInboxChannel(agentId, channelId) {
|
|
204
208
|
await this.client.requestWithApiKey('DELETE', `/connectors/inbox/agents/${encodeURIComponent(agentId)}/inbox/channels/${encodeURIComponent(channelId)}`);
|
|
205
209
|
}
|
|
210
|
+
// ─── App-user scope (AGF-072, Option A — APP_END_USER_CONNECTIONS_SDD.md §4.4) ──
|
|
211
|
+
//
|
|
212
|
+
// The 3 methods below are Plane B: a specific END USER of an `sk_live_`/
|
|
213
|
+
// `sk_test_` App connecting THEIR OWN account (their Slack, their Gmail) —
|
|
214
|
+
// distinct from `*ForTenant` above (Plane A, the App's own tenant-wide
|
|
215
|
+
// credentials) and from the ak_live_-only picker methods at the top of this
|
|
216
|
+
// file. Auth is `appSecret` (sk_live_/sk_test_), NOT ak_live_ — these calls
|
|
217
|
+
// use `this.client.request()` directly (plain `authHeaders()`, which picks
|
|
218
|
+
// `appSecret` when set) instead of `requestWithApiKey()`, because that
|
|
219
|
+
// helper hardcodes `forceApiKey: true` and would reject an appSecret-only
|
|
220
|
+
// client. Same pattern as `ChatResource.streamMessageForAppUser`.
|
|
221
|
+
//
|
|
222
|
+
// `appId` is NEVER a param on any of these — the platform resolves it
|
|
223
|
+
// exclusively from the `sk_live_`/`sk_test_` secret server-side (SDD §4.4),
|
|
224
|
+
// so App Y's secret can never touch App X's grants no matter what
|
|
225
|
+
// `externalUserId` is passed. Only `externalUserId` (the App's own,
|
|
226
|
+
// unsigned identifier for its end user) travels as a param.
|
|
227
|
+
/**
|
|
228
|
+
* `POST /connectors/oauth/:id/authorize-for-app-user` — starts the
|
|
229
|
+
* connector OAuth flow on behalf of ONE end user of the `sk_live_`/
|
|
230
|
+
* `sk_test_` App (`appId` resolved from the secret, `externalUserId`
|
|
231
|
+
* explicit). App-user counterpart of `authorizeForTenant()` above — same
|
|
232
|
+
* response shape (`{ url }`, open it e.g. via `window.open` in the
|
|
233
|
+
* consumer app), same callback flow end-to-end on the platform.
|
|
234
|
+
*
|
|
235
|
+
* Requires the `AgentForgeClient` to have been constructed with
|
|
236
|
+
* `appSecret` — throws early otherwise (this surface authenticates AS the
|
|
237
|
+
* App, not via ak_live_/ChatToken).
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* const af = new AgentForgeClient({ baseURL, appSecret: 'sk_live_...' });
|
|
241
|
+
* const { url } = await af.connectors.authorizeForAppUser('slack', {
|
|
242
|
+
* externalUserId: 'scrappydoc-user-42',
|
|
243
|
+
* postAuthRedirect: 'https://myapp.com/settings',
|
|
244
|
+
* });
|
|
245
|
+
*/
|
|
246
|
+
async authorizeForAppUser(connectorId, input) {
|
|
247
|
+
if (!this.client.getAppSecret()) {
|
|
248
|
+
throw new Error('connectors.authorizeForAppUser requires appSecret (sk_live_/sk_test_) in ' +
|
|
249
|
+
'AgentForgeClient. This surface authenticates AS the App, not via chatToken/apiKey.');
|
|
250
|
+
}
|
|
251
|
+
const params = new URLSearchParams({ externalUserId: input.externalUserId });
|
|
252
|
+
if (input.postAuthRedirect)
|
|
253
|
+
params.set('postAuthRedirect', input.postAuthRedirect);
|
|
254
|
+
return this.client.request('POST', `/connectors/oauth/${encodeURIComponent(connectorId)}/authorize-for-app-user?${params.toString()}`);
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* `GET /connectors/oauth/app-user/directory` — the given end user's
|
|
258
|
+
* connectors + connection status (App-user counterpart of
|
|
259
|
+
* `listConnected()`, which is the ak_live_ tenant-wide picker). Returns
|
|
260
|
+
* the SAME rich shape `listForTenant`/`listForUser` produce server-side
|
|
261
|
+
* (`AppUserConnectorStatus`: name/description/category/iconUrl/configured/
|
|
262
|
+
* accountLabel/connectedAt) — NOT the narrow `ConnectorStatus` the
|
|
263
|
+
* tenant-picker methods above use.
|
|
264
|
+
*
|
|
265
|
+
* Requires `appSecret` — throws early otherwise, same as
|
|
266
|
+
* `authorizeForAppUser`.
|
|
267
|
+
*
|
|
268
|
+
* @example
|
|
269
|
+
* const { items } = await af.connectors.listConnectorsForAppUser({
|
|
270
|
+
* externalUserId: 'scrappydoc-user-42',
|
|
271
|
+
* });
|
|
272
|
+
* const unconnected = items.filter((c) => c.configured && !c.connected);
|
|
273
|
+
*/
|
|
274
|
+
async listConnectorsForAppUser(input) {
|
|
275
|
+
if (!this.client.getAppSecret()) {
|
|
276
|
+
throw new Error('connectors.listConnectorsForAppUser requires appSecret (sk_live_/sk_test_) in ' +
|
|
277
|
+
'AgentForgeClient. This surface authenticates AS the App, not via chatToken/apiKey.');
|
|
278
|
+
}
|
|
279
|
+
const params = new URLSearchParams({ externalUserId: input.externalUserId });
|
|
280
|
+
return this.client.request('GET', `/connectors/oauth/app-user/directory?${params.toString()}`);
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* `DELETE /connectors/oauth/:id/app-user` — disconnects `connectorId` for
|
|
284
|
+
* the given end user. App-user counterpart of `disconnect()` above.
|
|
285
|
+
* Mirrors the platform's `disconnectForAppUser` 404-on-missing behavior
|
|
286
|
+
* (`ConnectorError('not_connected', ...)` → `AgentForgeNotFoundError`).
|
|
287
|
+
*
|
|
288
|
+
* Requires `appSecret` — throws early otherwise, same as
|
|
289
|
+
* `authorizeForAppUser`.
|
|
290
|
+
*
|
|
291
|
+
* @example
|
|
292
|
+
* await af.connectors.disconnectForAppUser('google-drive', {
|
|
293
|
+
* externalUserId: 'scrappydoc-user-42',
|
|
294
|
+
* });
|
|
295
|
+
*/
|
|
296
|
+
async disconnectForAppUser(connectorId, input) {
|
|
297
|
+
if (!this.client.getAppSecret()) {
|
|
298
|
+
throw new Error('connectors.disconnectForAppUser requires appSecret (sk_live_/sk_test_) in ' +
|
|
299
|
+
'AgentForgeClient. This surface authenticates AS the App, not via chatToken/apiKey.');
|
|
300
|
+
}
|
|
301
|
+
const params = new URLSearchParams({ externalUserId: input.externalUserId });
|
|
302
|
+
return this.client.request('DELETE', `/connectors/oauth/${encodeURIComponent(connectorId)}/app-user?${params.toString()}`);
|
|
303
|
+
}
|
|
304
|
+
// ─── App-user resource picker (AGF-072d — app-user twin of the picker
|
|
305
|
+
// methods at the top of this file) ──────────────────────────────────────
|
|
306
|
+
//
|
|
307
|
+
// Mirrors listResources/getDefaults/updateDefaults/createClickupTask/
|
|
308
|
+
// postSlackMessage above, scoped to (appId-from-secret, externalUserId)
|
|
309
|
+
// instead of the ak_live_ tenant. Hits `AppUserResourcePickerController`
|
|
310
|
+
// (`/app-user/connector-resources/*`) — a DISTINCT base path from the
|
|
311
|
+
// tenant picker's `/connector-resources/*`, not just a query-param
|
|
312
|
+
// variant. Same auth rule as the 3 methods above: requires `appSecret`,
|
|
313
|
+
// uses `this.client.request()` directly (not `requestWithApiKey()`).
|
|
314
|
+
//
|
|
315
|
+
// NOT mirrored here:
|
|
316
|
+
// - list-connected (`GET /app-user/connector-resources`): its
|
|
317
|
+
// `{connectorId,connected,browsable}[]` shape is a narrower duplicate
|
|
318
|
+
// of what `listConnectorsForAppUser()` above already returns (the
|
|
319
|
+
// richer `AppUserConnectorStatus[]` from
|
|
320
|
+
// `/connectors/oauth/app-user/directory`). Adding a second, thinner
|
|
321
|
+
// "list connected" would just invite callers to pick the wrong one.
|
|
322
|
+
// - disconnect (`DELETE /app-user/connector-resources/:connectorId`):
|
|
323
|
+
// redundant with `disconnectForAppUser()` above
|
|
324
|
+
// (`/connectors/oauth/:id/app-user`) — same ConnectorAuth row, same
|
|
325
|
+
// method name would collide. Use the existing one.
|
|
326
|
+
/**
|
|
327
|
+
* `GET /app-user/connector-resources/:connectorId?externalUserId=...` —
|
|
328
|
+
* real resource browsing (Slack channels, GitHub repos, ClickUp lists…)
|
|
329
|
+
* scoped to ONE end user's OWN grant. App-user counterpart of
|
|
330
|
+
* `listResources()` above — same return shape, same `unsupported: true`
|
|
331
|
+
* behavior for connectors without a resource selector implemented yet.
|
|
332
|
+
*
|
|
333
|
+
* Requires `appSecret` — throws early otherwise, same as
|
|
334
|
+
* `authorizeForAppUser`.
|
|
335
|
+
*
|
|
336
|
+
* @example
|
|
337
|
+
* const { items } = await af.connectors.listResourcesForAppUser('slack', {
|
|
338
|
+
* externalUserId: 'scrappydoc-user-42',
|
|
339
|
+
* });
|
|
340
|
+
*/
|
|
341
|
+
async listResourcesForAppUser(connectorId, input) {
|
|
342
|
+
if (!this.client.getAppSecret()) {
|
|
343
|
+
throw new Error('connectors.listResourcesForAppUser requires appSecret (sk_live_/sk_test_) in ' +
|
|
344
|
+
'AgentForgeClient. This surface authenticates AS the App, not via chatToken/apiKey.');
|
|
345
|
+
}
|
|
346
|
+
const params = new URLSearchParams({ externalUserId: input.externalUserId });
|
|
347
|
+
return this.client.request('GET', `/app-user/connector-resources/${encodeURIComponent(connectorId)}?${params.toString()}`);
|
|
348
|
+
}
|
|
349
|
+
/**
|
|
350
|
+
* `GET /app-user/connector-resources/:connectorId/defaults?externalUserId=...`
|
|
351
|
+
* — tool permissions for this connector, resolved with the App's own
|
|
352
|
+
* override always live (tier 0, `af_app_connectors`) since `appId` comes
|
|
353
|
+
* from the secret. App-user counterpart of `getDefaults()` above.
|
|
354
|
+
* `externalUserId` doesn't affect resolution (defaults are per-App, not
|
|
355
|
+
* per-end-user) — still required because the platform route always reads
|
|
356
|
+
* it off the scope helper shared by this controller's other routes.
|
|
357
|
+
*
|
|
358
|
+
* Requires `appSecret` — throws early otherwise, same as
|
|
359
|
+
* `authorizeForAppUser`.
|
|
360
|
+
*/
|
|
361
|
+
async getDefaultsForAppUser(connectorId, input) {
|
|
362
|
+
if (!this.client.getAppSecret()) {
|
|
363
|
+
throw new Error('connectors.getDefaultsForAppUser requires appSecret (sk_live_/sk_test_) in ' +
|
|
364
|
+
'AgentForgeClient. This surface authenticates AS the App, not via chatToken/apiKey.');
|
|
365
|
+
}
|
|
366
|
+
const params = new URLSearchParams({ externalUserId: input.externalUserId });
|
|
367
|
+
return this.client.request('GET', `/app-user/connector-resources/${encodeURIComponent(connectorId)}/defaults?${params.toString()}`);
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* `PUT /app-user/connector-resources/:connectorId/defaults?externalUserId=...`
|
|
371
|
+
* — overwrites the connector's tool permissions. App-user counterpart of
|
|
372
|
+
* `updateDefaults()` above. NOTE (mirrors the platform controller's own
|
|
373
|
+
* doc comment): this write lands on the tenant-level row
|
|
374
|
+
* (`af_connector_tool_defaults`), same as the ak_live_ route — there's no
|
|
375
|
+
* App-scoped-only override write today. `externalUserId` travels as a
|
|
376
|
+
* query param (matching `getDefaultsForAppUser`); the platform route also
|
|
377
|
+
* accepts it in the body but query is canonical for this SDK's GET/PUT
|
|
378
|
+
* pair.
|
|
379
|
+
*
|
|
380
|
+
* Requires `appSecret` — throws early otherwise, same as
|
|
381
|
+
* `authorizeForAppUser`.
|
|
382
|
+
*/
|
|
383
|
+
async updateDefaultsForAppUser(connectorId, permissions, input) {
|
|
384
|
+
if (!this.client.getAppSecret()) {
|
|
385
|
+
throw new Error('connectors.updateDefaultsForAppUser requires appSecret (sk_live_/sk_test_) in ' +
|
|
386
|
+
'AgentForgeClient. This surface authenticates AS the App, not via chatToken/apiKey.');
|
|
387
|
+
}
|
|
388
|
+
const params = new URLSearchParams({ externalUserId: input.externalUserId });
|
|
389
|
+
return this.client.request('PUT', `/app-user/connector-resources/${encodeURIComponent(connectorId)}/defaults?${params.toString()}`, { permissions });
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* `POST /app-user/connector-resources/clickup/tasks` — creates a REAL
|
|
393
|
+
* ClickUp task using the end user's OWN grant. App-user counterpart of
|
|
394
|
+
* `createClickupTask()` above. Unlike the GET/PUT methods above,
|
|
395
|
+
* `externalUserId` travels in the BODY here — the platform route reads it
|
|
396
|
+
* off `body.externalUserId` for this action endpoint (not a query param).
|
|
397
|
+
*
|
|
398
|
+
* Requires `appSecret` — throws early otherwise, same as
|
|
399
|
+
* `authorizeForAppUser`.
|
|
400
|
+
*/
|
|
401
|
+
async createClickupTaskForAppUser(input) {
|
|
402
|
+
if (!this.client.getAppSecret()) {
|
|
403
|
+
throw new Error('connectors.createClickupTaskForAppUser requires appSecret (sk_live_/sk_test_) in ' +
|
|
404
|
+
'AgentForgeClient. This surface authenticates AS the App, not via chatToken/apiKey.');
|
|
405
|
+
}
|
|
406
|
+
return this.client.request('POST', '/app-user/connector-resources/clickup/tasks', input);
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* `POST /app-user/connector-resources/slack/messages` — posts a REAL
|
|
410
|
+
* Slack message using the end user's OWN grant. App-user counterpart of
|
|
411
|
+
* `postSlackMessage()` above. `externalUserId` travels in the BODY, same
|
|
412
|
+
* as `createClickupTaskForAppUser` (the platform route reads
|
|
413
|
+
* `body.externalUserId` for both action endpoints).
|
|
414
|
+
*
|
|
415
|
+
* Requires `appSecret` — throws early otherwise, same as
|
|
416
|
+
* `authorizeForAppUser`.
|
|
417
|
+
*/
|
|
418
|
+
async postSlackMessageForAppUser(input) {
|
|
419
|
+
if (!this.client.getAppSecret()) {
|
|
420
|
+
throw new Error('connectors.postSlackMessageForAppUser requires appSecret (sk_live_/sk_test_) in ' +
|
|
421
|
+
'AgentForgeClient. This surface authenticates AS the App, not via chatToken/apiKey.');
|
|
422
|
+
}
|
|
423
|
+
return this.client.request('POST', '/app-user/connector-resources/slack/messages', input);
|
|
424
|
+
}
|
|
425
|
+
/**
|
|
426
|
+
* `POST /app-user/connector-resources/:connectorId/api-key` — guarda un
|
|
427
|
+
* API key pegado por el end user, para SU PROPIO grant (no el tenant del
|
|
428
|
+
* App). App-user counterpart of `saveApiKeyForTenant()` above, para
|
|
429
|
+
* connectors que NO usan OAuth (Granola, Mapbox). `externalUserId` viaja
|
|
430
|
+
* en el BODY, mismo patrón que `createClickupTaskForAppUser`/
|
|
431
|
+
* `postSlackMessageForAppUser`.
|
|
432
|
+
*
|
|
433
|
+
* Requires `appSecret` — throws early otherwise, same as
|
|
434
|
+
* `authorizeForAppUser`.
|
|
435
|
+
*
|
|
436
|
+
* @example
|
|
437
|
+
* await af.connectors.saveApiKeyForAppUser('granola', 'grn_xxxxx', {
|
|
438
|
+
* externalUserId: 'scrappydoc-user-42',
|
|
439
|
+
* });
|
|
440
|
+
*/
|
|
441
|
+
async saveApiKeyForAppUser(connectorId, apiKey, input) {
|
|
442
|
+
if (!this.client.getAppSecret()) {
|
|
443
|
+
throw new Error('connectors.saveApiKeyForAppUser requires appSecret (sk_live_/sk_test_) in ' +
|
|
444
|
+
'AgentForgeClient. This surface authenticates AS the App, not via chatToken/apiKey.');
|
|
445
|
+
}
|
|
446
|
+
return this.client.request('POST', `/app-user/connector-resources/${encodeURIComponent(connectorId)}/api-key`, { apiKey, externalUserId: input.externalUserId });
|
|
447
|
+
}
|
|
206
448
|
}
|
|
207
449
|
exports.ConnectorsResource = ConnectorsResource;
|
package/dist/types.d.ts
CHANGED
|
@@ -319,6 +319,21 @@ export interface ConnectorStatus {
|
|
|
319
319
|
* false = se puede conectar pero `listResources()` devuelve `unsupported`. */
|
|
320
320
|
browsable: boolean;
|
|
321
321
|
}
|
|
322
|
+
export interface AppUserConnectorStatus {
|
|
323
|
+
connectorId: string;
|
|
324
|
+
name: string;
|
|
325
|
+
description: string;
|
|
326
|
+
category?: string;
|
|
327
|
+
iconUrl?: string;
|
|
328
|
+
/** El operador del tenant ya trajo credenciales para este provider. Si es
|
|
329
|
+
* `false`, este end user no puede conectar todavía (falta setup admin). */
|
|
330
|
+
configured: boolean;
|
|
331
|
+
/** Este externalUserId particular ya completó el OAuth/API-key setup. */
|
|
332
|
+
connected: boolean;
|
|
333
|
+
accountLabel?: string;
|
|
334
|
+
/** ISO 8601 — `Date` en el server, serializado a string sobre JSON. */
|
|
335
|
+
connectedAt?: string;
|
|
336
|
+
}
|
|
322
337
|
export interface ConnectorResourceItem {
|
|
323
338
|
id: string;
|
|
324
339
|
name: string;
|
package/package.json
CHANGED