{"id":51916123,"url":"https://github.com/solspace/emdash-freeform","last_synced_at":"2026-07-27T11:01:02.851Z","repository":{"id":371363907,"uuid":"1238396440","full_name":"solspace/emdash-freeform","owner":"solspace","description":"Freeform for EmDash - a form building plugin.","archived":false,"fork":false,"pushed_at":"2026-07-14T16:31:55.000Z","size":5410,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-07-14T18:17:25.103Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/solspace.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-14T04:50:45.000Z","updated_at":"2026-07-14T16:28:55.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/solspace/emdash-freeform","commit_stats":null,"previous_names":["solspace/emdash-freeform"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/solspace/emdash-freeform","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solspace%2Femdash-freeform","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solspace%2Femdash-freeform/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solspace%2Femdash-freeform/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solspace%2Femdash-freeform/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/solspace","download_url":"https://codeload.github.com/solspace/emdash-freeform/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/solspace%2Femdash-freeform/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35949059,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-07-20T02:08:10.276Z","status":"online","status_checked_at":"2026-07-27T02:00:06.776Z","response_time":101,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-27T11:01:01.938Z","updated_at":"2026-07-27T11:01:02.823Z","avatar_url":"https://github.com/solspace.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Freeform for EmDash\n\nForm builder plugin for [EmDash CMS](https://emdashcms.com) — monorepo.\n\n**Manager / install guide:** [FREEFORM-REGISTRY-GUIDE.md](./FREEFORM-REGISTRY-GUIDE.md) — verify publish, install on a site, links.\n\n**Every day — two terminals:**\n\n```bash\n# 1 — demo site → http://localhost:4321/demo\ncd emdash-app \u0026\u0026 pnpm run dev:clean\n\n# 2 — plugin rebuild on save (optional)\ncd freeform \u0026\u0026 pnpm run build:watch\n```\n\n---\n\n## Repository layout\n\n```\nemdash-freeform/\n  freeform/               EmDash registry plugin\n  freeform-astro/         Astro integration + component library\n  emdash-freeform-mcp/    Standalone Cloudflare Worker MCP server\n  emdash-app/             Mars Rover Supply demo site (EmDash + Freeform consumer)\n  PLAN.md                 Phased product plan with progress tracking\n  LIMITATIONS.md          Known limitations and EmDash feature requests\n  FREEFORM-POC.md         Original POC handoff — architecture decisions and gotchas\n```\n\n---\n\n## Packages\n\n### `freeform` — EmDash plugin\n\nThe core plugin. Runs in EmDash's V8 sandbox (`format: \"standard\"`). Manages forms, submissions, email notifications, webhooks, spam scoring, and CSV exports via Block Kit admin UI and a full set of plugin routes.\n\n**Install** (for site owners): see [`freeform/README.md`](freeform/README.md#getting-started) — enable the registry in `astro.config.mjs`, install **freeform** from **Plugins → Registry**, then add **`@solspace/freeform-astro`** on the frontend.\n\n**Build locally:**\n```bash\ncd freeform\npnpm install\npnpm run build          # compile src/ → dist/\npnpm run bundle         # produces dist/freeform-x.x.x.tar.gz\n```\n\n**Development:** see [Daily dev — start here every time](#daily-dev--start-here-every-time) in Development setup.\n\n**Publish to registry:** see [Publishing](#publishing) (`pnpm dlx @emdash-cms/plugin-cli@0.5.1 login` must run outside the monorepo).\nSee [Publishing](#publishing) for CI via `freeform/v*` tags.\n\n---\n\n### `freeform-astro` — `@solspace/freeform-astro`\n\nAstro integration and component library. Injects 6 Freeform-specific routes into any Astro site and provides unstyled `FreeformForm` and `FreeformChat` components.\n\n**Install:**\n```bash\npnpm add @solspace/freeform-astro\n```\n\n**Usage:**\n```ts\n// astro.config.mjs\nimport freeformAstro from \"@solspace/freeform-astro\"\nexport default defineConfig({ integrations: [emdash(), freeformAstro()] })\n```\n\n```astro\n---\nimport { FreeformForm } from \"@solspace/freeform-astro/components\"\n---\n\u003cFreeformForm formId=\"contact\" /\u003e\n```\n\nComponents ship unstyled. Style them by targeting `data-freeform-*` attributes — see `emdash-app/src/pages/contact.astro` for a full dark-theme example.\n\n---\n\n### `emdash-freeform-mcp` — Cloudflare Worker MCP server\n\nStandalone Cloudflare Worker that exposes 25 MCP tools to AI agents (Claude Desktop, Cursor, etc.). Each customer deploys their own Worker instance pointed at their EmDash site.\n\n**Deploy:**\n```bash\ncd emdash-freeform-mcp\npnpm install\n# Edit wrangler.jsonc — set your Worker name and custom domain\nwrangler secret put EMDASH_SITE_URL\nwrangler deploy\n```\n\nSee `emdash-freeform-mcp/README.md` for full setup instructions including Claude Desktop config.\n\n---\n\n### `emdash-app` — Demo site\n\nMars Rover Supply — a demo EmDash site that consumes all three packages. Used for development and as a reference implementation.\n\nThe demo site is NOT published. It exists to validate the packages and demonstrate real-world usage.\n\n---\n\n## Development setup\n\n**Requirements:** Node.js ≥ 22.12, pnpm ≥ 11 (see root `package.json`).\n\n### First time (clone)\n\n```bash\ngit clone https://github.com/solspace/emdash-freeform\ncd emdash-freeform\npnpm install\n\n# Build the plugin once (required before the demo site can load Freeform)\ncd freeform \u0026\u0026 pnpm run build\n```\n\n### Daily dev — start here every time\n\nUse **two terminals** from the repo root.\n\n**Terminal 1 — demo site (keep running)**\n\n```bash\ncd emdash-app\npnpm run dev:clean\n```\n\n`dev:clean` builds the Freeform plugin first, clears Vite’s cache, and runs `npx emdash dev` (migrations + Astro on port **4321**). Wait until you see `astro … ready`, then open:\n\n| URL | What |\n|-----|------|\n| http://localhost:4321/demo | Freeform POC (contact form) |\n| http://localhost:4321/contact | Styled form example |\n| http://localhost:4321/_emdash/admin | EmDash admin → **Freeform** |\n\nOn the **first start** after a cache clear, the terminal may log one `emdash/middleware` optimize + `program reload` — that’s normal. If a page shows `Astro is not defined`, wait a few seconds and refresh once.\n\n**Terminal 2 — plugin watch (while editing `freeform/`)**\n\n```bash\ncd freeform\npnpm run build:watch\n```\n\nRebuilds `dist/` on save; refresh the browser or admin after changes.\n\n**If the dev server acts up** (wrong port, stale errors): stop all dev processes, then run `pnpm run dev:clean` again in `emdash-app`. Only one server should use port 4321.\n\n**Plain start** (no cache clear — use when yesterday’s dev session was fine):\n\n```bash\ncd emdash-app \u0026\u0026 npx emdash dev\n```\n\n---\n\n## Publishing\n\nReleases are tag-driven GitHub Actions workflows. Push a scoped tag and CI builds + publishes automatically.\n\n| Tag pattern | Package | Destination |\n|---|---|---|\n| `freeform/v*` | EmDash plugin | [Plugin registry](https://registry.emdashcms.com) |\n| `freeform-astro/v*` | `@solspace/freeform-astro` | [npm](https://www.npmjs.com/package/@solspace/freeform-astro) |\n\nSites install registry plugins with `experimental.registry: \"https://registry.emdashcms.com\"` in `astro.config.mjs`.\n\n### One-time setup (GitHub Actions secrets)\n\nIn the repo → **Settings** → **Secrets and variables** → **Actions**, add:\n\n| Secret | How to get it |\n|---|---|\n| `EMDASH_PLUGIN_OAUTH_SESSIONS` | After login (see below), copy the full contents of `~/.emdash/oauth/sessions.json`. CI also derives `~/.emdash/credentials.json` from this file (publish checks both). |\n| `NPM_TOKEN` | [npmjs.com](https://www.npmjs.com) → **Access Tokens** → granular token with **read/write** on `@solspace/*` |\n| `REGISTRY_TARBALL_URL` (optional) | Override the public tarball URL passed to `emdash-plugin publish`. By default CI publishes the tarball to npm as `@solspace/freeform-plugin-dist` and uses its unpkg URL (works with a private GitHub repo). |\n\nThe GitHub repo can stay **private** for source code — you do **not** need to make it public. Registry publish needs a **public HTTPS URL** for the tarball; CI mirrors each release to `@solspace/freeform-plugin-dist` on npm (same `NPM_TOKEN` as `freeform-astro`) and registers a jsDelivr/unpkg URL with the EmDash registry. CDNs can lag npm by a few minutes after first publish; re-run the workflow if that step times out. GitHub Releases are still created for your own archive. Override with `REGISTRY_TARBALL_URL` if you host the tarball elsewhere (R2, S3, etc.).\n\n### Release checklist\n\n1. **Bump the version** in the package you are shipping:\n   - Registry plugin: `freeform/package.json` **and** `freeform/src/index.ts` (`version` field)\n   - npm package: `freeform-astro/package.json`\n   - Update `freeform/CHANGELOG.md` when releasing the plugin\n   - Add or update `freeform-astro/README.md` when releasing the Astro package (npm displays this on the package page)\n\n2. **Commit and push** to `main` (merge `dev` → `main` first if needed).\n\n3. **Tag and push** (one tag per package, or both for a combined release):\n\n```bash\n# EmDash plugin registry\ngit tag freeform/v0.1.0\ngit push origin freeform/v0.1.0\n\n# npm Astro package\ngit tag freeform-astro/v0.1.1\ngit push origin freeform-astro/v0.1.1\n```\n\n4. Watch **Actions** in GitHub for the publish workflow result.\n\n5. Verify:\n   - Registry: `npx emdash-plugin search freeform` or EmDash admin → **Plugins** → **Registry**\n   - npm: `npm view @solspace/freeform-astro`\n\n### Re-running a failed registry publish\n\nIf bundle and GitHub Release succeeded but **Publish release record to registry** failed, re-run that job (or step) from **Actions** — you do not need a new tag.\n\nIf the workflow failed earlier (e.g. bundle), delete the tag and push it again on the fixed commit:\n\n```bash\ngit tag -d freeform-astro/v0.1.1\ngit push origin :refs/tags/freeform-astro/v0.1.1\ngit tag freeform-astro/v0.1.1\ngit push origin freeform-astro/v0.1.1\n```\n\nIf the version **already exists on npm or the registry**, bump the version — you cannot republish the same semver.\n\n### Publish locally (optional)\n\n**Registry plugin:**\n\nLog in **outside the monorepo** (workspace dependency hoisting breaks `emdash-plugin login` here):\n\n```bash\npnpm dlx @emdash-cms/plugin-cli@0.5.1 login solspace.com\ncat ~/.emdash/oauth/sessions.json   # → paste into EMDASH_PLUGIN_OAUTH_SESSIONS secret\n```\n\nThen bundle and publish:\n\n```bash\ncd freeform\npnpm run bundle\npnpm dlx @emdash-cms/plugin-cli@0.5.1 publish \\\n  --url https://your-host/freeform-x.y.z.tar.gz \\\n  --local dist/freeform-x.y.z.tar.gz\n```\n\n**npm package:**\n\n```bash\ncd freeform-astro\nnpm login   # first time\npnpm publish --access public --no-git-checks --dry-run   # test\npnpm publish --access public --no-git-checks             # publish\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolspace%2Femdash-freeform","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsolspace%2Femdash-freeform","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsolspace%2Femdash-freeform/lists"}