@agentforge-io/sdk-server 4.0.21 → 4.1.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/client.d.ts CHANGED
@@ -2,6 +2,7 @@ import { AgentsResource } from './resources/agents';
2
2
  import { AppsResource } from './resources/apps';
3
3
  import { ChatResource } from './resources/chat';
4
4
  import { ConnectorsResource } from './resources/connectors';
5
+ import { ProvisioningResource } from './resources/provisioning';
5
6
  import { SecretsResource } from './resources/secrets';
6
7
  import { ToolsResource } from './resources/tools';
7
8
  export interface AgentForgeClientOptions {
@@ -18,6 +19,13 @@ export interface AgentForgeClientOptions {
18
19
  * header as `apiKey`; the server's ApiKeyGuard accepts both `ak_live_`
19
20
  * and `sk_live_` prefixes. */
20
21
  appSecret?: string;
22
+ /** Machine-to-machine host provisioning secret (`HOST_PROVISIONING_SECRET`).
23
+ * UNLIKE the other three, this is NOT a per-tenant/App credential — it's the
24
+ * shared secret a trusted host (ScrappyDoc) uses to provision tenants/Apps
25
+ * via `af.provisioning.*` (`POST /platform/host-tenants` / `host-apps`). It
26
+ * travels on the `x-provisioning-secret` header, never `Authorization`. A
27
+ * client built with only this can ONLY call the provisioning surface. */
28
+ provisioningSecret?: string;
21
29
  /** Override fetch (for testing or custom transports). */
22
30
  fetch?: typeof fetch;
23
31
  /** Default request timeout in ms. Applied to every HTTP call unless
@@ -46,17 +54,23 @@ export declare class AgentForgeClient {
46
54
  private readonly chatToken?;
47
55
  private readonly apiKey?;
48
56
  private readonly appSecret?;
57
+ private readonly provisioningSecret?;
49
58
  private readonly fetchImpl;
50
59
  private readonly timeoutMs;
51
60
  readonly agents: AgentsResource;
52
61
  readonly apps: AppsResource;
53
62
  readonly chat: ChatResource;
54
63
  readonly connectors: ConnectorsResource;
64
+ readonly provisioning: ProvisioningResource;
55
65
  readonly secrets: SecretsResource;
56
66
  readonly tools: ToolsResource;
57
67
  constructor(opts: AgentForgeClientOptions);
58
68
  authHeaders(): Record<string, string>;
59
69
  getAppSecret(): string | undefined;
70
+ /** The `x-provisioning-secret` header value, or throws if the client wasn't
71
+ * built with one — used by `ProvisioningResource`, whose every call needs
72
+ * it (there is no other auth for the provisioning surface). */
73
+ requireProvisioningSecret(): string;
60
74
  getApiKey(): string | undefined;
61
75
  getChatToken(): string | undefined;
62
76
  /** Como `getApiKey()`, pero tira si el cliente no fue construido con una
package/dist/client.js CHANGED
@@ -24,6 +24,7 @@ const agents_1 = require("./resources/agents");
24
24
  const apps_1 = require("./resources/apps");
25
25
  const chat_1 = require("./resources/chat");
26
26
  const connectors_1 = require("./resources/connectors");
27
+ const provisioning_1 = require("./resources/provisioning");
27
28
  const secrets_1 = require("./resources/secrets");
28
29
  const tools_1 = require("./resources/tools");
29
30
  class AgentForgeClient {
@@ -31,19 +32,25 @@ class AgentForgeClient {
31
32
  if (!opts.baseURL) {
32
33
  throw new Error('AgentForgeClient: baseURL is required');
33
34
  }
34
- if (!opts.chatToken && !opts.apiKey && !opts.appSecret) {
35
- throw new Error('AgentForgeClient: one of chatToken, apiKey, or appSecret is required');
35
+ if (!opts.chatToken &&
36
+ !opts.apiKey &&
37
+ !opts.appSecret &&
38
+ !opts.provisioningSecret) {
39
+ throw new Error('AgentForgeClient: one of chatToken, apiKey, appSecret, or ' +
40
+ 'provisioningSecret is required');
36
41
  }
37
42
  this.baseURL = opts.baseURL.replace(/\/$/, '');
38
43
  this.chatToken = opts.chatToken;
39
44
  this.apiKey = opts.apiKey;
40
45
  this.appSecret = opts.appSecret;
46
+ this.provisioningSecret = opts.provisioningSecret;
41
47
  this.fetchImpl = opts.fetch ?? fetch;
42
48
  this.timeoutMs = opts.timeoutMs ?? 30000;
43
49
  this.agents = new agents_1.AgentsResource(this);
44
50
  this.apps = new apps_1.AppsResource(this);
45
51
  this.chat = new chat_1.ChatResource(this);
46
52
  this.connectors = new connectors_1.ConnectorsResource(this);
53
+ this.provisioning = new provisioning_1.ProvisioningResource(this);
47
54
  this.secrets = new secrets_1.SecretsResource(this);
48
55
  this.tools = new tools_1.ToolsResource(this);
49
56
  }
@@ -63,6 +70,16 @@ class AgentForgeClient {
63
70
  getAppSecret() {
64
71
  return this.appSecret;
65
72
  }
73
+ /** The `x-provisioning-secret` header value, or throws if the client wasn't
74
+ * built with one — used by `ProvisioningResource`, whose every call needs
75
+ * it (there is no other auth for the provisioning surface). */
76
+ requireProvisioningSecret() {
77
+ if (!this.provisioningSecret) {
78
+ throw new Error('AgentForgeClient: this call requires a provisioningSecret ' +
79
+ '(HOST_PROVISIONING_SECRET), but the client was constructed without one.');
80
+ }
81
+ return this.provisioningSecret;
82
+ }
66
83
  // Expone el modo auth para que resources puedan tomar decisiones (ej. chat
67
84
  // proxy necesita la ak_live_ explícita en x-api-key — no ChatToken).
68
85
  getApiKey() {
package/dist/index.d.ts CHANGED
@@ -9,6 +9,8 @@ export { ChatResource } from './resources/chat';
9
9
  export type { AnthropicClientOptions, StreamMessageInput } from './resources/chat';
10
10
  export { ConnectorsResource } from './resources/connectors';
11
11
  export type { InboxChannelView } from './resources/connectors';
12
+ export { ProvisioningResource } from './resources/provisioning';
13
+ export type { ProvisionedTenant, ProvisionedApp, } from './resources/provisioning';
12
14
  export { SecretsResource } from './resources/secrets';
13
15
  export { ToolsResource } from './resources/tools';
14
16
  export type { RespondToCallbackInput, VerifyCallbackInput } from './resources/tools';
package/dist/index.js CHANGED
@@ -28,7 +28,7 @@
28
28
  // const payload = af.tools.verifyCallback({ rawBody, signatureHeader, secretPlaintext });
29
29
  // await af.tools.respondToCallback({ resultUrl: payload.resultUrl, tenantId: payload.tenantId, secret, result });
30
30
  Object.defineProperty(exports, "__esModule", { value: true });
31
- exports.ToolsResource = exports.SecretsResource = exports.ConnectorsResource = exports.ChatResource = exports.AppsResource = exports.AgentsResource = exports.verifyToolCallbackSignature = exports.signToolCallbackPayload = exports.ToolCallbackSignatureError = exports.TOOL_CALLBACK_HEADERS = exports.AgentForgeNetworkError = exports.AgentForgeNotFoundError = exports.AgentForgeAuthError = exports.AgentForgeError = exports.AgentForgeClient = void 0;
31
+ exports.ToolsResource = exports.SecretsResource = exports.ProvisioningResource = exports.ConnectorsResource = exports.ChatResource = exports.AppsResource = exports.AgentsResource = exports.verifyToolCallbackSignature = exports.signToolCallbackPayload = exports.ToolCallbackSignatureError = exports.TOOL_CALLBACK_HEADERS = exports.AgentForgeNetworkError = exports.AgentForgeNotFoundError = exports.AgentForgeAuthError = exports.AgentForgeError = exports.AgentForgeClient = void 0;
32
32
  var client_1 = require("./client");
33
33
  Object.defineProperty(exports, "AgentForgeClient", { enumerable: true, get: function () { return client_1.AgentForgeClient; } });
34
34
  var errors_1 = require("./errors");
@@ -49,6 +49,8 @@ var chat_1 = require("./resources/chat");
49
49
  Object.defineProperty(exports, "ChatResource", { enumerable: true, get: function () { return chat_1.ChatResource; } });
50
50
  var connectors_1 = require("./resources/connectors");
51
51
  Object.defineProperty(exports, "ConnectorsResource", { enumerable: true, get: function () { return connectors_1.ConnectorsResource; } });
52
+ var provisioning_1 = require("./resources/provisioning");
53
+ Object.defineProperty(exports, "ProvisioningResource", { enumerable: true, get: function () { return provisioning_1.ProvisioningResource; } });
52
54
  var secrets_1 = require("./resources/secrets");
53
55
  Object.defineProperty(exports, "SecretsResource", { enumerable: true, get: function () { return secrets_1.SecretsResource; } });
54
56
  var tools_1 = require("./resources/tools");
@@ -9,6 +9,20 @@ export interface StreamMessageInput {
9
9
  /** Si se omite, el server crea una conversación nueva. */
10
10
  conversationId?: string;
11
11
  }
12
+ export interface StreamMessageForAppUserInput {
13
+ /** Which of the App's tenant agents to run. */
14
+ agentId: string;
15
+ /** The App's own identifier for its end user — NOT signed, rides as a
16
+ * plain param inside the sk_live_-authenticated request (AGF-072 §4.4
17
+ * rationale: the authenticated channel is the proof, not a per-user
18
+ * signature). Threads into the conversation key
19
+ * `app-user:${appId}:${externalUserId}` server-side; `appId` itself is
20
+ * never a param, only ever resolved from the secret. */
21
+ externalUserId: string;
22
+ content: string;
23
+ /** Si se omite, el server crea una conversación nueva. */
24
+ conversationId?: string;
25
+ }
12
26
  export declare class ChatResource {
13
27
  private readonly client;
14
28
  constructor(client: AgentForgeClient);
@@ -52,4 +66,37 @@ export declare class ChatResource {
52
66
  * no pertenece al ChatToken que llama.
53
67
  */
54
68
  getHistory(conversationId: string): Promise<ConversationHistory>;
69
+ /**
70
+ * AGF-073a — chat streaming AGENT-AWARE para el surface App-authenticated
71
+ * (`sk_live_`/`sk_test_`), server-to-server — `POST
72
+ * /api/v1/app-user-chat/conversations/stream` (o `.../conversations/:id/
73
+ * messages/stream` cuando `input.conversationId` viene seteado). Sibling
74
+ * ADITIVO de `streamMessage()`: NO usa ChatToken, requiere que el
75
+ * `AgentForgeClient` se haya construido con `appSecret`. `appId` lo
76
+ * resuelve el server exclusivamente del secret — nunca es un param acá
77
+ * tampoco (ver `APP_USER_CHAT_RUNTIME_SDD.md`).
78
+ *
79
+ * Mismo shape de eventos que `streamMessage()` — `ChatStreamEvent` con
80
+ * los mismos `kind`s (`conversation` | `chunk` | `stream_end` | `error`).
81
+ * Un consumidor no puede distinguir cuál de los dos métodos produjo el
82
+ * stream a partir de los eventos solos.
83
+ *
84
+ * @example
85
+ * const af = new AgentForgeClient({ baseURL, appSecret: 'sk_live_...' });
86
+ * for await (const ev of af.chat.streamMessageForAppUser({
87
+ * agentId: 'agent-uuid',
88
+ * externalUserId: 'scrappydoc-user-42',
89
+ * content: 'hola',
90
+ * })) {
91
+ * if (ev.kind === 'conversation') conversationId = ev.conversationId;
92
+ * }
93
+ */
94
+ streamMessageForAppUser(input: StreamMessageForAppUserInput): AsyncGenerator<ChatStreamEvent>;
95
+ /**
96
+ * AGF-073a companion to `streamMessageForAppUser` — historial completo de
97
+ * una conversación app-user, `GET /api/v1/app-user-chat/conversations/:id/
98
+ * messages?externalUserId=...`. `externalUserId` va como query param
99
+ * porque GET no lleva body; `appId` sigue resolviéndose del secret.
100
+ */
101
+ getHistoryForAppUser(conversationId: string, externalUserId: string): Promise<ConversationHistory>;
55
102
  }
@@ -110,6 +110,86 @@ class ChatResource {
110
110
  async getHistory(conversationId) {
111
111
  return this.client.request('GET', `/api/v1/chat/conversations/${encodeURIComponent(conversationId)}/messages`);
112
112
  }
113
+ /**
114
+ * AGF-073a — chat streaming AGENT-AWARE para el surface App-authenticated
115
+ * (`sk_live_`/`sk_test_`), server-to-server — `POST
116
+ * /api/v1/app-user-chat/conversations/stream` (o `.../conversations/:id/
117
+ * messages/stream` cuando `input.conversationId` viene seteado). Sibling
118
+ * ADITIVO de `streamMessage()`: NO usa ChatToken, requiere que el
119
+ * `AgentForgeClient` se haya construido con `appSecret`. `appId` lo
120
+ * resuelve el server exclusivamente del secret — nunca es un param acá
121
+ * tampoco (ver `APP_USER_CHAT_RUNTIME_SDD.md`).
122
+ *
123
+ * Mismo shape de eventos que `streamMessage()` — `ChatStreamEvent` con
124
+ * los mismos `kind`s (`conversation` | `chunk` | `stream_end` | `error`).
125
+ * Un consumidor no puede distinguir cuál de los dos métodos produjo el
126
+ * stream a partir de los eventos solos.
127
+ *
128
+ * @example
129
+ * const af = new AgentForgeClient({ baseURL, appSecret: 'sk_live_...' });
130
+ * for await (const ev of af.chat.streamMessageForAppUser({
131
+ * agentId: 'agent-uuid',
132
+ * externalUserId: 'scrappydoc-user-42',
133
+ * content: 'hola',
134
+ * })) {
135
+ * if (ev.kind === 'conversation') conversationId = ev.conversationId;
136
+ * }
137
+ */
138
+ async *streamMessageForAppUser(input) {
139
+ if (!this.client.getAppSecret()) {
140
+ throw new Error('chat.streamMessageForAppUser requires appSecret (sk_live_/sk_test_) in ' +
141
+ 'AgentForgeClient. This surface authenticates AS the App, not via chatToken.');
142
+ }
143
+ const path = input.conversationId
144
+ ? `/api/v1/app-user-chat/conversations/${encodeURIComponent(input.conversationId)}/messages/stream`
145
+ : '/api/v1/app-user-chat/conversations/stream';
146
+ const res = await this.client.requestStream('POST', path, {
147
+ agentId: input.agentId,
148
+ externalUserId: input.externalUserId,
149
+ content: input.content,
150
+ });
151
+ if (!res.body) {
152
+ throw new Error('chat.streamMessageForAppUser: response has no readable body');
153
+ }
154
+ const reader = res.body.getReader();
155
+ const decoder = new TextDecoder();
156
+ let buffer = '';
157
+ try {
158
+ for (;;) {
159
+ const { value, done } = await reader.read();
160
+ if (done)
161
+ break;
162
+ buffer += decoder.decode(value, { stream: true });
163
+ let idx;
164
+ while ((idx = buffer.indexOf('\n\n')) !== -1) {
165
+ const frame = buffer.slice(0, idx);
166
+ buffer = buffer.slice(idx + 2);
167
+ const raw = parseRawSseFrame(frame);
168
+ if (!raw)
169
+ continue;
170
+ const event = toChatStreamEvent(raw);
171
+ if (event)
172
+ yield event;
173
+ }
174
+ }
175
+ }
176
+ finally {
177
+ reader.releaseLock();
178
+ }
179
+ }
180
+ /**
181
+ * AGF-073a companion to `streamMessageForAppUser` — historial completo de
182
+ * una conversación app-user, `GET /api/v1/app-user-chat/conversations/:id/
183
+ * messages?externalUserId=...`. `externalUserId` va como query param
184
+ * porque GET no lleva body; `appId` sigue resolviéndose del secret.
185
+ */
186
+ async getHistoryForAppUser(conversationId, externalUserId) {
187
+ if (!this.client.getAppSecret()) {
188
+ throw new Error('chat.getHistoryForAppUser requires appSecret (sk_live_/sk_test_) in AgentForgeClient.');
189
+ }
190
+ return this.client.request('GET', `/api/v1/app-user-chat/conversations/${encodeURIComponent(conversationId)}/messages` +
191
+ `?externalUserId=${encodeURIComponent(externalUserId)}`);
192
+ }
113
193
  }
114
194
  exports.ChatResource = ChatResource;
115
195
  /** Frame SSE genérico: `event: <name>\ndata: <line>\ndata: <line>...`.
@@ -0,0 +1,52 @@
1
+ import type { AgentForgeClient } from '../client';
2
+ /** `POST /platform/host-tenants` result — a fresh tenant + its first ak_live_. */
3
+ export interface ProvisionedTenant {
4
+ tenantId: string;
5
+ apiKey: string;
6
+ }
7
+ /** `POST /platform/host-apps` result — a published platform App's identity +
8
+ * one-time-reveal sk_live_. */
9
+ export interface ProvisionedApp {
10
+ appId: string;
11
+ publicKey: string;
12
+ appSecret: string;
13
+ }
14
+ export declare class ProvisioningResource {
15
+ private readonly client;
16
+ constructor(client: AgentForgeClient);
17
+ private headers;
18
+ /**
19
+ * `POST /platform/host-tenants` — create a new tenant and its first
20
+ * `ak_live_` key on behalf of a trusted host app. Idempotency is the
21
+ * caller's concern (the host caches the returned `{tenantId, apiKey}`); the
22
+ * server mints a fresh tenant on every call.
23
+ *
24
+ * @param input.name display name (e.g. the host workspace's name)
25
+ * @param input.hostApp short host id (e.g. "scrappydoc") — determines the
26
+ * service account that owns the tenant
27
+ * @param input.hostRef host reference (e.g. the workspaceId) — traceability
28
+ */
29
+ tenant(input: {
30
+ name: string;
31
+ hostApp: string;
32
+ hostRef?: string;
33
+ }): Promise<ProvisionedTenant>;
34
+ /**
35
+ * `POST /platform/host-apps` (AGF-071a) — mint (or re-provision) a PUBLISHED
36
+ * platform App for an EXISTING tenant. Idempotent by `(tenantId, hostApp,
37
+ * hostRef)`: a re-provision returns the SAME `appId` with a freshly rotated
38
+ * `sk_live_` (the one-time-reveal secret may have been lost), never a
39
+ * duplicate App.
40
+ *
41
+ * @param input.tenantId the tenant the App belongs to (host provisions it
42
+ * first via `tenant()`)
43
+ * @param input.hostApp short host id (e.g. "scrappydoc")
44
+ * @param input.hostRef host reference (e.g. the workspaceId) — part of the
45
+ * idempotency key; defaults server-side to `tenantId`
46
+ */
47
+ app(input: {
48
+ tenantId: string;
49
+ hostApp: string;
50
+ hostRef?: string;
51
+ }): Promise<ProvisionedApp>;
52
+ }
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ // provisioning resource (AGF-071c) — machine-to-machine host provisioning of
3
+ // tenants and Apps. Lets a trusted host (ScrappyDoc) create a tenant + its
4
+ // ak_live_, and mint a platform App (pk_live_/sk_live_) for that tenant, WITHOUT
5
+ // hand-rolling a fetch — the SDK-first rule applies to provisioning too.
6
+ //
7
+ // Auth: UNLIKE every other resource, these calls don't use a per-tenant/App
8
+ // credential. They authenticate with the shared `HOST_PROVISIONING_SECRET` on
9
+ // the `x-provisioning-secret` header (the client must be built with
10
+ // `provisioningSecret`). The server gates both endpoints with
11
+ // `HostProvisioningGuard`, not `ApiKeyGuard`.
12
+ //
13
+ // These endpoints are `@Public()` on the server (the guard is the secret), so
14
+ // a client built with ONLY `{ baseURL, provisioningSecret }` can call them.
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.ProvisioningResource = void 0;
17
+ class ProvisioningResource {
18
+ constructor(client) {
19
+ this.client = client;
20
+ }
21
+ headers() {
22
+ return { 'x-provisioning-secret': this.client.requireProvisioningSecret() };
23
+ }
24
+ /**
25
+ * `POST /platform/host-tenants` — create a new tenant and its first
26
+ * `ak_live_` key on behalf of a trusted host app. Idempotency is the
27
+ * caller's concern (the host caches the returned `{tenantId, apiKey}`); the
28
+ * server mints a fresh tenant on every call.
29
+ *
30
+ * @param input.name display name (e.g. the host workspace's name)
31
+ * @param input.hostApp short host id (e.g. "scrappydoc") — determines the
32
+ * service account that owns the tenant
33
+ * @param input.hostRef host reference (e.g. the workspaceId) — traceability
34
+ */
35
+ async tenant(input) {
36
+ return this.client.request('POST', '/platform/host-tenants', { name: input.name, hostApp: input.hostApp, hostRef: input.hostRef }, { headers: this.headers() });
37
+ }
38
+ /**
39
+ * `POST /platform/host-apps` (AGF-071a) — mint (or re-provision) a PUBLISHED
40
+ * platform App for an EXISTING tenant. Idempotent by `(tenantId, hostApp,
41
+ * hostRef)`: a re-provision returns the SAME `appId` with a freshly rotated
42
+ * `sk_live_` (the one-time-reveal secret may have been lost), never a
43
+ * duplicate App.
44
+ *
45
+ * @param input.tenantId the tenant the App belongs to (host provisions it
46
+ * first via `tenant()`)
47
+ * @param input.hostApp short host id (e.g. "scrappydoc")
48
+ * @param input.hostRef host reference (e.g. the workspaceId) — part of the
49
+ * idempotency key; defaults server-side to `tenantId`
50
+ */
51
+ async app(input) {
52
+ return this.client.request('POST', '/platform/host-apps', { tenantId: input.tenantId, hostApp: input.hostApp, hostRef: input.hostRef }, { headers: this.headers() });
53
+ }
54
+ }
55
+ exports.ProvisioningResource = ProvisioningResource;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge-io/sdk-server",
3
- "version": "4.0.21",
3
+ "version": "4.1.0",
4
4
  "description": "Server-side SDK for backend apps integrating with AgentForge platform. Auth via ChatToken or ak_live_ API key.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",