@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.
- package/README.md +8 -0
- package/cjs/client.js +4 -0
- package/cjs/constants.js +1 -1
- package/cjs/resources/index.js +5 -1
- package/cjs/resources/notes.js +106 -0
- package/cjs/resources/push.js +315 -0
- package/cjs/resources/query.js +39 -2
- package/cjs/resources/webhooks.js +1 -0
- package/cjs/types/index.js +23 -3
- package/cjs/utils/index.js +3 -1
- package/cjs/utils/streaming.js +8 -0
- package/cjs/utils/validate-ref-pair.js +45 -0
- package/esm/client.d.ts +12 -0
- package/esm/client.d.ts.map +1 -1
- package/esm/client.js +4 -0
- package/esm/client.js.map +1 -1
- package/esm/constants.d.ts +1 -1
- package/esm/constants.d.ts.map +1 -1
- package/esm/constants.js +1 -1
- package/esm/constants.js.map +1 -1
- package/esm/index.d.ts +1 -0
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js.map +1 -1
- package/esm/resources/index.d.ts +3 -0
- package/esm/resources/index.d.ts.map +1 -1
- package/esm/resources/index.js +2 -0
- package/esm/resources/index.js.map +1 -1
- package/esm/resources/notes.d.ts +80 -0
- package/esm/resources/notes.d.ts.map +1 -0
- package/esm/resources/notes.js +103 -0
- package/esm/resources/notes.js.map +1 -0
- package/esm/resources/push.d.ts +140 -0
- package/esm/resources/push.d.ts.map +1 -0
- package/esm/resources/push.js +312 -0
- package/esm/resources/push.js.map +1 -0
- package/esm/resources/query.d.ts.map +1 -1
- package/esm/resources/query.js +39 -2
- package/esm/resources/query.js.map +1 -1
- package/esm/resources/webhooks.d.ts +1 -1
- package/esm/resources/webhooks.d.ts.map +1 -1
- package/esm/resources/webhooks.js +1 -0
- package/esm/resources/webhooks.js.map +1 -1
- package/esm/types/index.d.ts +225 -7
- package/esm/types/index.d.ts.map +1 -1
- package/esm/types/index.js +22 -2
- package/esm/types/index.js.map +1 -1
- package/esm/utils/index.d.ts +1 -0
- package/esm/utils/index.d.ts.map +1 -1
- package/esm/utils/index.js +1 -0
- package/esm/utils/index.js.map +1 -1
- package/esm/utils/streaming.d.ts +4 -0
- package/esm/utils/streaming.d.ts.map +1 -1
- package/esm/utils/streaming.js +8 -0
- package/esm/utils/streaming.js.map +1 -1
- package/esm/utils/validate-ref-pair.d.ts +23 -0
- package/esm/utils/validate-ref-pair.d.ts.map +1 -0
- package/esm/utils/validate-ref-pair.js +42 -0
- package/esm/utils/validate-ref-pair.js.map +1 -0
- 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
|
|
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
|
*/
|
package/cjs/resources/index.js
CHANGED
|
@@ -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;
|
package/cjs/resources/query.js
CHANGED
|
@@ -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: {
|
|
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: {
|
|
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);
|
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.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
|
+
];
|
package/cjs/utils/index.js
CHANGED
|
@@ -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; } });
|