INNER CODE UNIT · TypeScript
times
rowboatlabs/rowboat · apps/harbor/packages/server/src/connectors/cal/index.ts:177
const times = Object.values(slots).flat().filter((s) => dateInZone(new Date(s.start), timeZone) === day);
if (times.length === 0) return `No open times for ${type.title} on ${day}.`;
const shown = times.slice(0, 24).map((s) => new Intl.DateTimeFormat('en-US', { hour: 'numeric', minute: '2-digit', timeZone }).format(new Date(s.start)));
return `**${type.title}** on ${day} (${timeZone}): ${shown.join(', ')}${times.length > 24 ? ', …' : ''}`;
},
},
{
name: 'book',
args: '<event type> <YYYY-MM-DDTHH:MM> <email> [name]',
summary: "book someone in (the time is in the key owner's time zone unless it names its own)",
async run(api, args) {
const [slug, when, email, ...name] = args.split(' ').filter(Boolean);
if (!slug || !when || !email) throw new UsageError('I need the event type, the time and the attendee’s email.');
if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email)) throw new UsageError(`"${email}" isn't an email address.`);
const { timeZone } = await api.profile();
const own = /(Z|[+-]\d{2}:?\d{2})$/i.test(when);
const start = own ? new Date(when) : zonedToUtc(when.length === 16 ? `${when}:00` : when, timeZone);
if (Number.isNaN(start.getTime())) throw new UsageError(`"${when}" isn't a time like 2026-10-05T15:00.`);