calcomblock/types.go
Alex Dunmow 18b7825592 Extract calcomblock into a standalone wasm plugin repo
Convert the bundled backend/internal/plugins/calcomblock package into a
standalone reactor-mode wasm plugin, dropping every git.dev.alexdunmow.com/block/cms
import (forbidden in standalone plugins):

- package calcomblock -> package main; add wasip1 main.go with
  wasmguest.Serve(Registration). go.mod module
  git.dev.alexdunmow.com/block/calcomblock, block/core v0.18.2, no replace
  directives.
- Settings persistence: replace the pool-backed poolQuerier (direct SQL against
  the public-schema `settings` table, which a sandboxed plugin role cannot read)
  with capabilityQuerier over the SDK settings.Settings / settings.Updater
  capabilities. GetSiteTimezone now resolves via GetSiteSettings host-side.
- Vendor the small CMS-internal helpers the plugin used into internal/helpers
  (GetRealIP, StartCleanupLoop, MaskSecret, GetStringOr, the PluginSettingsQuerier
  settings helpers, PluginCrypto for tests) and internal/db (minimal Setting /
  UpsertSettingParams), each with a provenance header.
- Inline the captcha widget: vendor blocks.CaptchaWidget as a local
  CaptchaWidget templ (captcha_widget.templ) and regenerate templ; drop the
  block/cms/blocks import from booking.templ.
- blockConfig (server-authoritative captcha requirement via a
  page_block_snapshots scan) has no wasm-ABI capability, so it is left nil:
  honeypot + per-IP rate limit still apply. Documented as a follow-up.
- web: @block-ninja/ui workspace:* -> ^0.1.0 registry version; eslint.config.js
  repointed at ../../../cms/web/eslint.config.js; rebuild web/dist.
- Rewrite CLAUDE.md for the standalone wasm reality; add .gitignore.

Full test suite preserved and passing; builds to calcomblock-2.0.0.bnp;
check-safety passes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-05 03:04:18 +08:00

141 lines
5.6 KiB
Go

package main
// TimeSlot represents an available booking time slot
type TimeSlot struct {
Start string // ISO 8601 timestamp
End string // ISO 8601 timestamp
DisplayTime string // Human-readable time, e.g., "10:00 AM"
DateKey string // Date key from Cal.com API response
}
// SlotConfig holds configuration for rendering time slots
type SlotConfig struct {
BlockID string
Username string
EventType string
SelectedDate string // YYYY-MM-DD format
}
// FormConfig holds configuration for the booking form
type FormConfig struct {
BlockID string
Username string
EventType string
SelectedDate string // Human-readable date
SelectedTime string // Human-readable time
StartTime string // ISO 8601 timestamp for the booking
TimeZone string // IANA timezone of the event's availability schedule
BookingFields []BookingField
// DefaultCountryCode is the ISO alpha-2 region pre-selected in the phone
// country combobox, inferred from the visitor's timezone/locale. "" = none.
DefaultCountryCode string
// CaptchaEnabled renders the shared Cap proof-of-work widget in the confirm
// step. Server-authoritative: resolved from the block's stored captchaEnabled
// flag by blockId (HandleGetForm), the same source HandleCreateBooking
// enforces against — a bot cannot influence it.
CaptchaEnabled bool
}
// BookingResult holds the result of a successful booking
type BookingResult struct {
Success bool
BookingID string // Cal.com booking UID
FormattedDateTime string // e.g., "Monday, January 15, 2025 at 10:00 AM"
Email string
MeetingLink string // Join URL from the booking's `location` (video events only)
}
// BookingField is a single field configured on a Cal.com event type.
// Mirrors the Cal.com v2 event-type `bookingFields` array.
//
// Cal.com's v2 API (cal-api-version 2024-06-14) keys the field identifier as
// `slug`, NOT `name`, and returns an empty `label` for default/system fields
// (its own booker derives the visible label client-side via i18n). It also
// marks some system fields `hidden:true`. The raw decode therefore leaves
// Name/Label empty for the common case; GetEventType runs normalizeBookingFields
// to resolve Name (from Slug) and Label (from the system-field map) and to drop
// hidden fields before the form template ever sees them.
type BookingField struct {
Name string `json:"name"` // legacy/custom key; Slug is the v2 canonical identifier
Slug string `json:"slug"`
Label string `json:"label"`
Type string `json:"type"` // name|email|phone|text|textarea|number|boolean|select|multiselect|radio|checkbox
Required bool `json:"required"`
Hidden bool `json:"hidden"`
Placeholder string `json:"placeholder,omitempty"`
DefaultValue string `json:"defaultValue,omitempty"`
Options []BookingFieldOption `json:"options,omitempty"`
// Editable mirrors Cal.com's system/custom classification: "system",
// "system-but-optional", "system-but-hidden", "user", "user-readonly".
// Used to drop system-but-hidden fields before they reach the form.
Editable string `json:"editable,omitempty"`
// Views restricts a field to specific booker flows. rescheduleReason carries
// views:[{id:"reschedule"}] — i.e. it must render only when rescheduling,
// never on a new booking (see Cal.com getBookingFields.ts).
Views []BookingFieldView `json:"views,omitempty"`
}
// BookingFieldOption is a single choice for a select/radio/checkbox field.
type BookingFieldOption struct {
Label string `json:"label"`
Value string `json:"value"`
}
// BookingFieldView mirrors a Cal.com bookingField `views` entry. A non-empty
// views array scopes a field to particular booker flows (e.g. reschedule).
type BookingFieldView struct {
ID string `json:"id"`
Label string `json:"label,omitempty"`
}
// EventTypeSummary is a compact projection used to populate the editor dropdown.
type EventTypeSummary struct {
ID int64 `json:"id"`
Slug string `json:"slug"`
Title string `json:"title"`
LengthInMinutes int `json:"lengthInMinutes"`
}
// EventType is the full event-type record including its booking fields.
type EventType struct {
EventTypeSummary
BookingFields []BookingField `json:"bookingFields"`
// ScheduleID is the availability schedule backing this event type. nil
// means "the host's default schedule" — resolve via Schedule.IsDefault.
ScheduleID *int64 `json:"scheduleId"`
}
// Schedule is a Cal.com availability schedule. Its TimeZone is the meeting's
// timezone: the zone the host configured their availability in, and the zone
// all booking times are displayed in (the visitor's browser zone is ignored
// by design — see eventLocation in handler.go).
type Schedule struct {
ID int64 `json:"id"`
Name string `json:"name"`
TimeZone string `json:"timeZone"`
IsDefault bool `json:"isDefault"`
}
// WebhookPayload is the inner `payload` object of a Cal.com webhook event.
type WebhookPayload struct {
UID string `json:"uid"`
StartTime string `json:"startTime"`
EndTime string `json:"endTime"`
EventType struct {
Title string `json:"title"`
Slug string `json:"slug"`
} `json:"eventType"`
Attendees []struct {
Name string `json:"name"`
Email string `json:"email"`
TimeZone string `json:"timeZone"`
} `json:"attendees"`
}
// WebhookEvent is the top-level Cal.com webhook envelope.
type WebhookEvent struct {
TriggerEvent string `json:"triggerEvent"`
CreatedAt string `json:"createdAt"`
Payload WebhookPayload `json:"payload"`
}