← All @molecule/* packages · App templates
@molecule/api-resource-meetingAPI resource · resource-meeting · API (Node) · v1.0.1 · Apache-2.0
Meeting records + action items
npm install @molecule/api-resource-meeting@molecule/api-resource-meeting is an API resource: the routes, validation and storage for resource-meeting, built on the database and auth cores so it runs on whichever providers your app has bonded.
import { createMeetingRouter } from '@molecule/api-resource-meeting'
app.use('/meetings', createMeetingRouter())
// GET|POST / · GET|PUT|DELETE /:id
// GET|POST /:id/action-items · PUT|DELETE /:id/action-items/:itemIdWorks with: @molecule/api-bonds-default-express, @molecule/api-database, @molecule/api-i18n, @molecule/api-middleware-validation
Auto-generated, AI-first package reference for the molecule.dev ecosystem. It is written to be read by coding agents as much as by people, and is generated from this package's source — edit
src/index.tsJSDoc, not this file.
@molecule/api-resource-meeting — meeting CRUD + action items.
Tracks scheduled/in_progress/completed/cancelled meetings with attendees, optional recording URL, transcript, and AI-friendly summary slot. Action items nest under meetings and track completion + assignee + due date + source excerpt.
Extracted from the ai-meeting-notes flagship.
import { createMeetingRouter } from '@molecule/api-resource-meeting'
app.use('/meetings', createMeetingRouter())
// GET|POST / · GET|PUT|DELETE /:id
// GET|POST /:id/action-items · PUT|DELETE /:id/action-items/:itemId
import { createActionItem, createMeetingForOwner } from '@molecule/api-resource-meeting'
const meeting = await createMeetingForOwner(userId, {
title: 'Sprint planning',
scheduled_at: '2026-08-01T10:00:00Z',
})
await createActionItem(meeting.id, userId, { description: 'Send recap' })
resource
npm install @molecule/api-resource-meeting @molecule/api-bonds-default-express @molecule/api-database @molecule/api-i18n @molecule/api-middleware-validation express zod
npm install -D @types/express
ActionItemRowRaw database row shape for an action item linked to a meeting.
interface ActionItemRow {
id: string
meeting_id: string
description: string
assignee: string | null
due_date: string | Date | null
is_completed: boolean
source_excerpt: string | null
created_at: string | Date
updated_at: string | Date
}
MeetingRowRaw database row shape for a meeting record.
interface MeetingRow {
id: string
owner_id: string
title: string
description: string | null
status: MeetingStatus
scheduled_at: string | Date | null
started_at: string | Date | null
ended_at: string | Date | null
duration_seconds: number
recording_url: string | null
transcript: string | null
summary: string | null
attendees: Array<{ name: string; email?: string }>
created_at: string | Date
updated_at: string | Date
}
MeetingStatusLifecycle states a meeting can occupy from creation through completion.
type MeetingStatus = 'scheduled' | 'in_progress' | 'completed' | 'cancelled'
createActionItem(meetingId, ownerId, data)Creates a new action item under a meeting owned by the given owner; returns the inserted row or null if the meeting is not found/owned.
function createActionItem(
meetingId: string,
ownerId: string,
data: {
description: string
assignee?: string | null
due_date?: string | null
source_excerpt?: string | null
},
): Promise<ActionItemRow | null>
createMeetingForOwner(ownerId, data)Creates a new meeting record owned by the given owner and returns the inserted row.
function createMeetingForOwner(
ownerId: string,
data: {
title: string
description?: string | null
scheduled_at?: string | null
attendees?: Array<{ name: string; email?: string }>
},
): Promise<MeetingRow>
createMeetingRouter()Creates and returns an Express Router with all meeting and action-item CRUD routes.
function createMeetingRouter(): Router
deleteActionItem(itemId, meetingId, ownerId)Deletes an action item by ID if its parent meeting belongs to the given owner; returns true on success, false if not found or not owned.
function deleteActionItem(itemId: string, meetingId: string, ownerId: string): Promise<boolean>
deleteMeetingForOwner(meetingId, ownerId)Deletes a meeting by ID if it belongs to the given owner; returns true on success, false if not found or not owned.
function deleteMeetingForOwner(meetingId: string, ownerId: string): Promise<boolean>
getMeetingForOwner(meetingId, ownerId)Fetches a single meeting by ID, returning null if it does not exist or does not belong to the owner.
function getMeetingForOwner(meetingId: string, ownerId: string): Promise<MeetingRow | null>
listActionItems(meetingId, ownerId)Returns all action items for a meeting in creation order, or null if the meeting is not found/owned.
function listActionItems(meetingId: string, ownerId: string): Promise<ActionItemRow[] | null>
listMeetingsForOwner(ownerId, opts?)Returns a paginated list of meetings belonging to the given owner, optionally filtered by status.
function listMeetingsForOwner(
ownerId: string,
opts?: { status?: MeetingStatus; page?: number; limit?: number },
): Promise<{ data: MeetingRow[]; total: number }>
updateActionItem(itemId, meetingId, ownerId, patch)Applies a partial patch to an action item; returns the updated row or null if the meeting or item is not found/owned.
function updateActionItem(
itemId: string,
meetingId: string,
ownerId: string,
patch: Partial<ActionItemRow>,
): Promise<ActionItemRow | null>
updateMeetingForOwner(meetingId, ownerId, patch)Applies a partial patch to a meeting, recomputing duration_seconds when both timestamps are present, and returns the updated row or null if not found/owned.
function updateMeetingForOwner(
meetingId: string,
ownerId: string,
patch: Partial<MeetingRow>,
): Promise<MeetingRow | null>
actionItemCreateSchemaZod schema for validating action item creation payloads.
const actionItemCreateSchema: z.ZodObject<
{
description: z.ZodString
assignee: z.ZodOptional<z.ZodNullable<z.ZodString>>
due_date: z.ZodOptional<z.ZodNullable<z.ZodString>>
source_excerpt: z.ZodOptional<z.ZodNullable<z.ZodString>>
},
z.core.$strip
>
actionItemUpdateSchemaZod schema for validating action item update payloads.
const actionItemUpdateSchema: z.ZodObject<
{
description: z.ZodOptional<z.ZodString>
assignee: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>
due_date: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>
source_excerpt: z.ZodOptional<z.ZodOptional<z.ZodNullable<z.ZodString>>>
is_completed: z.ZodOptional<z.ZodBoolean>
},
z.core.$strip
>
MEETING_STATUSESAll valid status values a meeting can be in.
const MEETING_STATUSES: readonly ['scheduled', 'in_progress', 'completed', 'cancelled']
meetingCreateSchemaZod schema for validating meeting creation payloads.
const meetingCreateSchema: z.ZodObject<
{
title: z.ZodString
description: z.ZodOptional<z.ZodNullable<z.ZodString>>
scheduled_at: z.ZodOptional<z.ZodNullable<z.ZodString>>
attendees: z.ZodOptional<
z.ZodArray<
z.ZodObject<{ name: z.ZodString; email: z.ZodOptional<z.ZodString> }, z.core.$strip>
>
>
},
z.core.$strip
>
meetingUpdateSchemaZod schema for validating meeting update payloads.
const meetingUpdateSchema: z.ZodObject<
{
title: z.ZodOptional<z.ZodString>
description: z.ZodOptional<z.ZodNullable<z.ZodString>>
status: z.ZodOptional<
z.ZodEnum<{
scheduled: 'scheduled'
in_progress: 'in_progress'
completed: 'completed'
cancelled: 'cancelled'
}>
>
scheduled_at: z.ZodOptional<z.ZodNullable<z.ZodString>>
started_at: z.ZodOptional<z.ZodNullable<z.ZodString>>
ended_at: z.ZodOptional<z.ZodNullable<z.ZodString>>
recording_url: z.ZodOptional<z.ZodNullable<z.ZodString>>
transcript: z.ZodOptional<z.ZodNullable<z.ZodString>>
summary: z.ZodOptional<z.ZodNullable<z.ZodString>>
attendees: z.ZodOptional<
z.ZodArray<
z.ZodObject<{ name: z.ZodString; email: z.ZodOptional<z.ZodString> }, z.core.$strip>
>
>
},
z.core.$strip
>
Peer dependencies:
@molecule/api-bonds-default-express ^1.0.1@molecule/api-database ^1.0.1@molecule/api-i18n ^1.0.1@molecule/api-middleware-validation ^1.0.1express ^5.0.0zod ^4.0.0@molecule/api-bonds-default-express@molecule/api-database@molecule/api-i18n@molecule/api-middleware-validationexpresszodTables: src/__setup__/meetings.sql creates meetings +
meeting_action_items. An mlcl-scaffolded API replays __setup__/*.sql
automatically on migrate; anywhere else run it once — nothing at runtime
creates them.
The router does not authenticate — it reads the caller from
res.locals.session (populated by your global auth middleware) and 401s
without a session. All service functions are owner-scoped
(…ForOwner(…, ownerId) / (meetingId, ownerId, …)) and return null
for rows the caller doesn't own — always pass the AUTHENTICATED user's id.