@attrove/sdk 0.1.11 → 0.1.13
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/README.md +5 -2
- package/cjs/constants.js +1 -1
- package/cjs/resources/messages.js +3 -0
- package/cjs/resources/query.js +160 -7
- package/cjs/types/index.js +109 -66
- package/cjs/utils/streaming.js +16 -0
- package/esm/constants.d.ts +1 -1
- package/esm/constants.js +1 -1
- package/esm/resources/messages.d.ts.map +1 -1
- package/esm/resources/messages.js +3 -0
- package/esm/resources/messages.js.map +1 -1
- package/esm/resources/query.d.ts +12 -6
- package/esm/resources/query.d.ts.map +1 -1
- package/esm/resources/query.js +160 -7
- package/esm/resources/query.js.map +1 -1
- package/esm/types/index.d.ts +191 -51
- package/esm/types/index.d.ts.map +1 -1
- package/esm/types/index.js +107 -65
- package/esm/types/index.js.map +1 -1
- package/esm/utils/streaming.d.ts +9 -1
- package/esm/utils/streaming.d.ts.map +1 -1
- package/esm/utils/streaming.js +16 -0
- package/esm/utils/streaming.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,6 +41,9 @@ Ask questions about the user's unified context with AI-generated answers.
|
|
|
41
41
|
// Simple query
|
|
42
42
|
const response = await attrove.query('What did Sarah say about the Q4 budget?');
|
|
43
43
|
console.log(response.answer);
|
|
44
|
+
console.log(response.used_message_ids); // msg_xxx IDs
|
|
45
|
+
console.log(response.used_meeting_ids); // mtg_xxx IDs
|
|
46
|
+
console.log(response.used_event_ids); // evt_xxx IDs
|
|
44
47
|
|
|
45
48
|
// Multi-turn conversation - pass history from previous response
|
|
46
49
|
let history = response.history;
|
|
@@ -50,14 +53,14 @@ history = followUp.history;
|
|
|
50
53
|
|
|
51
54
|
// With filters
|
|
52
55
|
const filtered = await attrove.query('Latest updates', {
|
|
53
|
-
integrationIds: ['
|
|
56
|
+
integrationIds: ['int_xxx'], // Only search specific integration
|
|
54
57
|
includeSources: true // Include source snippets
|
|
55
58
|
});
|
|
56
59
|
```
|
|
57
60
|
|
|
58
61
|
### `search(query, options?)`
|
|
59
62
|
|
|
60
|
-
Semantic search that returns raw messages without AI summarization.
|
|
63
|
+
Semantic search that returns raw matches across messages, meetings, and events without AI summarization.
|
|
61
64
|
|
|
62
65
|
```typescript
|
|
63
66
|
const results = await attrove.search('product launch', {
|
package/cjs/constants.js
CHANGED
|
@@ -13,7 +13,7 @@ exports.getWsCloseReason = exports.WS_CLOSE_CODES = exports.RETRYABLE_STATUS_SET
|
|
|
13
13
|
* Automatically synchronized with package.json during the release process.
|
|
14
14
|
* For programmatic access, use `getVersion()` from './version'.
|
|
15
15
|
*/
|
|
16
|
-
exports.SDK_VERSION = "0.1.
|
|
16
|
+
exports.SDK_VERSION = "0.1.13"; // auto-synced from package.json during release
|
|
17
17
|
/**
|
|
18
18
|
* Default API base URL for Attrove services.
|
|
19
19
|
*/
|
|
@@ -65,6 +65,9 @@ class MessagesResource {
|
|
|
65
65
|
if (options.offset !== undefined) {
|
|
66
66
|
params.offset = String(options.offset);
|
|
67
67
|
}
|
|
68
|
+
if (options.excludeBots !== undefined) {
|
|
69
|
+
params.exclude_bots = String(options.excludeBots);
|
|
70
|
+
}
|
|
68
71
|
if (options.expand?.length) {
|
|
69
72
|
params.expand = options.expand.join(",");
|
|
70
73
|
}
|
package/cjs/resources/query.js
CHANGED
|
@@ -6,6 +6,146 @@
|
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
8
|
exports.QueryResource = void 0;
|
|
9
|
+
function normalizeOptionalId(value) {
|
|
10
|
+
return value == null ? null : String(value);
|
|
11
|
+
}
|
|
12
|
+
function normalizeRequiredId(value) {
|
|
13
|
+
return String(value);
|
|
14
|
+
}
|
|
15
|
+
function normalizeKeyMessage(message) {
|
|
16
|
+
return {
|
|
17
|
+
message_id: normalizeRequiredId(message.message_id),
|
|
18
|
+
thread_id: normalizeOptionalId(message.thread_id),
|
|
19
|
+
conversation_id: normalizeOptionalId(message.conversation_id),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function normalizeThreadMessage(message) {
|
|
23
|
+
return {
|
|
24
|
+
message_id: normalizeRequiredId(message.message_id),
|
|
25
|
+
received_at: message.received_at,
|
|
26
|
+
integration_type: normalizeIntegrationType(message.integration_type),
|
|
27
|
+
integration_type_generic: message.integration_type_generic,
|
|
28
|
+
sender_name: message.sender_name,
|
|
29
|
+
recipient_names: message.recipient_names,
|
|
30
|
+
body_text: message.body_text,
|
|
31
|
+
thread_id: normalizeOptionalId(message.thread_id),
|
|
32
|
+
thread_message_count: message.thread_message_count,
|
|
33
|
+
thread_position: message.thread_position,
|
|
34
|
+
parent_message_id: normalizeOptionalId(message.parent_message_id),
|
|
35
|
+
conversation_type: message.conversation_type,
|
|
36
|
+
conversation_id: normalizeOptionalId(message.conversation_id),
|
|
37
|
+
conversation_participants: message.conversation_participants,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
const VALID_MEETING_PROVIDERS = new Set([
|
|
41
|
+
'google_meet',
|
|
42
|
+
'zoom',
|
|
43
|
+
'teams',
|
|
44
|
+
'unknown',
|
|
45
|
+
]);
|
|
46
|
+
function normalizeMeetingProvider(provider) {
|
|
47
|
+
if (VALID_MEETING_PROVIDERS.has(provider)) {
|
|
48
|
+
return provider;
|
|
49
|
+
}
|
|
50
|
+
// prettier-ignore
|
|
51
|
+
console.warn(`[Attrove SDK] Unknown meeting provider "${provider}" normalized to "unknown". SDK may need updating.`);
|
|
52
|
+
return 'unknown';
|
|
53
|
+
}
|
|
54
|
+
const VALID_INTEGRATION_TYPES = new Set([
|
|
55
|
+
'slack',
|
|
56
|
+
'gmail',
|
|
57
|
+
'outlook',
|
|
58
|
+
'google_calendar',
|
|
59
|
+
'outlook_calendar',
|
|
60
|
+
'unknown',
|
|
61
|
+
]);
|
|
62
|
+
function normalizeIntegrationType(type) {
|
|
63
|
+
if (VALID_INTEGRATION_TYPES.has(type)) {
|
|
64
|
+
return type;
|
|
65
|
+
}
|
|
66
|
+
// prettier-ignore
|
|
67
|
+
console.warn(`[Attrove SDK] Unknown integration type "${type}" normalized to "unknown". SDK may need updating.`);
|
|
68
|
+
return 'unknown';
|
|
69
|
+
}
|
|
70
|
+
function normalizeSearchMeeting(meeting) {
|
|
71
|
+
return {
|
|
72
|
+
id: meeting.id,
|
|
73
|
+
title: meeting.title,
|
|
74
|
+
meeting_code: meeting.meeting_code,
|
|
75
|
+
start_time: meeting.start_time,
|
|
76
|
+
end_time: meeting.end_time,
|
|
77
|
+
summary: meeting.summary,
|
|
78
|
+
short_summary: meeting.short_summary,
|
|
79
|
+
action_items: meeting.action_items,
|
|
80
|
+
attendees: meeting.attendees,
|
|
81
|
+
meeting_link: meeting.meeting_link,
|
|
82
|
+
has_transcript: meeting.has_transcript,
|
|
83
|
+
provider: normalizeMeetingProvider(meeting.provider),
|
|
84
|
+
event_id: meeting.event_id,
|
|
85
|
+
created_at: meeting.created_at,
|
|
86
|
+
updated_at: meeting.updated_at,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function normalizeSearchEvent(event) {
|
|
90
|
+
let attendees;
|
|
91
|
+
if (Array.isArray(event.attendees)) {
|
|
92
|
+
attendees = event.attendees;
|
|
93
|
+
}
|
|
94
|
+
else if (event.attendees !== undefined && event.attendees !== null) {
|
|
95
|
+
// prettier-ignore
|
|
96
|
+
console.warn(`[Attrove SDK] Event ${event.id} has non-array attendees (${typeof event.attendees}), ignoring.`);
|
|
97
|
+
}
|
|
98
|
+
return {
|
|
99
|
+
id: event.id,
|
|
100
|
+
calendar_id: event.calendar_id,
|
|
101
|
+
title: event.title,
|
|
102
|
+
description: event.description,
|
|
103
|
+
start_time: event.start_time,
|
|
104
|
+
end_time: event.end_time,
|
|
105
|
+
location: event.location,
|
|
106
|
+
status: event.status,
|
|
107
|
+
all_day: event.all_day,
|
|
108
|
+
organizer_entity_id: event.organizer_entity_id,
|
|
109
|
+
attendee_entity_ids: event.attendee_entity_ids,
|
|
110
|
+
attendees,
|
|
111
|
+
html_link: event.html_link,
|
|
112
|
+
event_link: event.event_link,
|
|
113
|
+
created_at: event.created_at,
|
|
114
|
+
updated_at: event.updated_at,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function normalizeSearchResponse(response) {
|
|
118
|
+
const conversations = response.conversations || {};
|
|
119
|
+
if (!response.conversations) {
|
|
120
|
+
// prettier-ignore
|
|
121
|
+
console.warn('[Attrove SDK] Search response missing conversations field, defaulting to empty object.');
|
|
122
|
+
}
|
|
123
|
+
const normalizedConversations = {};
|
|
124
|
+
for (const [conversationId, conversation] of Object.entries(conversations)) {
|
|
125
|
+
const normalizedThreads = {};
|
|
126
|
+
for (const [threadId, messages] of Object.entries(conversation.threads || {})) {
|
|
127
|
+
normalizedThreads[threadId] = (messages || []).map(normalizeThreadMessage);
|
|
128
|
+
}
|
|
129
|
+
normalizedConversations[conversationId] = {
|
|
130
|
+
conversation_name: conversation.conversation_name,
|
|
131
|
+
threads: normalizedThreads,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (!response.key_messages) {
|
|
135
|
+
// prettier-ignore
|
|
136
|
+
console.warn('[Attrove SDK] Search response missing key_messages field, defaulting to empty array.');
|
|
137
|
+
}
|
|
138
|
+
const result = {
|
|
139
|
+
key_messages: (response.key_messages || []).map(normalizeKeyMessage),
|
|
140
|
+
conversations: normalizedConversations,
|
|
141
|
+
key_meetings: (response.key_meetings || []).map(normalizeSearchMeeting),
|
|
142
|
+
key_events: (response.key_events || []).map(normalizeSearchEvent),
|
|
143
|
+
};
|
|
144
|
+
if (response.warnings && response.warnings.length > 0) {
|
|
145
|
+
result.warnings = response.warnings;
|
|
146
|
+
}
|
|
147
|
+
return result;
|
|
148
|
+
}
|
|
9
149
|
/**
|
|
10
150
|
* Query resource for RAG operations.
|
|
11
151
|
*
|
|
@@ -48,7 +188,7 @@ class QueryResource {
|
|
|
48
188
|
*
|
|
49
189
|
* // With filters
|
|
50
190
|
* const response = await attrove.query('Latest updates', {
|
|
51
|
-
* integrationIds: ['
|
|
191
|
+
* integrationIds: ['int_xxx'],
|
|
52
192
|
* includeSources: true
|
|
53
193
|
* });
|
|
54
194
|
* ```
|
|
@@ -71,25 +211,28 @@ class QueryResource {
|
|
|
71
211
|
body.allow_bot_messages = options.allowBotMessages;
|
|
72
212
|
}
|
|
73
213
|
if (options.includeSources) {
|
|
74
|
-
body.expand =
|
|
214
|
+
body.expand = 'sources';
|
|
75
215
|
}
|
|
76
216
|
const response = await this.http.post(`/v1/users/${this.userId}/query`, body);
|
|
77
217
|
return {
|
|
78
218
|
answer: response.answer,
|
|
79
219
|
history: response.history,
|
|
80
220
|
used_message_ids: response.used_message_ids,
|
|
221
|
+
used_meeting_ids: response.used_meeting_ids ?? [],
|
|
222
|
+
used_event_ids: response.used_event_ids ?? [],
|
|
81
223
|
sources: response.sources,
|
|
82
224
|
};
|
|
83
225
|
}
|
|
84
226
|
/**
|
|
85
227
|
* Semantic search across the user's context.
|
|
86
228
|
*
|
|
87
|
-
* Returns raw matching messages grouped by conversation,
|
|
88
|
-
*
|
|
229
|
+
* Returns raw matching messages (grouped by conversation), plus matched meetings
|
|
230
|
+
* and calendar events, without AI summarization.
|
|
231
|
+
* Use this when you need full control over how results are displayed and processed.
|
|
89
232
|
*
|
|
90
233
|
* @param query - The search query (semantic, not keyword-based)
|
|
91
234
|
* @param options - Search options including filters, date range, etc.
|
|
92
|
-
* @returns Matching messages grouped by conversation
|
|
235
|
+
* @returns Matching messages grouped by conversation, plus matched meetings and calendar events
|
|
93
236
|
*
|
|
94
237
|
* @throws {AuthenticationError} If the API key is invalid or expired
|
|
95
238
|
* @throws {ValidationError} If the search parameters are invalid
|
|
@@ -108,10 +251,16 @@ class QueryResource {
|
|
|
108
251
|
* senderDomains: ['acme.com'],
|
|
109
252
|
* includeBodyText: true
|
|
110
253
|
* });
|
|
254
|
+
*
|
|
255
|
+
* // Expand meeting and event detail fields
|
|
256
|
+
* const richResults = await attrove.search('standup action items', {
|
|
257
|
+
* expand: ['summary', 'action_items', 'description']
|
|
258
|
+
* });
|
|
111
259
|
* ```
|
|
112
260
|
*/
|
|
113
261
|
async search(query, options = {}) {
|
|
114
262
|
const body = { query };
|
|
263
|
+
const expandFields = new Set(options.expand || []);
|
|
115
264
|
if (options.integrationIds?.length) {
|
|
116
265
|
body.integration_ids = options.integrationIds;
|
|
117
266
|
}
|
|
@@ -134,9 +283,13 @@ class QueryResource {
|
|
|
134
283
|
body.entity_ids = options.entityIds;
|
|
135
284
|
}
|
|
136
285
|
if (options.includeBodyText) {
|
|
137
|
-
|
|
286
|
+
expandFields.add('body_text');
|
|
287
|
+
}
|
|
288
|
+
if (expandFields.size > 0) {
|
|
289
|
+
body.expand = Array.from(expandFields).join(',');
|
|
138
290
|
}
|
|
139
|
-
|
|
291
|
+
const response = await this.http.post(`/v1/users/${this.userId}/search`, body);
|
|
292
|
+
return normalizeSearchResponse(response);
|
|
140
293
|
}
|
|
141
294
|
}
|
|
142
295
|
exports.QueryResource = QueryResource;
|
package/cjs/types/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* and do not depend on internal monorepo packages.
|
|
7
7
|
*/
|
|
8
8
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
-
exports.isValidStreamFrame = exports.ErrorCodes = exports.isValidISODate = exports.isValidApiKey = exports.createUUID = exports.createISODate = exports.createApiKey = exports.createConversationId = exports.createMessageId = exports.createIntegrationId = exports.createUserId = exports.isValidUUID = exports.asBrandedString = void 0;
|
|
9
|
+
exports.isValidStreamFrame = exports.ErrorCodes = exports.isValidISODate = exports.isApiKey = exports.isValidApiKey = exports.createUUID = exports.createISODate = exports.createApiKey = exports.createConversationId = exports.createMessageId = exports.createIntegrationId = exports.createUserId = exports.isValidUUID = exports.asBrandedString = void 0;
|
|
10
10
|
/**
|
|
11
11
|
* Helper to cast a string to a branded type.
|
|
12
12
|
*
|
|
@@ -79,11 +79,11 @@ exports.isValidUUID = isValidUUID;
|
|
|
79
79
|
* ```
|
|
80
80
|
*/
|
|
81
81
|
function createUserId(value) {
|
|
82
|
-
if (!value || typeof value !==
|
|
83
|
-
return { success: false, error:
|
|
82
|
+
if (!value || typeof value !== 'string') {
|
|
83
|
+
return { success: false, error: 'UserId must be a non-empty string' };
|
|
84
84
|
}
|
|
85
85
|
if (!UUID_REGEX.test(value)) {
|
|
86
|
-
return { success: false, error:
|
|
86
|
+
return { success: false, error: 'UserId must be a valid UUID format' };
|
|
87
87
|
}
|
|
88
88
|
return { success: true, value: value };
|
|
89
89
|
}
|
|
@@ -92,16 +92,16 @@ exports.createUserId = createUserId;
|
|
|
92
92
|
* Validate and create an IntegrationId from a string.
|
|
93
93
|
*/
|
|
94
94
|
function createIntegrationId(value) {
|
|
95
|
-
if (!value || typeof value !==
|
|
95
|
+
if (!value || typeof value !== 'string') {
|
|
96
96
|
return {
|
|
97
97
|
success: false,
|
|
98
|
-
error:
|
|
98
|
+
error: 'IntegrationId must be a non-empty string',
|
|
99
99
|
};
|
|
100
100
|
}
|
|
101
101
|
if (!UUID_REGEX.test(value)) {
|
|
102
102
|
return {
|
|
103
103
|
success: false,
|
|
104
|
-
error:
|
|
104
|
+
error: 'IntegrationId must be a valid UUID format',
|
|
105
105
|
};
|
|
106
106
|
}
|
|
107
107
|
return { success: true, value: value };
|
|
@@ -111,11 +111,11 @@ exports.createIntegrationId = createIntegrationId;
|
|
|
111
111
|
* Validate and create a MessageId from a string.
|
|
112
112
|
*/
|
|
113
113
|
function createMessageId(value) {
|
|
114
|
-
if (!value || typeof value !==
|
|
115
|
-
return { success: false, error:
|
|
114
|
+
if (!value || typeof value !== 'string') {
|
|
115
|
+
return { success: false, error: 'MessageId must be a non-empty string' };
|
|
116
116
|
}
|
|
117
117
|
if (!UUID_REGEX.test(value)) {
|
|
118
|
-
return { success: false, error:
|
|
118
|
+
return { success: false, error: 'MessageId must be a valid UUID format' };
|
|
119
119
|
}
|
|
120
120
|
return { success: true, value: value };
|
|
121
121
|
}
|
|
@@ -124,16 +124,16 @@ exports.createMessageId = createMessageId;
|
|
|
124
124
|
* Validate and create a ConversationId from a string.
|
|
125
125
|
*/
|
|
126
126
|
function createConversationId(value) {
|
|
127
|
-
if (!value || typeof value !==
|
|
127
|
+
if (!value || typeof value !== 'string') {
|
|
128
128
|
return {
|
|
129
129
|
success: false,
|
|
130
|
-
error:
|
|
130
|
+
error: 'ConversationId must be a non-empty string',
|
|
131
131
|
};
|
|
132
132
|
}
|
|
133
133
|
if (!UUID_REGEX.test(value)) {
|
|
134
134
|
return {
|
|
135
135
|
success: false,
|
|
136
|
-
error:
|
|
136
|
+
error: 'ConversationId must be a valid UUID format',
|
|
137
137
|
};
|
|
138
138
|
}
|
|
139
139
|
return { success: true, value: value };
|
|
@@ -151,8 +151,8 @@ exports.createConversationId = createConversationId;
|
|
|
151
151
|
* ```
|
|
152
152
|
*/
|
|
153
153
|
function createApiKey(value) {
|
|
154
|
-
if (!value || typeof value !==
|
|
155
|
-
return { success: false, error:
|
|
154
|
+
if (!value || typeof value !== 'string') {
|
|
155
|
+
return { success: false, error: 'ApiKey must be a non-empty string' };
|
|
156
156
|
}
|
|
157
157
|
if (!API_KEY_REGEX.test(value)) {
|
|
158
158
|
return {
|
|
@@ -175,22 +175,22 @@ exports.createApiKey = createApiKey;
|
|
|
175
175
|
* ```
|
|
176
176
|
*/
|
|
177
177
|
function createISODate(value) {
|
|
178
|
-
if (!value || typeof value !==
|
|
178
|
+
if (!value || typeof value !== 'string') {
|
|
179
179
|
return {
|
|
180
180
|
success: false,
|
|
181
|
-
error:
|
|
181
|
+
error: 'ISODateString must be a non-empty string',
|
|
182
182
|
};
|
|
183
183
|
}
|
|
184
184
|
if (!ISO_DATE_REGEX.test(value)) {
|
|
185
185
|
return {
|
|
186
186
|
success: false,
|
|
187
|
-
error:
|
|
187
|
+
error: 'ISODateString must be a valid ISO 8601 date format',
|
|
188
188
|
};
|
|
189
189
|
}
|
|
190
190
|
// Additional validation: ensure it parses to a valid date
|
|
191
191
|
const parsed = Date.parse(value);
|
|
192
192
|
if (Number.isNaN(parsed)) {
|
|
193
|
-
return { success: false, error:
|
|
193
|
+
return { success: false, error: 'ISODateString must be a valid date' };
|
|
194
194
|
}
|
|
195
195
|
return { success: true, value: value };
|
|
196
196
|
}
|
|
@@ -199,22 +199,54 @@ exports.createISODate = createISODate;
|
|
|
199
199
|
* Validate and create a UUID from a string.
|
|
200
200
|
*/
|
|
201
201
|
function createUUID(value) {
|
|
202
|
-
if (!value || typeof value !==
|
|
203
|
-
return { success: false, error:
|
|
202
|
+
if (!value || typeof value !== 'string') {
|
|
203
|
+
return { success: false, error: 'UUID must be a non-empty string' };
|
|
204
204
|
}
|
|
205
205
|
if (!UUID_REGEX.test(value)) {
|
|
206
|
-
return { success: false, error:
|
|
206
|
+
return { success: false, error: 'UUID must be a valid UUID format' };
|
|
207
207
|
}
|
|
208
208
|
return { success: true, value: value };
|
|
209
209
|
}
|
|
210
210
|
exports.createUUID = createUUID;
|
|
211
211
|
/**
|
|
212
212
|
* Check if a string is a valid API key format.
|
|
213
|
+
* Returns a boolean without type narrowing.
|
|
214
|
+
*
|
|
215
|
+
* Handles non-string inputs defensively for runtime safety.
|
|
216
|
+
*
|
|
217
|
+
* @see {@link isApiKey} for a type guard that narrows to ApiKeyFormat
|
|
213
218
|
*/
|
|
214
219
|
function isValidApiKey(value) {
|
|
215
|
-
return API_KEY_REGEX.test(value);
|
|
220
|
+
return typeof value === 'string' && API_KEY_REGEX.test(value);
|
|
216
221
|
}
|
|
217
222
|
exports.isValidApiKey = isValidApiKey;
|
|
223
|
+
/**
|
|
224
|
+
* Type guard that narrows a string to ApiKeyFormat.
|
|
225
|
+
* Use this when you want compile-time type safety after runtime validation.
|
|
226
|
+
*
|
|
227
|
+
* **Note:** This narrows to `ApiKeyFormat` (template literal type), not the
|
|
228
|
+
* branded `ApiKeyToken`. Use {@link createApiKey} if you need a branded token.
|
|
229
|
+
*
|
|
230
|
+
* @param value - String to check
|
|
231
|
+
* @returns True if the value is a valid API key format, narrowing the type
|
|
232
|
+
*
|
|
233
|
+
* @example
|
|
234
|
+
* ```ts
|
|
235
|
+
* const apiKey = process.env.ATTROVE_SECRET_KEY;
|
|
236
|
+
* if (apiKey && isApiKey(apiKey)) {
|
|
237
|
+
* // apiKey is now typed as ApiKeyFormat
|
|
238
|
+
* // TypeScript knows it starts with 'sk_'
|
|
239
|
+
* doSomethingWithKey(apiKey);
|
|
240
|
+
* }
|
|
241
|
+
* ```
|
|
242
|
+
*
|
|
243
|
+
* @see {@link createApiKey} for validation that returns a branded ApiKeyToken
|
|
244
|
+
* @see {@link isValidApiKey} for a simple boolean check without type narrowing
|
|
245
|
+
*/
|
|
246
|
+
function isApiKey(value) {
|
|
247
|
+
return typeof value === 'string' && API_KEY_REGEX.test(value);
|
|
248
|
+
}
|
|
249
|
+
exports.isApiKey = isApiKey;
|
|
218
250
|
/**
|
|
219
251
|
* Check if a string is a valid ISO 8601 date format.
|
|
220
252
|
*/
|
|
@@ -230,44 +262,44 @@ exports.isValidISODate = isValidISODate;
|
|
|
230
262
|
*/
|
|
231
263
|
exports.ErrorCodes = {
|
|
232
264
|
// Authentication errors
|
|
233
|
-
AUTH_MISSING_TOKEN:
|
|
234
|
-
AUTH_INVALID_TOKEN:
|
|
235
|
-
AUTH_EXPIRED_TOKEN:
|
|
236
|
-
AUTH_USER_MISMATCH:
|
|
237
|
-
AUTH_INSUFFICIENT_PERMISSIONS:
|
|
265
|
+
AUTH_MISSING_TOKEN: 'AUTH_MISSING_TOKEN',
|
|
266
|
+
AUTH_INVALID_TOKEN: 'AUTH_INVALID_TOKEN',
|
|
267
|
+
AUTH_EXPIRED_TOKEN: 'AUTH_EXPIRED_TOKEN',
|
|
268
|
+
AUTH_USER_MISMATCH: 'AUTH_USER_MISMATCH',
|
|
269
|
+
AUTH_INSUFFICIENT_PERMISSIONS: 'AUTH_INSUFFICIENT_PERMISSIONS',
|
|
238
270
|
// Resource errors
|
|
239
|
-
RESOURCE_NOT_FOUND:
|
|
240
|
-
RESOURCE_ACCESS_DENIED:
|
|
241
|
-
RESOURCE_ALREADY_EXISTS:
|
|
242
|
-
RESOURCE_DELETED:
|
|
271
|
+
RESOURCE_NOT_FOUND: 'RESOURCE_NOT_FOUND',
|
|
272
|
+
RESOURCE_ACCESS_DENIED: 'RESOURCE_ACCESS_DENIED',
|
|
273
|
+
RESOURCE_ALREADY_EXISTS: 'RESOURCE_ALREADY_EXISTS',
|
|
274
|
+
RESOURCE_DELETED: 'RESOURCE_DELETED',
|
|
243
275
|
// Validation errors
|
|
244
|
-
VALIDATION_INVALID_ID:
|
|
245
|
-
VALIDATION_REQUIRED_FIELD:
|
|
246
|
-
VALIDATION_INVALID_FORMAT:
|
|
247
|
-
VALIDATION_OUT_OF_RANGE:
|
|
276
|
+
VALIDATION_INVALID_ID: 'VALIDATION_INVALID_ID',
|
|
277
|
+
VALIDATION_REQUIRED_FIELD: 'VALIDATION_REQUIRED_FIELD',
|
|
278
|
+
VALIDATION_INVALID_FORMAT: 'VALIDATION_INVALID_FORMAT',
|
|
279
|
+
VALIDATION_OUT_OF_RANGE: 'VALIDATION_OUT_OF_RANGE',
|
|
248
280
|
// Integration errors
|
|
249
|
-
INTEGRATION_OAUTH_FAILED:
|
|
250
|
-
INTEGRATION_EMAIL_EXISTS:
|
|
251
|
-
INTEGRATION_TOKEN_EXPIRED:
|
|
252
|
-
INTEGRATION_SYNC_FAILED:
|
|
253
|
-
INTEGRATION_NOT_CONNECTED:
|
|
281
|
+
INTEGRATION_OAUTH_FAILED: 'INTEGRATION_OAUTH_FAILED',
|
|
282
|
+
INTEGRATION_EMAIL_EXISTS: 'INTEGRATION_EMAIL_EXISTS',
|
|
283
|
+
INTEGRATION_TOKEN_EXPIRED: 'INTEGRATION_TOKEN_EXPIRED',
|
|
284
|
+
INTEGRATION_SYNC_FAILED: 'INTEGRATION_SYNC_FAILED',
|
|
285
|
+
INTEGRATION_NOT_CONNECTED: 'INTEGRATION_NOT_CONNECTED',
|
|
254
286
|
// Rate limiting
|
|
255
|
-
RATE_LIMIT_EXCEEDED:
|
|
287
|
+
RATE_LIMIT_EXCEEDED: 'RATE_LIMIT_EXCEEDED',
|
|
256
288
|
// Server errors
|
|
257
|
-
INTERNAL_ERROR:
|
|
258
|
-
SERVICE_UNAVAILABLE:
|
|
259
|
-
REQUEST_TIMEOUT:
|
|
289
|
+
INTERNAL_ERROR: 'INTERNAL_ERROR',
|
|
290
|
+
SERVICE_UNAVAILABLE: 'SERVICE_UNAVAILABLE',
|
|
291
|
+
REQUEST_TIMEOUT: 'REQUEST_TIMEOUT',
|
|
260
292
|
};
|
|
261
293
|
/**
|
|
262
294
|
* Valid stream frame types.
|
|
263
295
|
*/
|
|
264
296
|
const VALID_FRAME_TYPES = new Set([
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
297
|
+
'chunk',
|
|
298
|
+
'end',
|
|
299
|
+
'error',
|
|
300
|
+
'state',
|
|
301
|
+
'message_ids',
|
|
302
|
+
'stream_start',
|
|
271
303
|
]);
|
|
272
304
|
/**
|
|
273
305
|
* Runtime validator for StreamFrame objects.
|
|
@@ -286,35 +318,46 @@ const VALID_FRAME_TYPES = new Set([
|
|
|
286
318
|
* ```
|
|
287
319
|
*/
|
|
288
320
|
function isValidStreamFrame(data) {
|
|
289
|
-
if (!data || typeof data !==
|
|
321
|
+
if (!data || typeof data !== 'object') {
|
|
290
322
|
return false;
|
|
291
323
|
}
|
|
292
324
|
const frame = data;
|
|
293
325
|
// All frames must have type and message_id
|
|
294
|
-
if (typeof frame.type !==
|
|
326
|
+
if (typeof frame.type !== 'string' || !VALID_FRAME_TYPES.has(frame.type)) {
|
|
295
327
|
return false;
|
|
296
328
|
}
|
|
297
|
-
if (typeof frame.message_id !==
|
|
329
|
+
if (typeof frame.message_id !== 'string') {
|
|
298
330
|
return false;
|
|
299
331
|
}
|
|
300
332
|
// Type-specific validation
|
|
301
333
|
switch (frame.type) {
|
|
302
|
-
case
|
|
303
|
-
return typeof frame.content ===
|
|
304
|
-
case
|
|
305
|
-
return (typeof frame.reason ===
|
|
306
|
-
[
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
334
|
+
case 'chunk':
|
|
335
|
+
return typeof frame.content === 'string';
|
|
336
|
+
case 'end':
|
|
337
|
+
return (typeof frame.reason === 'string' &&
|
|
338
|
+
['completed', 'cancelled', 'error'].includes(frame.reason) &&
|
|
339
|
+
isOptionalStringArray(frame.used_message_ids) &&
|
|
340
|
+
isOptionalStringArray(frame.used_meeting_ids) &&
|
|
341
|
+
isOptionalStringArray(frame.used_event_ids));
|
|
342
|
+
case 'error':
|
|
343
|
+
return typeof frame.error === 'string';
|
|
344
|
+
case 'state':
|
|
345
|
+
return typeof frame.state === 'string';
|
|
346
|
+
case 'message_ids':
|
|
312
347
|
return (Array.isArray(frame.used_message_ids) &&
|
|
313
|
-
frame.used_message_ids.every((id) => typeof id ===
|
|
314
|
-
|
|
348
|
+
frame.used_message_ids.every((id) => typeof id === 'string') &&
|
|
349
|
+
isOptionalStringArray(frame.used_meeting_ids) &&
|
|
350
|
+
isOptionalStringArray(frame.used_event_ids));
|
|
351
|
+
case 'stream_start':
|
|
315
352
|
return true;
|
|
316
353
|
default:
|
|
317
354
|
return false;
|
|
318
355
|
}
|
|
319
356
|
}
|
|
320
357
|
exports.isValidStreamFrame = isValidStreamFrame;
|
|
358
|
+
function isOptionalStringArray(value) {
|
|
359
|
+
if (value === undefined)
|
|
360
|
+
return true;
|
|
361
|
+
return (Array.isArray(value) &&
|
|
362
|
+
value.every((item) => typeof item === 'string'));
|
|
363
|
+
}
|
package/cjs/utils/streaming.js
CHANGED
|
@@ -108,6 +108,8 @@ class StreamingClient {
|
|
|
108
108
|
this.onWarning = onWarning;
|
|
109
109
|
let answer = "";
|
|
110
110
|
let usedMessageIds = [];
|
|
111
|
+
let usedMeetingIds = [];
|
|
112
|
+
let usedEventIds = [];
|
|
111
113
|
let cancelled = false;
|
|
112
114
|
let completed = false;
|
|
113
115
|
// Connect to WebSocket
|
|
@@ -225,6 +227,12 @@ class StreamingClient {
|
|
|
225
227
|
break;
|
|
226
228
|
case "message_ids":
|
|
227
229
|
usedMessageIds = frame.used_message_ids;
|
|
230
|
+
if (frame.used_meeting_ids !== undefined) {
|
|
231
|
+
usedMeetingIds = frame.used_meeting_ids;
|
|
232
|
+
}
|
|
233
|
+
if (frame.used_event_ids !== undefined) {
|
|
234
|
+
usedEventIds = frame.used_event_ids;
|
|
235
|
+
}
|
|
228
236
|
break;
|
|
229
237
|
case "error": {
|
|
230
238
|
const error = new index_js_2.AttroveError(frame.error, index_js_3.ErrorCodes.INTERNAL_ERROR);
|
|
@@ -238,6 +246,12 @@ class StreamingClient {
|
|
|
238
246
|
if (frame.used_message_ids) {
|
|
239
247
|
usedMessageIds = frame.used_message_ids;
|
|
240
248
|
}
|
|
249
|
+
if (frame.used_meeting_ids !== undefined) {
|
|
250
|
+
usedMeetingIds = frame.used_meeting_ids;
|
|
251
|
+
}
|
|
252
|
+
if (frame.used_event_ids !== undefined) {
|
|
253
|
+
usedEventIds = frame.used_event_ids;
|
|
254
|
+
}
|
|
241
255
|
onEnd?.(frame.reason);
|
|
242
256
|
// Build updated history
|
|
243
257
|
const updatedHistory = [
|
|
@@ -249,6 +263,8 @@ class StreamingClient {
|
|
|
249
263
|
answer,
|
|
250
264
|
history: updatedHistory,
|
|
251
265
|
usedMessageIds,
|
|
266
|
+
usedMeetingIds,
|
|
267
|
+
usedEventIds,
|
|
252
268
|
cancelled,
|
|
253
269
|
});
|
|
254
270
|
break;
|
package/esm/constants.d.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* Automatically synchronized with package.json during the release process.
|
|
11
11
|
* For programmatic access, use `getVersion()` from './version'.
|
|
12
12
|
*/
|
|
13
|
-
export declare const SDK_VERSION = "0.1.
|
|
13
|
+
export declare const SDK_VERSION = "0.1.13";
|
|
14
14
|
/**
|
|
15
15
|
* Default API base URL for Attrove services.
|
|
16
16
|
*/
|
package/esm/constants.js
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* Automatically synchronized with package.json during the release process.
|
|
11
11
|
* For programmatic access, use `getVersion()` from './version'.
|
|
12
12
|
*/
|
|
13
|
-
export const SDK_VERSION = "0.1.
|
|
13
|
+
export const SDK_VERSION = "0.1.13"; // auto-synced from package.json during release
|
|
14
14
|
/**
|
|
15
15
|
* Default API base URL for Attrove services.
|
|
16
16
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../../../packages/sdk/src/resources/messages.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EACL,OAAO,EAEP,UAAU,EACV,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAE3B;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;CACxB;AAED;;;;;GAKG;AACH,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM;IAGjC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACG,IAAI,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../../../../../packages/sdk/src/resources/messages.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EACL,OAAO,EAEP,UAAU,EACV,mBAAmB,EACpB,MAAM,mBAAmB,CAAC;AAE3B;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,UAAU,EAAE,UAAU,CAAC;CACxB;AAED;;;;;GAKG;AACH,qBAAa,gBAAgB;IAEzB,OAAO,CAAC,QAAQ,CAAC,IAAI;IACrB,OAAO,CAAC,QAAQ,CAAC,MAAM;gBADN,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM;IAGjC;;;;;;;;;;;;;;;;;;;;;;;;OAwBG;IACG,IAAI,CAAC,OAAO,GAAE,mBAAwB,GAAG,OAAO,CAAC,YAAY,CAAC;IA2CpE;;;;;;;;;;;;;;;OAeG;IACG,GAAG,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;CAGxC"}
|
|
@@ -62,6 +62,9 @@ export class MessagesResource {
|
|
|
62
62
|
if (options.offset !== undefined) {
|
|
63
63
|
params.offset = String(options.offset);
|
|
64
64
|
}
|
|
65
|
+
if (options.excludeBots !== undefined) {
|
|
66
|
+
params.exclude_bots = String(options.excludeBots);
|
|
67
|
+
}
|
|
65
68
|
if (options.expand?.length) {
|
|
66
69
|
params.expand = options.expand.join(",");
|
|
67
70
|
}
|