Skip to content

The packages

The framework is split into six npm packages, all published under the @drawnagency scope. Client repos depend on whichever packages they need — typically all six. A seventh workspace package, @drawnagency/platform, is private (never published): it holds the platform-side provisioning core consumed only by apps/admin and apps/mcp, and is documented at the end of this page.

primitives (leaf — no internal deps)
├── assets-r2 (depends on primitives)
├── authoring (depends on primitives + assets-r2)
├── github (depends on primitives)
├── auth-supabase (depends on primitives)
└── core (depends on primitives + github)
platform (private, unpublished — type-only dep on primitives)

Publish order follows this graph: primitives → assets-r2 → authoring → github → auth-supabase → core. assets-r2 precedes authoring because authoring’s upload-video imports the R2 signer from it — the order in scripts/publish.sh is the source of truth. Use bash scripts/publish.sh from the monorepo root — never publish packages manually.

The shared foundation. Contains:

  • Zod schemas for all section types, index.json, site-config.json, and image manifest.
  • Section component registrydefineSection(), registerSection(), getSectionSchema(), and the Symbol.for-keyed singleton registry.
  • React section components — the rendered UI for every built-in section type.
  • mergeSiteContent() and loadStaticSiteContent() — the core content assembly functions.
  • Auth capability helpersderiveUiCapabilities() and related types.

No internal @drawnagency/* dependencies. Safe to import on its own.

The Cloudflare R2 storage adapter — the bucket half of the storage model. Contains:

  • r2Assets() — returns an AssetStore backed by an R2 bucket, used for videos and other bucket-hosted assets.
  • r2Documents() — returns a DocumentStore for bucket-tier documents (large PDFs), sharing the same credentials.
  • A dependency-free SigV4 signer for presigned PUT/DELETE URLs.

The template’s default portal.config.mjs imports both. The bucket is optional: a portal can run with no bucket configured at all and still do GitHub-backed media — see Storage model. Depends on @drawnagency/primitives for the AssetStore/DocumentStore interfaces.

The content-population toolchain. Contains:

  • The authoring CLI (validate, process-images, upload-video subcommands).
  • The /populate-site Claude skill, linked into client repos via postinstalllink-skills.mjs.
  • Image processing pipeline (download → WebP conversion → manifest update).

Depends on @drawnagency/primitives for schema validation during validate, and on @drawnagency/assets-r2 for the upload-video subcommand’s presigned uploads.

The GitHub storage client. Contains:

  • createGitHubClientAsync() — instantiates an Octokit client authenticated as the GitHub App installation.
  • Helpers for reading/writing files, listing branches, and getting commit SHAs from a client repo.
  • owner, repo, branch constants resolved from environment variables.

Depends on @drawnagency/primitives.

The Supabase authentication adapter. Contains:

  • supabaseAuth() — returns an AuthProvider implementation backed by Supabase Auth.
  • Session resolution, audience CRUD, user management, and password-auth toggle — all routed through Supabase.
  • OAuth PKCE flow helpers.

Depends on @drawnagency/primitives for the AuthProvider interface and shared types.

The Astro integration and everything that ties the framework together. Contains:

  • defineConfig() (from @drawnagency/core/config) / portalIntegration() — the Astro integration that registers routes, sets up noExternal, creates .portal/ symlinks for dev mode, and wires virtual:portal/* modules.
  • Astro pages: viewer index, /edit, auth API routes, media API route.
  • packages/core/src/middleware.ts — the dual-path auth gate.
  • loadContentFromGitHub() and loadMediaManifestFromGitHub() — GitHub-backed loaders built on @drawnagency/primitivesmergeSiteContent().
  • Password-only auth adapter (lib/password.ts) as an alternative to Supabase.

Depends on @drawnagency/primitives and @drawnagency/github.

The platform-side core — not published to npm and never installed by client repos. Contains:

  • provisionSite() / teardownSite() — the site lifecycle orchestration (GitHub repo from template, Netlify site, Cloudflare DNS, Supabase records, env vars, webhooks).
  • Provider clients for the GitHub App (installation tokens), Netlify, and Cloudflare APIs, plus the service-role Supabase admin client.
  • checkPlatformAccess() — the shared platform identity gate (platform_users/allowed_signups) used by both the admin middleware and the MCP connector’s OAuth callback.

It exports source (./src/*.ts, no dist/) so apps/admin can bundle it without a package build step, and imports @drawnagency/primitives as import type only. Consumed by apps/admin and apps/mcp.

All packages use 0.1.x versions. Client repos reference them with ^0.1.0 ranges, which under semver 0.x rules means >=0.1.0 <0.2.0. Bumping to 0.2.0 in any package requires client repos to explicitly widen their range.

Workspace dependencies in the monorepo use workspace:* (or workspace:^). pnpm publish resolves these to real version numbers at publish time — npm publish does not and will break consumer installs silently.