@applica-software-guru/persona-sdk 0.1.113 → 0.1.114
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/bundle.cjs.js +1 -1
- package/dist/bundle.cjs.js.map +1 -1
- package/dist/bundle.es.js +316 -274
- package/dist/bundle.es.js.map +1 -1
- package/dist/index.d.ts +75 -0
- package/package.json +1 -1
- package/src/index.ts +6 -0
- package/src/workflows/channels-api.ts +61 -0
- package/src/workflows/types.ts +45 -0
- package/src/workflows/workflows-api.ts +5 -0
- package/tests/channels-api.test.mjs +55 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { HttpApi } from '../http-api';
|
|
2
|
+
import { AuthenticationProvider } from '../auth/authentication-provider';
|
|
3
|
+
import { ChannelIdentity, ChannelLink, ChannelProvider, NotificationChannel } from './types';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Notification channels: where the project's human tasks are announced and
|
|
7
|
+
* can be answered outside the inbox (a Telegram group, one message per
|
|
8
|
+
* task). Linking goes through one-shot deep links returned by the service.
|
|
9
|
+
* Identity endpoints require a user (IAM bearer) session. Lives on the
|
|
10
|
+
* workflows service.
|
|
11
|
+
*/
|
|
12
|
+
export class ChannelsApi extends HttpApi {
|
|
13
|
+
constructor(baseUrl: string, auth: string | AuthenticationProvider) {
|
|
14
|
+
super(baseUrl, auth);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** The providers enabled on the server (e.g. the Telegram bot). */
|
|
18
|
+
async providers(): Promise<ChannelProvider[]> {
|
|
19
|
+
return this.httpGet<ChannelProvider[]>('/channels/providers');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** The project's channels, with their setup status. */
|
|
23
|
+
async list(): Promise<NotificationChannel[]> {
|
|
24
|
+
return this.httpGet<NotificationChannel[]>('/channels');
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** One-shot deep link that links a group to the project. */
|
|
28
|
+
async createLink(provider = 'telegram'): Promise<ChannelLink> {
|
|
29
|
+
return this.httpPost<ChannelLink>('/channels/' + provider + '/link-token');
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async update(
|
|
33
|
+
channelId: string,
|
|
34
|
+
changes: { includePayload?: boolean; locale?: string }
|
|
35
|
+
): Promise<NotificationChannel> {
|
|
36
|
+
return this.httpPatch<NotificationChannel>('/channels/' + channelId, changes);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/** Re-checks the channel setup (the bot can still post in the group). */
|
|
40
|
+
async verify(channelId: string): Promise<NotificationChannel> {
|
|
41
|
+
return this.httpPost<NotificationChannel>('/channels/' + channelId + '/verify');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async unlink(channelId: string): Promise<void> {
|
|
45
|
+
await this.httpDelete('/channels/' + channelId);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** The caller's linked accounts. */
|
|
49
|
+
async myIdentities(): Promise<ChannelIdentity[]> {
|
|
50
|
+
return this.httpGet<ChannelIdentity[]>('/channels/identities/me');
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/** One-shot deep link that links the caller's account. */
|
|
54
|
+
async createIdentityLink(provider = 'telegram'): Promise<ChannelLink> {
|
|
55
|
+
return this.httpPost<ChannelLink>('/channels/identities/' + provider + '/link-token');
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async unlinkIdentity(provider = 'telegram'): Promise<void> {
|
|
59
|
+
await this.httpDelete('/channels/identities/me/' + provider);
|
|
60
|
+
}
|
|
61
|
+
}
|
package/src/workflows/types.ts
CHANGED
|
@@ -152,6 +152,8 @@ export interface HumanTask {
|
|
|
152
152
|
origin?: 'node' | 'agent_escalation';
|
|
153
153
|
question?: string;
|
|
154
154
|
payload?: Record<string, unknown>;
|
|
155
|
+
/** Closed set of answers (buttons); absent = free-text answer. */
|
|
156
|
+
options?: string[];
|
|
155
157
|
assignee?: string;
|
|
156
158
|
role?: string;
|
|
157
159
|
status: string;
|
|
@@ -163,6 +165,49 @@ export interface HumanTask {
|
|
|
163
165
|
sessionCode?: string;
|
|
164
166
|
}
|
|
165
167
|
|
|
168
|
+
export type ChannelStatus = 'active' | 'incomplete' | 'disconnected';
|
|
169
|
+
|
|
170
|
+
/** A place where a project's human tasks are announced (e.g. a Telegram group). */
|
|
171
|
+
export interface NotificationChannel {
|
|
172
|
+
id: string;
|
|
173
|
+
projectId: string;
|
|
174
|
+
provider: string;
|
|
175
|
+
chatId: string;
|
|
176
|
+
title?: string;
|
|
177
|
+
status: ChannelStatus;
|
|
178
|
+
/** Why the channel is not active (e.g. `removed`, `cannot_post`). */
|
|
179
|
+
statusDetail?: string;
|
|
180
|
+
includePayload: boolean;
|
|
181
|
+
locale: string;
|
|
182
|
+
linkedBy?: string;
|
|
183
|
+
createdAt?: string;
|
|
184
|
+
updatedAt?: string;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/** An external account linked to the current user. */
|
|
188
|
+
export interface ChannelIdentity {
|
|
189
|
+
id: string;
|
|
190
|
+
provider: string;
|
|
191
|
+
externalUserId: string;
|
|
192
|
+
externalUsername?: string;
|
|
193
|
+
iamUserId: string;
|
|
194
|
+
iamUserEmail?: string;
|
|
195
|
+
createdAt?: string;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export interface ChannelProvider {
|
|
199
|
+
provider: string;
|
|
200
|
+
botUsername?: string;
|
|
201
|
+
ready: boolean;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** One-shot deep link completing a group or account link. */
|
|
205
|
+
export interface ChannelLink {
|
|
206
|
+
token: string;
|
|
207
|
+
url: string;
|
|
208
|
+
expiresAt: string;
|
|
209
|
+
}
|
|
210
|
+
|
|
166
211
|
export interface Workflow {
|
|
167
212
|
id?: string;
|
|
168
213
|
projectId?: string;
|
|
@@ -5,6 +5,7 @@ import { Revision } from '../revisions/types';
|
|
|
5
5
|
import { Workflow } from './types';
|
|
6
6
|
import { WorkflowExecutionsApi } from './workflow-executions-api';
|
|
7
7
|
import { HumanTasksApi } from './human-tasks-api';
|
|
8
|
+
import { ChannelsApi } from './channels-api';
|
|
8
9
|
|
|
9
10
|
export class WorkflowsApi extends HttpApi {
|
|
10
11
|
constructor(baseUrl: string, auth: string | AuthenticationProvider) {
|
|
@@ -43,6 +44,10 @@ export class WorkflowsApi extends HttpApi {
|
|
|
43
44
|
return new HumanTasksApi(this.getBaseUrl(), this.getAuthProvider());
|
|
44
45
|
}
|
|
45
46
|
|
|
47
|
+
channels(): ChannelsApi {
|
|
48
|
+
return new ChannelsApi(this.getBaseUrl(), this.getAuthProvider());
|
|
49
|
+
}
|
|
50
|
+
|
|
46
51
|
async listRevisions(workflowId: string): Promise<Revision[]> {
|
|
47
52
|
return this.httpGet<Revision[]>('/workflows/' + workflowId + '/revisions');
|
|
48
53
|
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import test from 'node:test';
|
|
3
|
+
|
|
4
|
+
import { ChannelsApi } from '../dist/bundle.es.js';
|
|
5
|
+
|
|
6
|
+
function jsonResponse(body) {
|
|
7
|
+
return new Response(JSON.stringify(body), {
|
|
8
|
+
status: 200,
|
|
9
|
+
headers: { 'Content-Type': 'application/json' },
|
|
10
|
+
});
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function recordFetch(context, body) {
|
|
14
|
+
const originalFetch = globalThis.fetch;
|
|
15
|
+
context.after(() => {
|
|
16
|
+
globalThis.fetch = originalFetch;
|
|
17
|
+
});
|
|
18
|
+
const calls = [];
|
|
19
|
+
globalThis.fetch = async (url, init) => {
|
|
20
|
+
calls.push({ url: String(url), method: init.method, body: init.body ? JSON.parse(init.body) : undefined });
|
|
21
|
+
return jsonResponse(body);
|
|
22
|
+
};
|
|
23
|
+
return calls;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
test('createLink asks the workflows service for a group deep link', async (context) => {
|
|
27
|
+
const link = { token: 't', url: 'https://t.me/bot?startgroup=t', expiresAt: '2026-10-28T10:00:00' };
|
|
28
|
+
const calls = recordFetch(context, link);
|
|
29
|
+
|
|
30
|
+
const api = new ChannelsApi('https://workflows.test', 'api-key');
|
|
31
|
+
const result = await api.createLink();
|
|
32
|
+
|
|
33
|
+
assert.equal(calls[0].method, 'POST');
|
|
34
|
+
assert.equal(calls[0].url, 'https://workflows.test/channels/telegram/link-token');
|
|
35
|
+
assert.equal(result.url, link.url);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('identity links and settings use the expected endpoints', async (context) => {
|
|
39
|
+
const calls = recordFetch(context, {});
|
|
40
|
+
const api = new ChannelsApi('https://workflows.test', 'api-key');
|
|
41
|
+
|
|
42
|
+
await api.createIdentityLink();
|
|
43
|
+
await api.update('wf-chan_1', { includePayload: false });
|
|
44
|
+
await api.verify('wf-chan_1');
|
|
45
|
+
|
|
46
|
+
assert.deepEqual(
|
|
47
|
+
calls.map((call) => `${call.method} ${call.url}`),
|
|
48
|
+
[
|
|
49
|
+
'POST https://workflows.test/channels/identities/telegram/link-token',
|
|
50
|
+
'PATCH https://workflows.test/channels/wf-chan_1',
|
|
51
|
+
'POST https://workflows.test/channels/wf-chan_1/verify',
|
|
52
|
+
]
|
|
53
|
+
);
|
|
54
|
+
assert.deepEqual(calls[1].body, { includePayload: false });
|
|
55
|
+
});
|