vessels-sdk 0.6.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -160,6 +160,8 @@ var WebhookVesselSchema = zod.z.object({
160
160
  id: zod.z.string(),
161
161
  external_id: zod.z.string().nullable(),
162
162
  title: zod.z.string().nullable(),
163
+ /** The vessel's type (e.g. "Ticket"). Nullable — agent-created vessels have no type. */
164
+ type: zod.z.string().nullable().optional(),
163
165
  metadata: zod.z.record(zod.z.unknown())
164
166
  });
165
167
  var WebhookContextMessageSchema = zod.z.object({
@@ -202,9 +204,35 @@ var WebhookUserMessagePayloadSchema = zod.z.object({
202
204
  context: zod.z.array(WebhookContextMessageSchema)
203
205
  })
204
206
  });
207
+ var WebhookVesselCreatedPayloadSchema = zod.z.object({
208
+ event: zod.z.literal("vessel.created"),
209
+ vessel_id: zod.z.string(),
210
+ workspace_id: zod.z.string(),
211
+ timestamp: zod.z.string(),
212
+ data: zod.z.object({
213
+ vessel: WebhookVesselSchema,
214
+ message: zod.z.object({
215
+ message_id: zod.z.string(),
216
+ content: zod.z.string().nullable(),
217
+ created_at: zod.z.string()
218
+ })
219
+ })
220
+ });
221
+ var WebhookMessageCancelledPayloadSchema = zod.z.object({
222
+ event: zod.z.literal("message.cancelled"),
223
+ vessel_id: zod.z.string(),
224
+ workspace_id: zod.z.string(),
225
+ timestamp: zod.z.string(),
226
+ data: zod.z.object({
227
+ message_id: zod.z.string(),
228
+ vessel: WebhookVesselSchema
229
+ })
230
+ });
205
231
  var WebhookPayloadSchema = zod.z.discriminatedUnion("event", [
206
232
  WebhookInteractionResponsePayloadSchema,
207
- WebhookUserMessagePayloadSchema
233
+ WebhookUserMessagePayloadSchema,
234
+ WebhookVesselCreatedPayloadSchema,
235
+ WebhookMessageCancelledPayloadSchema
208
236
  ]);
209
237
 
210
238
  // src/index.ts
@@ -237,6 +265,12 @@ var VesselsRateLimitError = class extends Error {
237
265
  this.retryAfter = retryAfter;
238
266
  }
239
267
  };
268
+ var VesselsConflictError = class extends Error {
269
+ constructor(message) {
270
+ super(message);
271
+ this.name = "VesselsConflictError";
272
+ }
273
+ };
240
274
  var Vessels = class {
241
275
  apiKey;
242
276
  baseUrl;
@@ -270,38 +304,45 @@ var Vessels = class {
270
304
  return res;
271
305
  }
272
306
  async push(payload) {
307
+ const { idempotencyKey, ...body } = payload;
273
308
  const res = await this._fetch(`${this.baseUrl}/api/v1/push`, {
274
309
  method: "POST",
275
310
  headers: {
276
311
  "Content-Type": "application/json",
277
- "Authorization": `Bearer ${this.apiKey}`
312
+ "Authorization": `Bearer ${this.apiKey}`,
313
+ ...idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}
278
314
  },
279
- body: JSON.stringify(payload)
315
+ body: JSON.stringify(body)
280
316
  });
281
317
  const data = await res.json();
282
318
  if (res.status === 401) throw new VesselsAuthError(data.error ?? "Unauthorized");
283
319
  if (res.status === 429) throw new VesselsRateLimitError(data.error ?? "Rate limited", Number(res.headers.get("retry-after")));
320
+ if (res.status === 409) throw new VesselsConflictError(data.error ?? "Idempotent request in progress");
284
321
  if (res.status === 400) throw new VesselsValidationError(data.error ?? "Validation failed", data.details);
285
322
  if (!res.ok) throw new Error(data.error ?? `HTTP ${res.status}`);
286
323
  return {
287
324
  ok: true,
288
325
  messageId: data.message_id,
289
326
  vesselId: data.vessel_id,
290
- createdAt: data.created_at
327
+ createdAt: data.created_at,
328
+ replayed: res.headers.get("Idempotent-Replayed") === "true"
291
329
  };
292
330
  }
