vessels 0.2.2 → 0.2.4
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.js +85 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -23,16 +23,39 @@ function writeConfig(config) {
|
|
|
23
23
|
if (!existsSync(CONFIG_DIR)) mkdirSync(CONFIG_DIR, { recursive: true });
|
|
24
24
|
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
25
25
|
}
|
|
26
|
-
function
|
|
27
|
-
|
|
26
|
+
function isTokenExpired(token) {
|
|
27
|
+
try {
|
|
28
|
+
const payload = JSON.parse(Buffer.from(token.split(".")[1], "base64url").toString());
|
|
29
|
+
return payload.exp * 1e3 < Date.now() + 6e4;
|
|
30
|
+
} catch {
|
|
31
|
+
return true;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function getFreshToken() {
|
|
35
|
+
const config = readConfig();
|
|
36
|
+
if (!config.access_token) return null;
|
|
37
|
+
if (!isTokenExpired(config.access_token)) return config.access_token;
|
|
38
|
+
if (config.refresh_token) {
|
|
39
|
+
try {
|
|
40
|
+
const supabase = createClient(SUPABASE_URL, SUPABASE_ANON_KEY);
|
|
41
|
+
const { data } = await supabase.auth.refreshSession({ refresh_token: config.refresh_token });
|
|
42
|
+
if (data.session) {
|
|
43
|
+
writeConfig({ ...config, access_token: data.session.access_token, refresh_token: data.session.refresh_token });
|
|
44
|
+
return data.session.access_token;
|
|
45
|
+
}
|
|
46
|
+
} catch {
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
28
50
|
}
|
|
29
51
|
async function api(path, options = {}) {
|
|
30
|
-
const token =
|
|
52
|
+
const token = await getFreshToken();
|
|
53
|
+
if (!token) throw new Error("Not logged in. Run: vessels login --email <email>");
|
|
31
54
|
const res = await fetch(`${BASE_URL}${path}`, {
|
|
32
55
|
...options,
|
|
33
56
|
headers: {
|
|
34
57
|
"Content-Type": "application/json",
|
|
35
|
-
|
|
58
|
+
Authorization: `Bearer ${token}`,
|
|
36
59
|
...options.headers ?? {}
|
|
37
60
|
}
|
|
38
61
|
});
|
|
@@ -184,6 +207,59 @@ async function cmdWebhooksToggle(id, active) {
|
|
|
184
207
|
});
|
|
185
208
|
console.log(`Webhook ${data.endpoint.id} ${data.endpoint.active ? "enabled" : "disabled"}.`);
|
|
186
209
|
}
|
|
210
|
+
var UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
211
|
+
async function resolveVesselId(input) {
|
|
212
|
+
if (UUID_RE.test(input)) return input;
|
|
213
|
+
const data = await api("/api/v1/vessels?limit=200&archived=true");
|
|
214
|
+
const vessel = (data.vessels ?? []).find((v) => v.external_id === input);
|
|
215
|
+
if (!vessel) {
|
|
216
|
+
console.error(`Vessel not found: ${input}`);
|
|
217
|
+
process.exit(1);
|
|
218
|
+
}
|
|
219
|
+
return vessel.id;
|
|
220
|
+
}
|
|
221
|
+
async function cmdMessage(args) {
|
|
222
|
+
const flags = parseFlags(args);
|
|
223
|
+
if (!flags.vessel || !flags.message) {
|
|
224
|
+
console.error("Usage: vessels message --vessel <id> --message <text>");
|
|
225
|
+
process.exit(1);
|
|
226
|
+
}
|
|
227
|
+
const vesselId = await resolveVesselId(flags.vessel);
|
|
228
|
+
const since = new Date(Date.now() - 5e3).toISOString();
|
|
229
|
+
const data = await api(`/api/v1/vessels/${vesselId}/messages`, {
|
|
230
|
+
method: "POST",
|
|
231
|
+
body: JSON.stringify({ message: flags.message })
|
|
232
|
+
});
|
|
233
|
+
console.log(`
|
|
234
|
+
Sent.`);
|
|
235
|
+
console.log(` vessel_id ${vesselId}`);
|
|
236
|
+
console.log(` message_id ${data.message_id}`);
|
|
237
|
+
const logsData = await api(`/api/v1/webhooks/deliveries?since=${encodeURIComponent(since)}&limit=10`);
|
|
238
|
+
const deliveries = logsData.deliveries ?? [];
|
|
239
|
+
if (!deliveries.length) {
|
|
240
|
+
console.log("\nNo webhook deliveries \u2014 add an endpoint at vessels-two.vercel.app/settings/webhooks");
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
console.log(`
|
|
244
|
+
Webhook deliveries (${deliveries.length}):
|
|
245
|
+
`);
|
|
246
|
+
for (const d of deliveries) {
|
|
247
|
+
const ok = d.response_status !== null && d.response_status >= 200 && d.response_status < 300;
|
|
248
|
+
const icon = ok ? "\u2713" : "\u2717";
|
|
249
|
+
const status = d.response_status ?? "no response";
|
|
250
|
+
const url = d.endpoint_url ?? "(deleted endpoint)";
|
|
251
|
+
const retry = d.attempt > 1 ? ` \xB7 attempt ${d.attempt}` : "";
|
|
252
|
+
const time = new Date(d.delivered_at).toLocaleTimeString([], { timeStyle: "medium" });
|
|
253
|
+
console.log(` ${icon} ${status} ${url}`);
|
|
254
|
+
console.log(` ${d.event_type}${retry} \xB7 ${time}`);
|
|
255
|
+
if (d.response_body) {
|
|
256
|
+
const body = d.response_body.length > 300 ? d.response_body.slice(0, 300) + "\u2026" : d.response_body;
|
|
257
|
+
console.log(`
|
|
258
|
+
${body.split("\n").join("\n ")}`);
|
|
259
|
+
}
|
|
260
|
+
console.log();
|
|
261
|
+
}
|
|
262
|
+
}
|
|
187
263
|
async function cmdPush(args) {
|
|
188
264
|
const flags = parseFlags(args);
|
|
189
265
|
const apiKey = flags.key ?? process.env.VESSELS_API_KEY;
|
|
@@ -233,6 +309,10 @@ Commands:
|
|
|
233
309
|
vessels push --vessel <id> --message <text> --key <api_key>
|
|
234
310
|
(--key can be omitted if VESSELS_API_KEY is set)
|
|
235
311
|
|
|
312
|
+
vessels message --vessel <id> --message <text>
|
|
313
|
+
Send a message as the logged-in user and print webhook delivery logs.
|
|
314
|
+
Accepts vessel UUID or external_id (e.g. booking-123).
|
|
315
|
+
|
|
236
316
|
Agent/Claude Code setup (fully non-interactive):
|
|
237
317
|
vessels login --email me@example.com
|
|
238
318
|
# tell your agent the OTP from the email
|
|
@@ -291,6 +371,7 @@ Run: vessels help`);
|
|
|
291
371
|
process.exit(1);
|
|
292
372
|
}
|
|
293
373
|
if (cmd === "push") return cmdPush([sub, ...rest].filter(Boolean));
|
|
374
|
+
if (cmd === "message") return cmdMessage([sub, ...rest].filter(Boolean));
|
|
294
375
|
console.error(`Unknown command: ${cmd}
|
|
295
376
|
Run: vessels help`);
|
|
296
377
|
process.exit(1);
|