@attrove/sdk 0.1.19 → 0.2.1

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.
Files changed (59) hide show
  1. package/README.md +8 -0
  2. package/cjs/client.js +4 -0
  3. package/cjs/constants.js +1 -1
  4. package/cjs/resources/index.js +5 -1
  5. package/cjs/resources/notes.js +106 -0
  6. package/cjs/resources/push.js +315 -0
  7. package/cjs/resources/query.js +39 -2
  8. package/cjs/resources/webhooks.js +1 -0
  9. package/cjs/types/index.js +23 -3
  10. package/cjs/utils/index.js +3 -1
  11. package/cjs/utils/streaming.js +8 -0
  12. package/cjs/utils/validate-ref-pair.js +45 -0
  13. package/esm/client.d.ts +12 -0
  14. package/esm/client.d.ts.map +1 -1
  15. package/esm/client.js +4 -0
  16. package/esm/client.js.map +1 -1
  17. package/esm/constants.d.ts +1 -1
  18. package/esm/constants.d.ts.map +1 -1
  19. package/esm/constants.js +1 -1
  20. package/esm/constants.js.map +1 -1
  21. package/esm/index.d.ts +1 -0
  22. package/esm/index.d.ts.map +1 -1
  23. package/esm/index.js.map +1 -1
  24. package/esm/resources/index.d.ts +3 -0
  25. package/esm/resources/index.d.ts.map +1 -1
  26. package/esm/resources/index.js +2 -0
  27. package/esm/resources/index.js.map +1 -1
  28. package/esm/resources/notes.d.ts +80 -0
  29. package/esm/resources/notes.d.ts.map +1 -0
  30. package/esm/resources/notes.js +103 -0
  31. package/esm/resources/notes.js.map +1 -0
  32. package/esm/resources/push.d.ts +140 -0
  33. package/esm/resources/push.d.ts.map +1 -0
  34. package/esm/resources/push.js +312 -0
  35. package/esm/resources/push.js.map +1 -0
  36. package/esm/resources/query.d.ts.map +1 -1
  37. package/esm/resources/query.js +39 -2
  38. package/esm/resources/query.js.map +1 -1
  39. package/esm/resources/webhooks.d.ts +1 -1
  40. package/esm/resources/webhooks.d.ts.map +1 -1
  41. package/esm/resources/webhooks.js +1 -0
  42. package/esm/resources/webhooks.js.map +1 -1
  43. package/esm/types/index.d.ts +225 -7
  44. package/esm/types/index.d.ts.map +1 -1
  45. package/esm/types/index.js +22 -2
  46. package/esm/types/index.js.map +1 -1
  47. package/esm/utils/index.d.ts +1 -0
  48. package/esm/utils/index.d.ts.map +1 -1
  49. package/esm/utils/index.js +1 -0
  50. package/esm/utils/index.js.map +1 -1
  51. package/esm/utils/streaming.d.ts +4 -0
  52. package/esm/utils/streaming.d.ts.map +1 -1
  53. package/esm/utils/streaming.js +8 -0
  54. package/esm/utils/streaming.js.map +1 -1
  55. package/esm/utils/validate-ref-pair.d.ts +23 -0
  56. package/esm/utils/validate-ref-pair.d.ts.map +1 -0
  57. package/esm/utils/validate-ref-pair.js +42 -0
  58. package/esm/utils/validate-ref-pair.js.map +1 -0
  59. package/package.json +2 -2
package/README.md CHANGED
@@ -56,6 +56,14 @@ const filtered = await attrove.query('Latest updates', {
56
56
  integrationIds: ['int_xxx'], // Only search specific integration
57
57
  includeSources: true // Include source snippets
58
58
  });