293
331
  async pushMany(payload) {
332
+ const { idempotencyKey, ...body } = payload;
294
333
  const res = await this._fetch(`${this.baseUrl}/api/v1/push/many`, {
295
334
  method: "POST",
296
335
  headers: {
297
336
  "Content-Type": "application/json",
298
- "Authorization": `Bearer ${this.apiKey}`
337
+ "Authorization": `Bearer ${this.apiKey}`,
338
+ ...idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}
299
339
  },
300
- body: JSON.stringify(payload)
340
+ body: JSON.stringify(body)
301
341
  });
302
342
  const data = await res.json();
303
343
  if (res.status === 401) throw new VesselsAuthError(data.error ?? "Unauthorized");
304
344
  if (res.status === 429) throw new VesselsRateLimitError(data.error ?? "Rate limited", Number(res.headers.get("retry-after")));
345
+ if (res.status === 409) throw new VesselsConflictError(data.error ?? "Idempotent request in progress");
305
346
  if (res.status === 400) throw new VesselsValidationError(data.error ?? "Validation failed", data.details);
306
347
  if (!res.ok) throw new Error(data.error ?? `HTTP ${res.status}`);
307
348
  return {
@@ -311,7 +352,8 @@ var Vessels = class {
311
352
  messageId: r.message_id,
312
353
  vesselId: r.vessel_id,
313
354
  ...r.error ? { error: r.error } : {}
314
- }))
355
+ })),
356
+ replayed: res.headers.get("Idempotent-Replayed") === "true"
315
357
  };
316
358
  }
