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>
141 lines
5.6 KiB
Go
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"`
|
|
}
|