Skip to content

Package reference

The framework is distributed as six packages under the @drawnagency npm scope. All are published as ESM with declaration files. The build toolchain (tsup and typescript) is declared only in the root devDependencies — by design, so packages can build via pnpm’s workspace hoisting without each declaring the toolchain separately.

Each package’s build script runs:

Terminal window
tsup && rm -f tsconfig.tsbuildinfo && tsc --emitDeclarationOnly

tsup produces the Node-compatible ESM bundle with correct .js extensions; tsc --emitDeclarationOnly writes .d.ts files alongside it.


Purpose: The shared foundation. Contains the section registry, defineSection helper, all Zod schemas, shared React components (editor UI, viewer section shells), auth types, media types, and utility libraries. Every other package depends on this one.

Internal deps: None.

Key exports:

Entry pathContents
. (root)defineSection, registerSection, registerSchema, getAllSections, getAllSchemas, SectionDefinition, auth types, AuthProvider, Session, Audience, media types
./lib/registryFull registry API: createRegistry, registerSection, registerSchema, registerRichText, getSection, getSchema, getAllSections, getAllSchemas, clearRegistry
./schemasBarrel for all Zod schemas
./schemas/authAudience, Session, auth Zod schemas
./schemas/blockBlock/content Zod schemas
./schemas/linkLinkValue and link Zod schema
./lib/dexieDexie-based in-memory edit store
./lib/envenv() helper (with guarded process.env fallback)
./lib/platform-brokerPlatform API client
./lib/registryRegistry module (see above)
./components/sections/register-schemasensureSchemasRegistered() — registers all built-in schemas
./components/sections/brand-guidebrandGuideSectionDefs array + color schema exports
./components/editorEditor React components
./components/primitivesShared primitive React components
./authAuth helper exports
./mediaMedia helper exports

The package ships both dist/ (compiled) and src/ (source). The Astro integration aliases all primitives import paths to src/ during dev and SSR builds — see SSR / Netlify gotchas.


Purpose: The Cloudflare R2 storage adapter — the optional bucket half of the storage model (videos, large documents). Ships a dependency-free SigV4 signer, so it pulls in no AWS SDK. Imported by the template’s default portal.config.mjs.

Internal deps: @drawnagency/primitives (workspace:^) — for the AssetStore / DocumentStore interfaces.

Key exports:

Entry pathContents
. (root)r2Assets()AssetStore, r2Documents()DocumentStore

Standalone (“.env”) mode reads R2_ACCOUNT_ID, R2_BUCKET, the access key pair and PORTAL_SITE_ID; platform mode goes through the broker instead. A portal may have no bucket at all — GitHub-backed media works without one, so never assume these are configured. See the storage-model notes in the SSR / Netlify rules.


Purpose: CLI tooling and Claude skills for populating client sites. Provides the authoring binary (used via pnpm exec authoring) with subcommands validate, process-images and upload-video. Also ships the /populate-site skill into client repos via postinstall.

Internal deps: @drawnagency/primitives (workspace:^), @drawnagency/assets-r2 (workspace:^ — the R2 signer behind upload-video).

Key exports:

Entry pathContents
. (root)Public API for authoring utilities
bin/authoringCLI binary: validate --project <path>, process-images --project <path>, upload-video <file> --project <path> --width <n> --height <n>

files in package.json includes dist/, skills/, and scripts/. The skills/ directory contains the /populate-site skill; scripts/link-skills.mjs is run by client repos’ postinstall to symlink it into .claude/skills/.


Purpose: GitHub storage adapter. Handles reading and writing content files and media to a GitHub repository via the GitHub REST API (@octokit/rest). Exports githubStorage(), the StorageProvider implementation used in portal.config.mjs.

Internal deps: @drawnagency/primitives (workspace:^).

Key exports:

Entry pathContents
. (root)githubStorage() — returns a StorageProvider

Purpose: Supabase auth adapter. Wraps @supabase/supabase-js and @supabase/ssr to implement the AuthProvider interface from @drawnagency/primitives. Handles OAuth sign-in, session cookies, audience management, and invite flows.

Internal deps: @drawnagency/primitives (workspace:^).

Key exports:

Entry pathContents
. (root)supabaseAuth() — returns an AuthProvider; createSupabaseAuth() for advanced use

Purpose: The Astro integration and all server-side page/API routes. Injects viewer and editor routes, middleware, API endpoints, and the Vite plugin configuration into the client Astro project. Also exports the defineConfig helper and the password-only auth adapter.

Internal deps: @drawnagency/primitives (workspace:^), @drawnagency/github (workspace:^).

Key exports:

Entry pathContents
. (root)The Astro integration (default export); do not import this in browser code — it pulls in node:url, node:fs, etc.
./configdefineConfig() helper — import this in portal.config.mjs
./passwordcreatePasswordAuth() — the password-only auth adapter
./styles/base.cssBase Tailwind CSS; client repos @import this from their own src/styles/base.css

The ./config and ./password entry points resolve to src/ files directly (not dist/) so they can be used in contexts where dist/ may not have been built (e.g. apps/admin uses only import type from core; portal.config.mjs must import defineConfig from ./config specifically).


@drawnagency/platform (private — not published)

Section titled “@drawnagency/platform (private — not published)”

Purpose: The platform-side provisioning and access core shared by apps/admin and apps/mcp. Contains provisionSite/teardownSite, the GitHub App/Netlify/Cloudflare provider clients, the service-role Supabase admin client, and checkPlatformAccess (the platform_users/allowed_signups gate).

Internal deps: @drawnagency/primitivesimport type only (no runtime import, so no primitives dist/ is required by consumers).

Key difference from the published six: every export points at ./src/*.ts — there is no build step and no dist/. apps/admin bundles it from source via vite.ssr.noExternal (its Netlify build runs without build:packages); apps/mcp bundles it with esbuild. CI’s check-admin-isolation gate fails the build if this package ever grows a dist-pointing export. It is excluded from scripts/publish.sh and has no build script, so “build all six packages” remains literally six.