317
359
  async editMessage(messageId, patch) {
@@ -396,9 +438,19 @@ var Vessels = class {
396
438
  id: e.vessel?.id,
397
439
  externalId: e.vessel?.external_id ?? null,
398
440
  title: e.vessel?.title ?? null,
441
+ type: e.vessel?.type ?? null,
399
442
  metadata: e.vessel?.metadata ?? {},
400
443
  labels: e.vessel?.labels ?? []
401
444
  };
445
+ if (e.type === "vessel.created") {
446
+ return {
447
+ id: e.id,
448
+ type: "vessel.created",
449
+ timestamp: e.timestamp,
450
+ vessel,
451
+ message: { id: e.message?.id, content: e.message?.content ?? null }
452
+ };
453
+ }
402
454
  if (e.type === "interaction.response") {
403
455
  return {
404
456
  id: e.id,
@@ -470,9 +522,22 @@ var Vessels = class {
470
522
  id: v.id,
471
523
  externalId: v.external_id ?? null,
472
524
  title: v.title ?? null,
525
+ type: v.type ?? null,
473
526
  metadata: v.metadata ?? {},
474
527
  labels: v.labels ?? []
475
528
  };
529
+ if (raw.event === "vessel.created") {
530
+ return {
531
+ id: raw.vessel_id,
532
+ type: "vessel.created",
533
+ timestamp: raw.timestamp,
534
+ vessel,
535
+ message: {
536
+ id: raw.data.message?.message_id,
537
+ content: raw.data.message?.content ?? null
538
+ }
539
+ };
540
+ }
476
541
  if (raw.event === "interaction.response") {
477
542
  return {
478
543
  id: raw.data.response_id,
@@ -493,6 +558,15 @@ var Vessels = class {
493
558
  user: raw.data.user ?? null
494
559
  };
495
560
  }
561
+ if (raw.event === "message.cancelled") {
562
+ return {
563
+ id: raw.data.message_id,
564
+ type: "message.cancelled",
565
+ timestamp: raw.timestamp,
566
+ vessel,
567
+ messageId: raw.data.message_id
568
+ };
569
+ }
496
570
  if (raw.event === "message.user") {
497
571
  return {
498
572
  id: raw.data.message_id,
@@ -517,8 +591,10 @@ var Vessels = class {
517
591
  exports.AgentActivityTypes = AgentActivityTypes;
518
592
  exports.Vessels = Vessels;
519
593
  exports.VesselsAuthError = VesselsAuthError;
594
+ exports.VesselsConflictError = VesselsConflictError;
520
595
  exports.VesselsRateLimitError = VesselsRateLimitError;
521
596
  exports.VesselsValidationError = VesselsValidationError;
522
597
  exports.WebhookInteractionResponsePayloadSchema = WebhookInteractionResponsePayloadSchema;
523
598
  exports.WebhookPayloadSchema = WebhookPayloadSchema;
524
599
  exports.WebhookUserMessagePayloadSchema = WebhookUserMessagePayloadSchema;
600
+ exports.WebhookVesselCreatedPayloadSchema = WebhookVesselCreatedPayloadSchema;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _vessels_types from '@vessels/types';
2
- export { AgentActivity, AgentActivityType, ApprovalInteraction, Attachment, Card, ChecklistInteraction, ChoiceInteraction, ConfirmPreviewInteraction, Interaction, MessagePatch, PushManyPayload, PushPayload, TextInputInteraction, WebhookInteractionResponsePayload, WebhookInteractionResponsePayloadSchema, WebhookPayload, WebhookPayloadSchema, WebhookUserMessagePayload, WebhookUserMessagePayloadSchema } from '@vessels/types';
2
+ export { AgentActivity, AgentActivityType, ApprovalInteraction, Attachment, Card, ChecklistInteraction, ChoiceInteraction, ConfirmPreviewInteraction, Interaction, MessagePatch, PushManyOptions, PushManyPayload, PushOptions, PushPayload, TextInputInteraction, WebhookInteractionResponsePayload, WebhookInteractionResponsePayloadSchema, WebhookPayload, WebhookPayloadSchema, WebhookUserMessagePayload, WebhookUserMessagePayloadSchema, WebhookVesselCreatedPayload, WebhookVesselCreatedPayloadSchema } from '@vessels/types';
3
3
 
4
4
  declare const AgentActivityTypes: {
5
5
  readonly thinking: "thinking";
@@ -19,6 +19,10 @@ declare class VesselsRateLimitError extends Error {
19
19
  retryAfter?: number;
20
20
  constructor(message: string, retryAfter?: number);
21
21
  }
22
+ /** Thrown on HTTP 409 — an identical idempotent request is still in flight. Back off and retry. */
23
+ declare class VesselsConflictError extends Error {
24
+ constructor(message: string);
25
+ }
22
26
  interface VesselsConfig {
23
27
  apiKey: string;
24
28
  baseUrl?: string;
@@ -29,6 +33,8 @@ interface PushResponse {
29
33
  messageId: string;
30
34
  vesselId: string;
31
35
  createdAt: string;
36
+ /** True when this response is a replay of an earlier request with the same idempotency key. */
37
+ replayed: boolean;
32
38
  }
33
39
  interface PushManyResult {
34
40
  ok: true;
@@ -38,6 +44,8 @@ interface PushManyResult {
38
44
  vesselId: string;
39
45
  error?: string;
40
46
  }>;
47
+ /** True when this response is a replay of an earlier request with the same idempotency key. */
48
+ replayed: boolean;
41
49
  }
42
50
  interface PollOptions {
43
51
  since?: string;
@@ -48,6 +56,8 @@ interface VesselContext {
48
56
  id: string;
49
57
  externalId: string | null;
50
58
  title: string | null;
59
+ /** The vessel's type (e.g. "Ticket"). Null for agent-created vessels. */
60
+ type: string | null;
51
61
  metadata: Record<string, unknown>;
52
62
  labels: string[];
53
63
  }
@@ -91,6 +101,35 @@ interface UserMessageEvent {
91
101
  createdAt: string;
92
102
  }>;
93
103
  }
104
+ /**
105
+ * Fired when a human opens a new typed vessel from the app (user-initiated
106
+ * vessels). `message` is the first thing the human typed; `vessel.type` is the
107
+ * vessel's type (e.g. "Ticket").
108
+ */
109
+ interface VesselCreatedEvent {
110
+ id: string;
111
+ type: 'vessel.created';
112
+ timestamp: string;
113
+ vessel: VesselContext;
114
+ message: {
115
+ id: string;
116
+ content: string | null;
117
+ };
118
+ }
119
+ /**
120
+ * Fired when a human taps "Stop" on an in-progress (working) agent message in
121
+ * the app. Vessels does NOT force-stop anything — you decide what to do (abort
122
+ * a task, stop polling, ignore it). Delivery is synchronous: the app tells the
123
+ * human whether your handler accepted it (return 2xx) so they know cancel is
124
+ * wired up. `messageId` is the working agent message the human wants stopped.
125
+ */
126
+ interface MessageCancelledEvent {
127
+ id: string;
128
+ type: 'message.cancelled';
129
+ timestamp: string;
130
+ vessel: VesselContext;
131
+ messageId: string;
132
+ }
94
133
  /** A message in a vessel, as returned by getMessages — the human-facing record. */
95
134
  interface Message {
96
135
  id: string;
@@ -103,7 +142,7 @@ interface Message {
103
142
  metadata: Record<string, unknown>;
104
143
  createdAt: string;
105
144
  }
106
- type PollEvent = InteractionResponseEvent | UserMessageEvent;
145
+ type PollEvent = InteractionResponseEvent | UserMessageEvent | VesselCreatedEvent;
107
146
  interface PollResponse {
108
147
  ok: true;
109
148
  events: PollEvent[];
@@ -115,8 +154,8 @@ declare class Vessels {
115
154
  private _debug;
116
155
  constructor(config: VesselsConfig);
117
156
  private _fetch;
118
- push(payload: _vessels_types.PushPayload): Promise<PushResponse>;
119
- pushMany(payload: _vessels_types.PushManyPayload): Promise<PushManyResult>;
157
+ push(payload: _vessels_types.PushOptions): Promise<PushResponse>;
158
+ pushMany(payload: _vessels_types.PushManyOptions): Promise<PushManyResult>;
120
159
  editMessage(messageId: string, patch: _vessels_types.MessagePatch): Promise<{
121
160
  ok: true;
122
161
  }>;
@@ -182,7 +221,7 @@ declare class Vessels {
182
221
  }): _vessels_types.ConfirmPreviewInteraction;
183
222
  poll(options?: PollOptions): Promise<PollResponse>;
184
223
  verifyWebhook(body: string, signature: string, webhookSecret: string): Promise<boolean>;
185
- parseWebhookEvent(body: string, signature: string, webhookSecret: string): Promise<InteractionResponseEvent | UserMessageEvent | null>;
224
+ parseWebhookEvent(body: string, signature: string, webhookSecret: string): Promise<InteractionResponseEvent | UserMessageEvent | VesselCreatedEvent | MessageCancelledEvent | null>;
186
225
  }
187
226
 
188
- export { AgentActivityTypes, type InteractionResponseEvent, type Message, type OriginMessage, type PollEvent, type PollOptions, type PollResponse, type PushManyResult, type PushResponse, type UserMessageEvent, type VesselContext, Vessels, VesselsAuthError, type VesselsConfig, VesselsRateLimitError, VesselsValidationError };
227
+ export { AgentActivityTypes, type InteractionResponseEvent, type Message, type MessageCancelledEvent, type OriginMessage, type PollEvent, type PollOptions, type PollResponse, type PushManyResult, type PushResponse, type UserMessageEvent, type VesselContext, type VesselCreatedEvent, Vessels, VesselsAuthError, type VesselsConfig, VesselsConflictError, VesselsRateLimitError, VesselsValidationError };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _vessels_types from '@vessels/types';
2
- export { AgentActivity, AgentActivityType, ApprovalInteraction, Attachment, Card, ChecklistInteraction, ChoiceInteraction, ConfirmPreviewInteraction, Interaction, MessagePatch, PushManyPayload, PushPayload, TextInputInteraction, WebhookInteractionResponsePayload, WebhookInteractionResponsePayloadSchema, WebhookPayload, WebhookPayloadSchema, WebhookUserMessagePayload, WebhookUserMessagePayloadSchema } from '@vessels/types';
2
+ export { AgentActivity, AgentActivityType, ApprovalInteraction, Attachment, Card, ChecklistInteraction, ChoiceInteraction, ConfirmPreviewInteraction, Interaction, MessagePatch, PushManyOptions, PushManyPayload, PushOptions, PushPayload, TextInputInteraction, WebhookInteractionResponsePayload, WebhookInteractionResponsePayloadSchema, WebhookPayload, WebhookPayloadSchema, WebhookUserMessagePayload, WebhookUserMessagePayloadSchema, WebhookVesselCreatedPayload, WebhookVesselCreatedPayloadSchema } from '@vessels/types';
3
3
 
4
4
  declare const AgentActivityTypes: {
5
5
  readonly thinking: "thinking";
@@ -19,6 +19,10 @@ declare class VesselsRateLimitError extends Error {
19
19
  retryAfter?: number;
20
20
  constructor(message: string, retryAfter?: number);
21
21
  }
22
+ /** Thrown on HTTP 409 — an identical idempotent request is still in flight. Back off and retry. */
23
+ declare class VesselsConflictError extends Error {
24
+ constructor(message: string);
25
+ }
22
26
  interface VesselsConfig {
23
27
  apiKey: string;
24
28
  baseUrl?: string;
@@ -29,6 +33,8 @@ interface PushResponse {
29
33
  messageId: string;
30
34
  vesselId: string;
31
35
  createdAt: string;
36
+ /** True when this response is a replay of an earlier request with the same idempotency key. */
37
+ replayed: boolean;
32
38
  }
33
39
  interface PushManyResult {
34
40
  ok: true;
@@ -38,6 +44,8 @@ interface PushManyResult {
38
44
  vesselId: string;
39
45
  error?: string;
40
46
  }>;
47
+ /** True when this response is a replay of an earlier request with the same idempotency key. */
48
+ replayed: boolean;
41
49
  }
42
50
  interface PollOptions {
43
51
  since?: string;
@@ -48,6 +56,8 @@ interface VesselContext {
48
56
  id: string;
49
57
  externalId: string | null;
50
58
  title: string | null;
59
+ /** The vessel's type (e.g. "Ticket"). Null for agent-created vessels. */
60
+ type: string | null;
51
61
  metadata: Record<string, unknown>;
52
62
  labels: string[];
53
63
  }
@@ -91,6 +101,35 @@ interface UserMessageEvent {
91
101
  createdAt: string;
92
102
  }>;
93
103
  }
104
+ /**
105
+ * Fired when a human opens a new typed vessel from the app (user-initiated
106
+ * vessels). `message` is the first thing the human typed; `vessel.type` is the
107
+ * vessel's type (e.g. "Ticket").
108
+ */
109
+ interface VesselCreatedEvent {
110
+ id: string;
111
+ type: 'vessel.created';
112
+ timestamp: string;
113
+ vessel: VesselContext;
114
+ message: {
115
+ id: string;
116
+ content: string | null;
117
+ };
118
+ }
119
+ /**
120
+ * Fired when a human taps "Stop" on an in-progress (working) agent message in
121
+ * the app. Vessels does NOT force-stop anything — you decide what to do (abort
122
+ * a task, stop polling, ignore it). Delivery is synchronous: the app tells the
123
+ * human whether your handler accepted it (return 2xx) so they know cancel is
124
+ * wired up. `messageId` is the working agent message the human wants stopped.
125
+ */
126
+ interface MessageCancelledEvent {
127
+ id: string;
128
+ type: 'message.cancelled';
129
+ timestamp: string;
130
+ vessel: VesselContext;
131
+ messageId: string;
132
+ }
94
133
  /** A message in a vessel, as returned by getMessages — the human-facing record. */
95
134
  interface Message {
96
135
  id: string;
@@ -103,7 +142,7 @@ interface Message {
103
142
  metadata: Record<string, unknown>;
104
143
  createdAt: string;
105
144
  }
106
- type PollEvent = InteractionResponseEvent | UserMessageEvent;
145
+ type PollEvent = InteractionResponseEvent | UserMessageEvent | VesselCreatedEvent;
107
146
  interface PollResponse {
108
147
  ok: true;
109
148
  events: PollEvent[];
@@ -115,8 +154,8 @@ declare class Vessels {
115
154
  private _debug;
116
155
  constructor(config: VesselsConfig);
117
156
  private _fetch;
118
- push(payload: _vessels_types.PushPayload): Promise<PushResponse>;
119
- pushMany(payload: _vessels_types.PushManyPayload): Promise<PushManyResult>;
157
+ push(payload: _vessels_types.PushOptions): Promise<PushResponse>;
158
+ pushMany(payload: _vessels_types.PushManyOptions): Promise<PushManyResult>;
120
159
  editMessage(messageId: string, patch: _vessels_types.MessagePatch): Promise<{
121
160
  ok: true;
122
161
  }>;
@@ -182,7 +221,7 @@ declare class Vessels {
182
221
  }): _vessels_types.ConfirmPreviewInteraction;
183
222
  poll(options?: PollOptions): Promise<PollResponse>;
184
223
  verifyWebhook(body: string, signature: string, webhookSecret: string): Promise<boolean>;
185
- parseWebhookEvent(body: string, signature: string, webhookSecret: string): Promise<InteractionResponseEvent | UserMessageEvent | null>;
224
+ parseWebhookEvent(body: string, signature: string, webhookSecret: string): Promise<InteractionResponseEvent | UserMessageEvent | VesselCreatedEvent | MessageCancelledEvent | null>;
186
225
  }
187
226
 
188
- export { AgentActivityTypes, type InteractionResponseEvent, type Message, type OriginMessage, type PollEvent, type PollOptions, type PollResponse, type PushManyResult, type PushResponse, type UserMessageEvent, type VesselContext, Vessels, VesselsAuthError, type VesselsConfig, VesselsRateLimitError, VesselsValidationError };
227
+ export { AgentActivityTypes, type InteractionResponseEvent, type Message, type MessageCancelledEvent, type OriginMessage, type PollEvent, type PollOptions, type PollResponse, type PushManyResult, type PushResponse, type UserMessageEvent, type VesselContext, type VesselCreatedEvent, Vessels, VesselsAuthError, type VesselsConfig, VesselsConflictError, VesselsRateLimitError, VesselsValidationError };
package/dist/index.js CHANGED
@@ -158,6 +158,8 @@ var WebhookVesselSchema = z.object({
158
158
  id: z.string(),
159
159
  external_id: z.string().nullable(),
160
160
  title: z.string().nullable(),
161
+ /** The vessel's type (e.g. "Ticket"). Nullable — agent-created vessels have no type. */
162
+ type: z.string().nullable().optional(),
161
163
  metadata: z.record(z.unknown())
162
164
  });
163
165
  var WebhookContextMessageSchema = z.object({
@@ -200,9 +202,35 @@ var WebhookUserMessagePayloadSchema = z.object({
200
202
  context: z.array(WebhookContextMessageSchema)
201
203
  })
202
204
  });
205
+ var WebhookVesselCreatedPayloadSchema = z.object({
206
+ event: z.literal("vessel.created"),
207
+ vessel_id: z.string(),
208
+ workspace_id: z.string(),
209
+ timestamp: z.string(),
210
+ data: z.object({
211
+ vessel: WebhookVesselSchema,
212
+ message: z.object({
213
+ message_id: z.string(),
214
+ content: z.string().nullable(),
215
+ created_at: z.string()
216
+ })
217
+ })
218
+ });
219
+ var WebhookMessageCancelledPayloadSchema = z.object({
220
+ event: z.literal("message.cancelled"),
221
+ vessel_id: z.string(),
222
+ workspace_id: z.string(),
223
+ timestamp: z.string(),
224
+ data: z.object({
225
+ message_id: z.string(),
226
+ vessel: WebhookVesselSchema
227
+ })
228
+ });
203
229
  var WebhookPayloadSchema = z.discriminatedUnion("event", [
204
230
  WebhookInteractionResponsePayloadSchema,
205
- WebhookUserMessagePayloadSchema
231
+ WebhookUserMessagePayloadSchema,
232
+ WebhookVesselCreatedPayloadSchema,
233
+ WebhookMessageCancelledPayloadSchema
206
234
  ]);
207
235
 
208
236
  // src/index.ts
@@ -235,6 +263,12 @@ var VesselsRateLimitError = class extends Error {
235
263
  this.retryAfter = retryAfter;
236
264
  }
237
265
  };
266
+ var VesselsConflictError = class extends Error {
267
+ constructor(message) {
268
+ super(message);
269
+ this.name = "VesselsConflictError";
270
+ }
271
+ };
238
272
  var Vessels = class {
239
273
  apiKey;
240
274
  baseUrl;
@@ -268,38 +302,45 @@ var Vessels = class {
268
302
  return res;
269
303
  }
270
304
  async push(payload) {
305
+ const { idempotencyKey, ...body } = payload;
271
306
  const res = await this._fetch(`${this.baseUrl}/api/v1/push`, {
272
307
  method: "POST",
273
308
  headers: {
274
309
  "Content-Type": "application/json",
275
- "Authorization": `Bearer ${this.apiKey}`
310
+ "Authorization": `Bearer ${this.apiKey}`,
311
+ ...idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}
276
312
  },
277
- body: JSON.stringify(payload)
313
+ body: JSON.stringify(body)
278
314
  });
279
315
  const data = await res.json();
280
316
  if (res.status === 401) throw new VesselsAuthError(data.error ?? "Unauthorized");
281
317
  if (res.status === 429) throw new VesselsRateLimitError(data.error ?? "Rate limited", Number(res.headers.get("retry-after")));
318
+ if (res.status === 409) throw new VesselsConflictError(data.error ?? "Idempotent request in progress");
282
319
  if (res.status === 400) throw new VesselsValidationError(data.error ?? "Validation failed", data.details);
283
320
  if (!res.ok) throw new Error(data.error ?? `HTTP ${res.status}`);
284
321
  return {
285
322
  ok: true,
286
323
  messageId: data.message_id,
287
324
  vesselId: data.vessel_id,
288
- createdAt: data.created_at
325
+ createdAt: data.created_at,
326
+ replayed: res.headers.get("Idempotent-Replayed") === "true"
289
327
  };
290
328
  }
291
329
  async pushMany(payload) {
330
+ const { idempotencyKey, ...body } = payload;
292
331
  const res = await this._fetch(`${this.baseUrl}/api/v1/push/many`, {
293
332
  method: "POST",
294
333
  headers: {
295
334
  "Content-Type": "application/json",
296
- "Authorization": `Bearer ${this.apiKey}`
335
+ "Authorization": `Bearer ${this.apiKey}`,
336
+ ...idempotencyKey ? { "Idempotency-Key": idempotencyKey } : {}
297
337
  },
298
- body: JSON.stringify(payload)
338
+ body: JSON.stringify(body)
299
339
  });
300
340
  const data = await res.json();
301
341
  if (res.status === 401) throw new VesselsAuthError(data.error ?? "Unauthorized");
302
342
  if (res.status === 429) throw new VesselsRateLimitError(data.error ?? "Rate limited", Number(res.headers.get("retry-after")));
343
+ if (res.status === 409) throw new VesselsConflictError(data.error ?? "Idempotent request in progress");
303
344
  if (res.status === 400) throw new VesselsValidationError(data.error ?? "Validation failed", data.details);
304
345
  if (!res.ok) throw new Error(data.error ?? `HTTP ${res.status}`);
305
346
  return {
@@ -309,7 +350,8 @@ var Vessels = class {
309
350
  messageId: r.message_id,
310
351
  vesselId: r.vessel_id,
311
352
  ...r.error ? { error: r.error } : {}
312
- }))
353
+ })),
354
+ replayed: res.headers.get("Idempotent-Replayed") === "true"
313
355
  };
314
356
  }
315
357
  async editMessage(messageId, patch) {
@@ -394,9 +436,19 @@ var Vessels = class {
394
436
  id: e.vessel?.id,
395
437
  externalId: e.vessel?.external_id ?? null,
396
438
  title: e.vessel?.title ?? null,
439
+ type: e.vessel?.type ?? null,
397
440
  metadata: e.vessel?.metadata ?? {},
398
441
  labels: e.vessel?.labels ?? []
399
442
  };
443
+ if (e.type === "vessel.created") {
444
+ return {
445
+ id: e.id,
446
+ type: "vessel.created",
447
+ timestamp: e.timestamp,
448
+ vessel,
449
+ message: { id: e.message?.id, content: e.message?.content ?? null }
450
+ };
451
+ }
400
452
  if (e.type === "interaction.response") {
401
453
  return {
402
454
  id: e.id,
@@ -468,9 +520,22 @@ var Vessels = class {
468
520
  id: v.id,
469
521
  externalId: v.external_id ?? null,
470
522
  title: v.title ?? null,
523
+ type: v.type ?? null,
471
524
  metadata: v.metadata ?? {},
472
525
  labels: v.labels ?? []
473
526
  };
527
+ if (raw.event === "vessel.created") {
528
+ return {
529
+ id: raw.vessel_id,
530
+ type: "vessel.created",
531
+ timestamp: raw.timestamp,
532
+ vessel,
533
+ message: {
534
+ id: raw.data.message?.message_id,
535
+ content: raw.data.message?.content ?? null
536
+ }
537
+ };
538
+ }
474
539
  if (raw.event === "interaction.response") {
475
540
  return {
476
541
  id: raw.data.response_id,
@@ -491,6 +556,15 @@ var Vessels = class {
491
556
  user: raw.data.user ?? null
492
557
  };
493
558
  }
559
+ if (raw.event === "message.cancelled") {
560
+ return {
561
+ id: raw.data.message_id,
562
+ type: "message.cancelled",
563
+ timestamp: raw.timestamp,
564
+ vessel,
565
+ messageId: raw.data.message_id
566
+ };
567
+ }
494
568
  if (raw.event === "message.user") {
495
569
  return {
496
570
  id: raw.data.message_id,
@@ -512,4 +586,4 @@ var Vessels = class {
512
586
  }
513
587
  };
514
588
 
515
- export { AgentActivityTypes, Vessels, VesselsAuthError, VesselsRateLimitError, VesselsValidationError, WebhookInteractionResponsePayloadSchema, WebhookPayloadSchema, WebhookUserMessagePayloadSchema };
589
+ export { AgentActivityTypes, Vessels, VesselsAuthError, VesselsConflictError, VesselsRateLimitError, VesselsValidationError, WebhookInteractionResponsePayloadSchema, WebhookPayloadSchema, WebhookUserMessagePayloadSchema, WebhookVesselCreatedPayloadSchema };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vessels-sdk",
3
- "version": "0.6.0",
3
+ "version": "0.9.0",
4
4
  "description": "Let your agent reach you. Official Vessels SDK.",
5
5
  "type": "module",
6
6
  "exports": {