59
+
60
+ // Custom instructions + reference context
61
+ const custom = await attrove.query('Compare Alice and Bob on budget adherence.', {
62
+ // instructions: control output format and behavior (overrides default style)
63
+ instructions: 'Return a markdown table with columns: Person, On-Track, Key Evidence.',
64
+ // context: ground-truth data the AI treats as authoritative (influences query rewriting, not vector search)
65
+ context: 'FY26 budget: Engineering $2M, Marketing $800K. Alice owns Engineering, Bob owns Marketing.',
66
+ });
59
67
  ```
60
68
 
61
69
  ### `search(query, options?)`
package/cjs/client.js CHANGED
@@ -18,6 +18,8 @@ const calendars_js_1 = require("./resources/calendars.js");
18
18
  const events_js_1 = require("./resources/events.js");
19
19
  const meetings_js_1 = require("./resources/meetings.js");
20
20
  const threads_js_1 = require("./resources/threads.js");
21
+ const notes_js_1 = require("./resources/notes.js");
22
+ const push_js_1 = require("./resources/push.js");
21
23
  const query_js_1 = require("./resources/query.js");
22
24
  const index_js_1 = require("./errors/index.js");
23
25
  const index_js_2 = require("./types/index.js");
@@ -124,6 +126,8 @@ class Attrove {
124
126
  this.events = new events_js_1.EventsResource(this.http, this.config.userId);
125
127
  this.meetings = new meetings_js_1.MeetingsResource(this.http, this.config.userId);
126
128
  this.threads = new threads_js_1.ThreadsResource(this.http, this.config.userId);
129
+ this.notes = new notes_js_1.NotesResource(this.http, this.config.userId);
130
+ this.push = new push_js_1.PushResource(this.http, this.config.userId);
127
131
  this.queryResource = new query_js_1.QueryResource(this.http, this.config.userId);
128
132
  }
129
133
  /**
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.19"; // auto-synced from package.json during release
16
+ exports.SDK_VERSION = "0.2.1"; // auto-synced from package.json during release
17
17
  /**
18
18
  * Default API base URL for Attrove services.
19
19
  */
@@ -3,7 +3,7 @@
3
3
  * Resource exports
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.AdminWebhooksResource = exports.AdminSettingsResource = exports.QueryResource = exports.ThreadsResource = exports.MeetingsResource = exports.EventsResource = exports.CalendarsResource = exports.EntitiesResource = exports.IntegrationsResource = exports.ConversationsResource = exports.MessagesResource = exports.UsersResource = void 0;
6
+ exports.AdminWebhooksResource = exports.PushResource = exports.NotesResource = exports.AdminSettingsResource = exports.QueryResource = exports.ThreadsResource = exports.MeetingsResource = exports.EventsResource = exports.CalendarsResource = exports.EntitiesResource = exports.IntegrationsResource = exports.ConversationsResource = exports.MessagesResource = exports.UsersResource = void 0;
7
7
  var users_js_1 = require("./users.js");
8
8
  Object.defineProperty(exports, "UsersResource", { enumerable: true, get: function () { return users_js_1.UsersResource; } });
9
9
  var messages_js_1 = require("./messages.js");
@@ -26,5 +26,9 @@ var query_js_1 = require("./query.js");
26
26
  Object.defineProperty(exports, "QueryResource", { enumerable: true, get: function () { return query_js_1.QueryResource; } });
27
27
  var settings_js_1 = require("./settings.js");
28
28
  Object.defineProperty(exports, "AdminSettingsResource", { enumerable: true, get: function () { return settings_js_1.AdminSettingsResource; } });
29
+ var notes_js_1 = require("./notes.js");
30
+ Object.defineProperty(exports, "NotesResource", { enumerable: true, get: function () { return notes_js_1.NotesResource; } });
31
+ var push_js_1 = require("./push.js");
32
+ Object.defineProperty(exports, "PushResource", { enumerable: true, get: function () { return push_js_1.PushResource; } });
29
33
  var webhooks_js_1 = require("./webhooks.js");
30
34
  Object.defineProperty(exports, "AdminWebhooksResource", { enumerable: true, get: function () { return webhooks_js_1.AdminWebhooksResource; } });
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ /**
3
+ * Notes Resource
4
+ *
5
+ * Provides methods for listing and retrieving notes.
6
+ * Notes are analyst observations, partner-pushed context, or session summaries
7
+ * that are RAG-indexed and become queryable via query() and search().
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.NotesResource = void 0;
11
+ const validate_ref_pair_js_1 = require("../utils/validate-ref-pair.js");
12
+ const index_js_1 = require("../errors/index.js");
13
+ const index_js_2 = require("../types/index.js");
14
+ /**
15
+ * Notes resource for listing and retrieving notes.
16
+ *
17
+ * Notes are RAG-indexed context items that can be created via the Push API
18
+ * (`attrove.push.note()`) or by partner systems. They support cross-referencing
19
+ * to other primitives (messages, meetings, events, entities) via `ref_type` and `ref_id`.
20
+ */
21
+ class NotesResource {
22
+ constructor(http, userId) {
23
+ this.http = http;
24
+ this.userId = userId;
25
+ }
26
+ /**
27
+ * List notes with optional filtering.
28
+ *
29
+ * Supports filtering by specific IDs (useful after receiving a `notes.new` webhook),
30
+ * by reference type/ID (find all notes linked to a specific message or meeting),
31
+ * and standard pagination.
32
+ *
33
+ * @param options - Filtering and pagination options
34
+ * @returns Paginated list of notes
35
+ *
36
+ * @throws {AuthenticationError} If the API key is invalid or expired
37
+ * @throws {ValidationError} If the filter parameters are invalid
38
+ * @throws {NetworkError} If unable to reach the API
39
+ * @throws {ServerError} If the server encounters an error
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * // List recent notes
44
+ * const { data, pagination } = await attrove.notes.list();
45
+ *
46
+ * // Fetch specific notes from a webhook payload
47
+ * const { data } = await attrove.notes.list({
48
+ * ids: ['note_1Z', 'note_2B4'],
49
+ * });
50
+ *
51
+ * // Find notes linked to a specific message
52
+ * const { data } = await attrove.notes.list({
53
+ * refType: 'message',
54
+ * refId: 'msg_xxx',
55
+ * });
56
+ * ```
57
+ */
58
+ async list(options = {}) {
59
+ (0, validate_ref_pair_js_1.validateRefPair)(options.refType, options.refId);
60
+ const params = {};
61
+ if (options.ids?.length) {
62
+ params.ids = options.ids.join(',');
63
+ }
64
+ if (options.refType) {
65
+ params.ref_type = options.refType;
66
+ }
67
+ if (options.refId) {
68
+ params.ref_id = options.refId;
69
+ }
70
+ if (options.limit !== undefined) {
71
+ params.limit = String(options.limit);
72
+ }
73
+ if (options.offset !== undefined) {
74
+ params.offset = String(options.offset);
75
+ }
76
+ const response = await this.http.request(`/v1/users/${this.userId}/notes`, { method: 'GET' }, params);
77
+ return {
78
+ data: response.data,
79
+ pagination: response.pagination,
80
+ };
81
+ }
82
+ /**
83
+ * Get a single note by ID.
84
+ *
85
+ * @param id - Note ID (opaque note_xxx format)
86
+ * @returns The requested note
87
+ *
88
+ * @throws {AuthenticationError} If the API key is invalid or expired
89
+ * @throws {NotFoundError} If the note does not exist
90
+ * @throws {ValidationError} If the ID format is invalid
91
+ * @throws {NetworkError} If unable to reach the API
92
+ *
93
+ * @example
94
+ * ```ts
95
+ * const note = await attrove.notes.get('note_1Z');
96
+ * console.log(note.title, note.body);
97
+ * ```
98
+ */
99
+ async get(id) {
100
+ if (!id || typeof id !== 'string') {
101
+ throw new index_js_1.ValidationError('id is required and must be a non-empty string', index_js_2.ErrorCodes.VALIDATION_REQUIRED_FIELD, { field: 'id', received: typeof id });
102
+ }
103
+ return this.http.get(`/v1/users/${this.userId}/notes/${id}`);
104
+ }
105
+ }
106
+ exports.NotesResource = NotesResource;
@@ -0,0 +1,315 @@
1
+ "use strict";
2
+ /**
3
+ * Push Resource
4
+ *
5
+ * Provides methods for pushing data directly into Attrove without
6
+ * requiring user OAuth connections. Supports messages, meetings,
7
+ * events, and notes. All pushed items are asynchronously RAG-indexed
8
+ * and become queryable via query() and search().
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.PushResource = void 0;
12
+ const validate_ref_pair_js_1 = require("../utils/validate-ref-pair.js");
13
+ const index_js_1 = require("../errors/index.js");
14
+ const index_js_2 = require("../types/index.js");
15
+ /**
16
+ * Push resource for ingesting data directly into a user's context.
17
+ *
18
+ * Each method auto-provisions a virtual integration (e.g., `manual_email`,
19
+ * `manual_notes`) on first push for the user. Items are queued for
20
+ * asynchronous RAG processing and fire webhook events when indexed.
21
+ *
22
+ * Idempotent when `externalId` is provided: re-pushing the same external ID
23
+ * updates the existing item and re-indexes it.
24
+ */
25
+ class PushResource {
26
+ constructor(http, userId) {
27
+ this.http = http;
28
+ this.userId = userId;
29
+ }
30
+ /**
31
+ * Push a message (email, chat, alert, or custom) for the user.
32
+ *
33
+ * The `source` field determines the virtual integration type:
34
+ * - `email` → `manual_email` (subject-based threading)
35
+ * - `chat`, `alert`, `custom` → `manual_chat` (channel-based grouping)
36
+ *
37
+ * @param input - Message data
38
+ * @returns Push response with opaque ID (msg_xxx) and processing status
39
+ *
40
+ * @throws {ValidationError} If required fields are missing or invalid
41
+ * @throws {AuthenticationError} If the API key is invalid or expired
42
+ * @throws {ServerError} If the server encounters an error
43
+ *
44
+ * @example
45
+ * ```ts
46
+ * const result = await attrove.push.message({
47
+ * source: 'email',
48
+ * bodyText: 'Hey team, the Q4 report is ready for review.',
49
+ * subject: 'Q4 Report Ready',
50
+ * senderEmail: 'alice@acme.com',
51
+ * senderName: 'Alice Chen',
52
+ * externalId: 'email-12345',
53
+ * });
54
+ * console.log(result.id); // msg_xxx
55
+ * console.log(result.status); // 'queued'
56
+ * ```
57
+ */
58
+ async message(input) {
59
+ const validSources = index_js_2.PUSH_MESSAGE_SOURCES;
60
+ if (!input.source || !validSources.includes(input.source)) {
61
+ throw new index_js_1.ValidationError(`source must be one of: ${validSources.join(', ')}`, index_js_2.ErrorCodes.VALIDATION_INVALID_FORMAT, { field: 'source', received: input.source });
62
+ }
63
+ if (!input.bodyText ||
64
+ typeof input.bodyText !== 'string' ||
65
+ input.bodyText.trim() === '') {
66
+ throw new index_js_1.ValidationError('bodyText is required and must be a non-empty string', index_js_2.ErrorCodes.VALIDATION_REQUIRED_FIELD, { field: 'bodyText' });
67
+ }
68
+ const body = {
69
+ source: input.source,
70
+ body_text: input.bodyText,
71
+ };
72
+ if (input.subject != null)
73
+ body.subject = input.subject;
74
+ if (input.senderName != null)
75
+ body.sender_name = input.senderName;
76
+ if (input.senderEmail != null)
77
+ body.sender_email = input.senderEmail;
78
+ if (input.recipientEmails != null)
79
+ body.recipient_emails = input.recipientEmails;
80
+ if (input.receivedAt != null)
81
+ body.received_at = input.receivedAt;
82
+ if (input.externalId != null)
83
+ body.external_id = input.externalId;
84
+ if (input.threadId != null)
85
+ body.thread_id = input.threadId;
86
+ if (input.metadata != null)
87
+ body.metadata = input.metadata;
88
+ const data = await this.http.post(`/v1/users/${this.userId}/messages`, body);
89
+ if (!data?.id || !data?.status) {
90
+ throw new index_js_1.ServerError('Unexpected response shape from push message endpoint', 500, {
91
+ missingFields: [
92
+ ...(!data?.id ? ['id'] : []),
93
+ ...(!data?.status ? ['status'] : []),
94
+ ],
95
+ received: (() => {
96
+ if (data == null)
97
+ return String(data);
98
+ const raw = JSON.stringify(data);
99
+ return raw.length > 200 ? raw.substring(0, 200) + '...' : raw;
100
+ })(),
101
+ });
102
+ }
103
+ return { ...data };
104
+ }
105
+ /**
106
+ * Push a meeting with transcript, summary, and attendees for the user.
107
+ *
108
+ * @param input - Meeting data
109
+ * @returns Push response with opaque ID (mtg_xxx) and processing status
110
+ *
111
+ * @throws {ValidationError} If required fields are missing or invalid
112
+ * @throws {AuthenticationError} If the API key is invalid or expired
113
+ * @throws {ServerError} If the server encounters an error
114
+ *
115
+ * @example
116
+ * ```ts
117
+ * const result = await attrove.push.meeting({
118
+ * title: 'Weekly Standup',
119
+ * startTime: '2026-03-23T09:00:00Z',
120
+ * endTime: '2026-03-23T09:30:00Z',
121
+ * transcript: 'Alice: Good morning everyone...',
122
+ * summary: 'Discussed sprint progress and blockers.',
123
+ * attendees: [
124
+ * { name: 'Alice Chen', email: 'alice@acme.com' },
125
+ * { name: 'Bob Smith', email: 'bob@acme.com' },
126
+ * ],
127
+ * externalId: 'meeting-xyz',
128
+ * });
129
+ * console.log(result.id); // mtg_xxx
130
+ * ```
131
+ */
132
+ async meeting(input) {
133
+ if (!input.title ||
134
+ typeof input.title !== 'string' ||
135
+ input.title.trim() === '') {
136
+ throw new index_js_1.ValidationError('title is required and must be a non-empty string', index_js_2.ErrorCodes.VALIDATION_REQUIRED_FIELD, { field: 'title' });
137
+ }
138
+ if (!input.startTime) {
139
+ throw new index_js_1.ValidationError('startTime is required (ISO 8601 datetime)', index_js_2.ErrorCodes.VALIDATION_REQUIRED_FIELD, { field: 'startTime' });
140
+ }
141
+ if (!input.endTime) {
142
+ throw new index_js_1.ValidationError('endTime is required (ISO 8601 datetime)', index_js_2.ErrorCodes.VALIDATION_REQUIRED_FIELD, { field: 'endTime' });
143
+ }
144
+ const body = {
145
+ title: input.title,
146
+ start_time: input.startTime,
147
+ end_time: input.endTime,
148
+ };
149
+ if (input.transcript != null)
150
+ body.transcript = input.transcript;
151
+ if (input.summary != null)
152
+ body.summary = input.summary;
153
+ if (input.shortSummary != null)
154
+ body.short_summary = input.shortSummary;
155
+ if (input.actionItems != null)
156
+ body.action_items = input.actionItems;
157
+ if (input.attendees != null)
158
+ body.attendees = input.attendees;
159
+ if (input.externalId != null)
160
+ body.external_id = input.externalId;
161
+ if (input.metadata != null)
162
+ body.metadata = input.metadata;
163
+ const data = await this.http.post(`/v1/users/${this.userId}/meetings`, body);
164
+ if (!data?.id || !data?.status) {
165
+ throw new index_js_1.ServerError('Unexpected response shape from push meeting endpoint', 500, {
166
+ missingFields: [
167
+ ...(!data?.id ? ['id'] : []),
168
+ ...(!data?.status ? ['status'] : []),
169
+ ],
170
+ received: (() => {
171
+ if (data == null)
172
+ return String(data);
173
+ const raw = JSON.stringify(data);
174
+ return raw.length > 200 ? raw.substring(0, 200) + '...' : raw;
175
+ })(),
176
+ });
177
+ }
178
+ return { ...data };
179
+ }
180
+ /**
181
+ * Push a calendar event or milestone for the user.
182
+ *
183
+ * If `endTime` is omitted, it defaults to `startTime` (point-in-time event).
184
+ *
185
+ * @param input - Event data
186
+ * @returns Push response with opaque ID (evt_xxx) and processing status
187
+ *
188
+ * @throws {ValidationError} If required fields are missing or invalid
189
+ * @throws {AuthenticationError} If the API key is invalid or expired
190
+ * @throws {ServerError} If the server encounters an error
191
+ *
192
+ * @example
193
+ * ```ts
194
+ * const result = await attrove.push.event({
195
+ * title: 'Product Launch',
196
+ * startTime: '2026-04-01T00:00:00Z',
197
+ * description: 'V2 launch day — all hands on deck.',
198
+ * allDay: true,
199
+ * externalId: 'milestone-launch-v2',
200
+ * });
201
+ * console.log(result.id); // evt_xxx
202
+ * ```
203
+ */
204
+ async event(input) {
205
+ if (!input.title ||
206
+ typeof input.title !== 'string' ||
207
+ input.title.trim() === '') {
208
+ throw new index_js_1.ValidationError('title is required and must be a non-empty string', index_js_2.ErrorCodes.VALIDATION_REQUIRED_FIELD, { field: 'title' });
209
+ }
210
+ if (!input.startTime) {
211
+ throw new index_js_1.ValidationError('startTime is required (ISO 8601 datetime)', index_js_2.ErrorCodes.VALIDATION_REQUIRED_FIELD, { field: 'startTime' });
212
+ }
213
+ const body = {
214
+ title: input.title,
215
+ start_time: input.startTime,
216
+ };
217
+ if (input.endTime != null)
218
+ body.end_time = input.endTime;
219
+ if (input.description != null)
220
+ body.description = input.description;
221
+ if (input.location != null)
222
+ body.location = input.location;
223
+ if (input.allDay != null)
224
+ body.all_day = input.allDay;
225
+ if (input.externalId != null)
226
+ body.external_id = input.externalId;
227
+ if (input.metadata != null)
228
+ body.metadata = input.metadata;
229
+ const data = await this.http.post(`/v1/users/${this.userId}/events`, body);
230
+ if (!data?.id || !data?.status) {
231
+ throw new index_js_1.ServerError('Unexpected response shape from push event endpoint', 500, {
232
+ missingFields: [
233
+ ...(!data?.id ? ['id'] : []),
234
+ ...(!data?.status ? ['status'] : []),
235
+ ],
236
+ received: (() => {
237
+ if (data == null)
238
+ return String(data);
239
+ const raw = JSON.stringify(data);
240
+ return raw.length > 200 ? raw.substring(0, 200) + '...' : raw;
241
+ })(),
242
+ });
243
+ }
244
+ return { ...data };
245
+ }
246
+ /**
247
+ * Push an analyst note or observation for the user.
248
+ *
249
+ * Notes can optionally reference another primitive (message, meeting, event,
250
+ * or entity) via `refType` and `refId`. Both must be provided together or
251
+ * both omitted. The `refId` must use the correct opaque prefix for its type
252
+ * (msg_xxx, mtg_xxx, evt_xxx, ent_xxx).
253
+ *
254
+ * @param input - Note data
255
+ * @returns Push response with opaque ID (note_xxx) and processing status
256
+ *
257
+ * @throws {ValidationError} If required fields are missing or invalid
258
+ * @throws {AuthenticationError} If the API key is invalid or expired
259
+ * @throws {ServerError} If the server encounters an error
260
+ *
261
+ * @example
262
+ * ```ts
263
+ * // Standalone note
264
+ * const result = await attrove.push.note({
265
+ * body: 'Decision: chose Redis for caching due to latency requirements.',
266
+ * title: 'Architecture Decision',
267
+ * });
268
+ *
269
+ * // Note linked to a message
270
+ * const linked = await attrove.push.note({
271
+ * body: 'This email contains the final pricing agreement.',
272
+ * refType: 'message',
273
+ * refId: 'msg_1Z',
274
+ * });
275
+ * ```
276
+ */
277
+ async note(input) {
278
+ if (!input.body ||
279
+ typeof input.body !== 'string' ||
280
+ input.body.trim() === '') {
281
+ throw new index_js_1.ValidationError('body is required and must be a non-empty string', index_js_2.ErrorCodes.VALIDATION_REQUIRED_FIELD, { field: 'body' });
282
+ }
283
+ const validated = (0, validate_ref_pair_js_1.validateRefPair)(input.refType, input.refId);
284
+ const body = {
285
+ body: input.body,
286
+ };
287
+ if (input.title != null)
288
+ body.title = input.title;
289
+ if (validated.refType != null)
290
+ body.ref_type = validated.refType;
291
+ if (validated.refId != null)
292
+ body.ref_id = validated.refId;
293
+ if (input.externalId != null)
294
+ body.external_id = input.externalId;
295
+ if (input.metadata != null)
296
+ body.metadata = input.metadata;
297
+ const data = await this.http.post(`/v1/users/${this.userId}/notes`, body);
298
+ if (!data?.id || !data?.status) {
299
+ throw new index_js_1.ServerError('Unexpected response shape from push note endpoint', 500, {
300
+ missingFields: [
301
+ ...(!data?.id ? ['id'] : []),
302
+ ...(!data?.status ? ['status'] : []),
303
+ ],
304
+ received: (() => {
305
+ if (data == null)
306
+ return String(data);
307
+ const raw = JSON.stringify(data);
308
+ return raw.length > 200 ? raw.substring(0, 200) + '...' : raw;
309
+ })(),
310
+ });
311
+ }
312
+ return { ...data };
313
+ }
314
+ }
315
+ exports.PushResource = PushResource;
@@ -41,6 +41,7 @@ const VALID_MEETING_PROVIDERS = new Set([
41
41
  'google_meet',
42
42
  'zoom',
43
43
  'teams',
44
+ 'manual_meetings',
44
45
  'unknown',
45
46
  ]);
