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>
2.4 KiB
calcomblock plugin
Standalone wasm Cal.com Booking plugin (reactor-mode wasip1, packed into a
.bnp and hot-loaded by the CMS). Registers the calcom:booking block plus a
chi HTTP handler mounted at /api/plugins/calcomblock/ (public booking + slots
- webhook endpoints, admin-gated settings/test/event-types). The block editor is
a Vite / Module-Federation bundle in
web/(exposed asremoteEntry.js), served host-side from the.bnpat/plugins/calcomblock/.
Extracted from the former bundled cms/backend/internal/plugins/calcomblock.
The old .so/Air/go:embed workflow is gone — see ~/src/blockninja/plugins/AGENTS.md
and the developing-blockninja-plugins skill for the current build/publish loop.
SDK boundary
Only git.dev.alexdunmow.com/block/core/... is importable — never block/cms/....
Two small things that used to come from cms/internal are vendored under
internal/ with provenance headers:
internal/helpers—GetRealIP,StartCleanupLoop,MaskSecret,GetStringOr, thePluginSettingsQueriersettings helpers, and aPluginCrypto(AES-256-GCM) used only by tests.internal/db— the minimalSetting/UpsertSettingParamsstructs the settings helpers reference.
Settings persistence (wasm sandbox)
Settings go through the SDK settings capabilities, NOT direct SQL: a plugin's
Postgres role is sandboxed to its own schema, so the CMS settings table
(public schema) is unreachable. capabilityQuerier (settings_store.go) adapts
settings.Settings / settings.Updater to the PluginSettingsQuerier
interface and is wired in NewCalcomRouter.
Known limitation
The server-authoritative captcha requirement (CalcomBookingRequiresCaptcha,
which scanned published page_block_snapshots) has no wasm-ABI capability
equivalent, so blockConfig is nil: an enabled booking block still enforces the
honeypot + per-IP rate limit, but the published-content captcha gate is not
re-derived server-side. Restoring it needs a core capability exposing
published-block content across the ABI.
Frontend
cd web && node node_modules/vite/bin/vite.js build # rebuild dist (pnpm's run-wrapper
# trips on ignored build scripts)
web/dist IS committed and packed into the .bnp; rebuild it before
ninja plugin build. @block-ninja/ui installs from the scoped Gitea registry
(^0.1.0), not a workspace link.