46
47
  function normalizeMeetingProvider(provider) {
@@ -67,7 +68,31 @@ function normalizeIntegrationType(type) {
67
68
  console.warn(`[Attrove SDK] Unknown integration type "${type}" normalized to "unknown". SDK may need updating.`);
68
69
  return 'unknown';
69
70
  }
71
+ const VALID_CONTENT_STATUSES = new Set([
72
+ 'none',
73
+ 'notes_only',
74
+ 'transcript_only',
75
+ 'transcript_and_notes',
76
+ ]);
77
+ function normalizeMeetingContentStatus(status, hasTranscript, hasNotes) {
78
+ if (status && VALID_CONTENT_STATUSES.has(status)) {
79
+ return status;
80
+ }
81
+ if (status) {
82
+ // prettier-ignore
83
+ console.warn(`[Attrove SDK] Unknown meeting content status "${status}" — deriving from booleans. SDK may need updating.`);
84
+ }
85
+ // Derive from booleans when API doesn't provide the field (older API versions)
86
+ if (hasTranscript && hasNotes)
87
+ return 'transcript_and_notes';
88
+ if (hasTranscript)
89
+ return 'transcript_only';
90
+ if (hasNotes)
91
+ return 'notes_only';
92
+ return 'none';
93
+ }
70
94
  function normalizeSearchMeeting(meeting) {
95
+ const hasNotes = meeting.has_notes ?? false;
71
96
  return {
72
97
  id: meeting.id,
73
98
  title: meeting.title,
@@ -80,6 +105,8 @@ function normalizeSearchMeeting(meeting) {
80
105
  attendees: meeting.attendees,
81
106
  meeting_link: meeting.meeting_link,
82
107
  has_transcript: meeting.has_transcript,
108
+ has_notes: hasNotes,
109
+ content_status: normalizeMeetingContentStatus(meeting.content_status, meeting.has_transcript, hasNotes),
83
110
  provider: normalizeMeetingProvider(meeting.provider),
84
111
  event_id: meeting.event_id,
85
112
  created_at: meeting.created_at,
@@ -213,8 +240,14 @@ class QueryResource {
213
240
  if (options.includeSources) {
214
241
  body.expand = 'sources';
215
242
  }
243
+ if (options.instructions !== undefined) {
244
+ body.instructions = options.instructions;
245
+ }
246
+ if (options.context !== undefined) {
247
+ body.context = options.context;
248
+ }
216
249
  const config = options.idempotencyKey
217
- ? { headers: { "Idempotency-Key": options.idempotencyKey } }
250
+ ? { headers: { 'Idempotency-Key': options.idempotencyKey } }
218
251
  : undefined;
219
252
  const response = await this.http.post(`/v1/users/${this.userId}/query`, body, config);
220
253
  return {
@@ -223,6 +256,7 @@ class QueryResource {
223
256
  used_message_ids: response.used_message_ids,
224
257
  used_meeting_ids: response.used_meeting_ids ?? [],
225
258
  used_event_ids: response.used_event_ids ?? [],
259
+ used_note_ids: response.used_note_ids ?? [],
226
260
  sources: response.sources,
227
261
  };
228
262
  }
@@ -285,6 +319,9 @@ class QueryResource {
285
319
  if (options.entityIds?.length) {
286
320
  body.entity_ids = options.entityIds;
287
321
  }
322
+ if (options.retrievalMode) {
323
+ body.retrieval_mode = options.retrievalMode;
324
+ }
288
325
  if (options.includeBodyText) {
289
326
  expandFields.add('body_text');
290
327
  }
@@ -292,7 +329,7 @@ class QueryResource {
292
329
  body.expand = Array.from(expandFields).join(',');
293
330
  }
294
331
  const config = options.idempotencyKey
295
- ? { headers: { "Idempotency-Key": options.idempotencyKey } }
332
+ ? { headers: { 'Idempotency-Key': options.idempotencyKey } }
296
333
  : undefined;
297
334
  const response = await this.http.post(`/v1/users/${this.userId}/search`, body, config);
298
335
  return normalizeSearchResponse(response);
@@ -11,6 +11,7 @@ const ADMIN_WEBHOOK_SUBSCRIBABLE_EVENT_TYPES = [
11
11
  'meetings.new',
12
12
  'events.new',
13
13
  'events.starting_soon',
14
+ 'notes.new',
14
15
  ];
15
16
  const _arrayCoversType = true;
16
17
  void _arrayCoversType;
@@ -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.UNKNOWN_SENDER = 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;
9
+ exports.PUSH_MESSAGE_SOURCES = exports.NOTE_REF_TYPES = exports.isValidStreamFrame = exports.UNKNOWN_SENDER = 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
  *
@@ -285,6 +285,10 @@ exports.ErrorCodes = {
285
285
  INTEGRATION_NOT_CONNECTED: 'INTEGRATION_NOT_CONNECTED',
286
286
  // Rate limiting
287
287
  RATE_LIMIT_EXCEEDED: 'RATE_LIMIT_EXCEEDED',
288
+ // Meeting errors
289
+ MEETING_SYNC_FAILED: 'MEETING_SYNC_FAILED',
290
+ MEETING_SUMMARY_FAILED: 'MEETING_SUMMARY_FAILED',
291
+ MEETING_REINDEX_FAILED: 'MEETING_REINDEX_FAILED',
288
292
  // Server errors
289
293
  INTERNAL_ERROR: 'INTERNAL_ERROR',
290
294
  SERVICE_UNAVAILABLE: 'SERVICE_UNAVAILABLE',
@@ -340,7 +344,8 @@ function isValidStreamFrame(data) {
340
344
  ['completed', 'cancelled', 'error'].includes(frame.reason) &&
341
345
  isOptionalStringArray(frame.used_message_ids) &&
342
346
  isOptionalStringArray(frame.used_meeting_ids) &&
343
- isOptionalStringArray(frame.used_event_ids));
347
+ isOptionalStringArray(frame.used_event_ids) &&
348
+ isOptionalStringArray(frame.used_note_ids));
344
349
  case 'error':
345
350
  return typeof frame.error === 'string';
346
351
  case 'state':
@@ -349,7 +354,8 @@ function isValidStreamFrame(data) {
349
354
  return (Array.isArray(frame.used_message_ids) &&
350
355
  frame.used_message_ids.every((id) => typeof id === 'string') &&
351
356
  isOptionalStringArray(frame.used_meeting_ids) &&
352
- isOptionalStringArray(frame.used_event_ids));
357
+ isOptionalStringArray(frame.used_event_ids) &&
358
+ isOptionalStringArray(frame.used_note_ids));
353
359
  case 'stream_start':
354
360
  return true;
355
361
  default:
@@ -363,3 +369,17 @@ function isOptionalStringArray(value) {
363
369
  return (Array.isArray(value) &&
364
370
  value.every((item) => typeof item === 'string'));
365
371
  }
372
+ /** Canonical list of valid note reference types — use for runtime validation. */
373
+ exports.NOTE_REF_TYPES = [
374
+ 'message',
375
+ 'meeting',
376
+ 'event',
377
+ 'entity',
378
+ ];
379
+ /** Canonical list of valid push message source types — use for runtime validation. */
380
+ exports.PUSH_MESSAGE_SOURCES = [
381
+ 'email',
382
+ 'chat',
383
+ 'alert',
384
+ 'custom',
385
+ ];
@@ -3,7 +3,7 @@
3
3
  * Utility exports
4
4
  */
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.verifyWebhookSignatureDetailed = exports.verifyWebhookSignature = exports.generateMessageId = exports.StreamingClient = exports.HttpClient = void 0;
6
+ exports.validateRefPair = exports.verifyWebhookSignatureDetailed = exports.verifyWebhookSignature = exports.generateMessageId = exports.StreamingClient = exports.HttpClient = void 0;
7
7
  var fetch_js_1 = require("./fetch.js");
8
8
  Object.defineProperty(exports, "HttpClient", { enumerable: true, get: function () { return fetch_js_1.HttpClient; } });
9
9
  var streaming_js_1 = require("./streaming.js");
@@ -12,3 +12,5 @@ Object.defineProperty(exports, "generateMessageId", { enumerable: true, get: fun
12
12
  var webhooks_js_1 = require("./webhooks.js");
13
13
  Object.defineProperty(exports, "verifyWebhookSignature", { enumerable: true, get: function () { return webhooks_js_1.verifyWebhookSignature; } });
14
14
  Object.defineProperty(exports, "verifyWebhookSignatureDetailed", { enumerable: true, get: function () { return webhooks_js_1.verifyWebhookSignatureDetailed; } });
15
+ var validate_ref_pair_js_1 = require("./validate-ref-pair.js");
16
+ Object.defineProperty(exports, "validateRefPair", { enumerable: true, get: function () { return validate_ref_pair_js_1.validateRefPair; } });