{"id":50606362,"url":"https://github.com/helmcode/nan","last_synced_at":"2026-06-05T23:03:51.036Z","repository":{"id":360162129,"uuid":"1188264072","full_name":"helmcode/nan","owner":"helmcode","description":"NaN Community Landing","archived":false,"fork":false,"pushed_at":"2026-06-01T16:07:02.000Z","size":4262,"stargazers_count":0,"open_issues_count":4,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-01T18:06:44.408Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://nan.builders/","language":"Astro","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/helmcode.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-03-21T20:52:38.000Z","updated_at":"2026-06-01T16:21:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/helmcode/nan","commit_stats":null,"previous_names":["helmcode/nan"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/helmcode/nan","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/helmcode%2Fnan","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/helmcode%2Fnan/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/helmcode%2Fnan/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/helmcode%2Fnan/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/helmcode","download_url":"https://codeload.github.com/helmcode/nan/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/helmcode%2Fnan/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33963022,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-05T02:00:06.157Z","response_time":120,"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-06-05T23:03:50.332Z","updated_at":"2026-06-05T23:03:51.030Z","avatar_url":"https://github.com/helmcode.png","language":"Astro","funding_links":[],"categories":[],"sub_categories":[],"readme":"# NaN Website\n\nMarketing site and public documentation for [nan.builders](https://nan.builders). Built with Astro 6 (SSR mode) on Cloudflare Workers, Preact islands for interactive components, Tailwind CSS v4, and an ES/EN i18n catalog. The site backs into the `cloud-api` Go service for waitlist registration and community signup, and uses Resend for transactional email.\n\n## Tech stack\n\n- Astro 6 (`output: 'server'`, Cloudflare adapter)\n- Preact 10 for client-side islands\n- TypeScript (strict)\n- Tailwind CSS v4 (Vite plugin)\n- `rehype-pretty-code` + Shiki for code highlighting in docs\n- `astro-i18n` plus a local helper (`src/lib/i18n.ts`) for ES/EN strings\n- Vitest 4 for unit tests\n- Cloudflare Workers (assets binding + SSR entrypoint)\n- Resend for transactional email\n- Node.js `\u003e=22.12.0`, npm (lockfile is `package-lock.json`)\n\n## Architecture\n\nThe site is a single Astro app deployed as a Cloudflare Worker. The landing (`/`), the community page (`/community`), and the docs (`/docs/*`) are SSR-rendered at the edge. Two API routes (`/api/waitlist`, `/api/community-signup`) validate input, forward to the `cloud-api` backend, and trigger Resend confirmation email. Interactive bits (waitlist form, community signup form, FAQ accordion) are Preact islands hydrated with `client:load` / `client:visible`. Static assets are served from the `ASSETS` binding configured in `wrangler.jsonc`.\n\nSee [`ARCHITECTURE.md`](./ARCHITECTURE.md) for the full breakdown of rendering modes, route inventory, security model, and member lifecycle.\n\n## Project structure\n\n```\nwebsite/\n├── src/\n│   ├── pages/\n│   │   ├── index.astro              # Landing (SSR)\n│   │   ├── community.astro          # Community tier page (SSR)\n│   │   ├── api/\n│   │   │   ├── waitlist.ts          # POST — waitlist signup\n│   │   │   └── community-signup.ts  # POST — community tier signup\n│   │   └── docs/                    # SSR docs: index, getting-started, models,\n│   │                                #   examples, api, agents\n│   ├── components/\n│   │   ├── landing/                 # Hero, Pricing, WaitlistForm, FaqAccordion,\n│   │   │                            #   LanguageSwitcher, LoginButton, etc.\n│   │   ├── docs/                    # CodeBlock, RateLimits\n│   │   └── ui/                      # Button\n│   ├── layouts/                     # Base, Docs, Page\n│   ├── lib/                         # waitlist, communitySignup, email, i18n\n│   ├── styles/                      # Tailwind theme + global CSS\n│   ├── tests/                       # Vitest suites (api/, lib/)\n│   └── env.d.ts                     # Cloudflare env typings\n├── i18n/                            # en.json, es.json translation catalogs\n├── public/                          # Static assets, favicons, _routes.json\n├── .github/workflows/               # ci.yml, deploy.yml\n├── astro.config.mjs\n├── wrangler.jsonc\n├── vitest.config.ts\n├── tsconfig.json\n└── package.json\n```\n\n## Getting started\n\n### Prerequisites\n\n- Node.js `\u003e=22.12.0` (uses native `--env-file=` in scripts)\n- npm (the lockfile is `package-lock.json`; do not switch package managers)\n- Access to a `cloud-api` instance (default: `https://cloud-api.nan.builders`). Without `CLOUD_API_WAITLIST_KEY` the signup form will fail at the API call, but the site will still render fine for visual work.\n\n### Setup\n\n```bash\ngit clone \u003crepo\u003e\ncd website\nnpm install\ncp .env.example .env\n# fill in values (see \"Environment variables\" below)\nnpm run dev\n```\n\nThe dev server runs on `http://localhost:4321`.\n\n### Scripts\n\n| Script | Command | Description |\n|---|---|---|\n| `dev` | `astro dev` | Start the Astro dev server with HMR. |\n| `build` | `astro check --quiet \\|\\| true \u0026\u0026 astro build \u0026\u0026 cp public/_routes.json dist/client/` | Type-check (non-blocking), build for Cloudflare Workers, then copy the routing rules into `dist/client/`. |\n| `preview` | `astro preview` | Preview the production build locally. |\n| `astro` | `astro` | Run the Astro CLI passthrough. |\n| `generate-types` | `wrangler types` | Regenerate `worker-configuration.d.ts` from `wrangler.jsonc` (file is gitignored). |\n| `test` | `vitest run` | Run the full Vitest suite once. |\n| `test:watch` | `vitest` | Run Vitest in watch mode. |\n\n## Environment variables\n\nRuntime variables are declared in `src/env.d.ts` and consumed via `Astro.locals.runtime.env` (Cloudflare adapter). Local development reads them from `.env`; production values live in the Cloudflare dashboard (set with `wrangler secret put`).\n\n| Name | Required | Where it's used | Description |\n|---|---|---|---|\n| `RESEND_API_KEY` | runtime | `src/lib/email.ts` | Resend API key for transactional email (waitlist + community signup confirmation). |\n| `RESEND_FROM_EMAIL` | runtime | `src/lib/email.ts` | `From` address used by Resend. |\n| `CLOUD_API_URL` | runtime | `src/lib/waitlist.ts`, `src/lib/communitySignup.ts` | Base URL of the `cloud-api` backend (e.g. `https://cloud-api.nan.builders`). |\n| `CLOUD_API_WAITLIST_KEY` | runtime | `src/lib/waitlist.ts`, `src/lib/communitySignup.ts` | API key for the `cloud-api` waitlist/community registration endpoints. |\n\nAll four are listed (without values) in `.env.example`. You must fill them locally if you want the API routes to work end-to-end. None of these secrets should ever be committed.\n\n## Testing\n\n```bash\nnpm test         # run all Vitest suites\nnpm run test:watch\n```\n\nVitest config: [`vitest.config.ts`](./vitest.config.ts). Tests are picked up from `src/**/*.test.ts`. Current suites:\n\n- `src/tests/api/waitlist.test.ts`\n- `src/tests/api/community-signup.test.ts`\n- `src/tests/lib/waitlist.test.ts`\n- `src/tests/lib/email.test.ts`\n- `src/lib/communitySignup.test.ts`\n- `src/components/landing/waitlistForm.helpers.test.ts`\n\n## Build and local preview\n\n```bash\nnpm run build    # astro check (non-blocking) → astro build → copy _routes.json\nnpm run preview  # serve the production build locally\n```\n\n`astro check` is invoked with `--quiet` and `|| true` so type warnings do not fail the build; full type checking happens in CI via `npx astro check`.\n\n## Deployment\n\nThe site is deployed to Cloudflare Workers under the name `nan-website` (see `wrangler.jsonc`). Pushes to `main` trigger the `Deploy` workflow, which runs tests, builds, and then `npx wrangler deploy`. The production site is served at [https://nan.builders](https://nan.builders).\n\n`wrangler.jsonc` highlights:\n\n- `main: \"@astrojs/cloudflare/entrypoints/server\"` — Astro's Cloudflare SSR entrypoint.\n- `assets: { directory: \"./dist\", binding: \"ASSETS\" }` — static assets binding for the Worker.\n- `compatibility_date: \"2026-03-17\"` and `compatibility_flags: [\"global_fetch_strictly_public\"]` — outbound `fetch` is restricted to public addresses.\n- `observability.enabled: true` — Workers observability is on.\n\nAll runtime secrets must be set in the Cloudflare dashboard (or via `wrangler secret put`), not in the repository.\n\n## CI/CD\n\nTwo GitHub Actions workflows live in `.github/workflows/`:\n\n### `ci.yml` — `CI`\n\n- **Trigger:** `pull_request` to `main`.\n- **Job `build-and-test`** (Ubuntu, Node 22, npm cache):\n  1. `npm ci`\n  2. `npm test`\n  3. `npx astro check`\n  4. `npm run build`\n\n### `deploy.yml` — `Deploy`\n\n- **Trigger:** `push` to `main`.\n- **Job `deploy`** (Ubuntu, Node 22, npm cache, `deployments: write`):\n  1. `npm ci`\n  2. `npm test`\n  3. `npm run build`\n  4. `npx wrangler deploy`\n\nRequired repository secrets (consumed by `deploy.yml`):\n\n- `CLOUDFLARE_API_TOKEN`\n- `CLOUDFLARE_ACCOUNT_ID`\n\n## Internationalization\n\nThe site supports Spanish (`es`, default) and English (`en`).\n\n- Translation catalogs: [`i18n/es.json`](./i18n/es.json) and [`i18n/en.json`](./i18n/en.json).\n- Helpers: [`src/lib/i18n.ts`](./src/lib/i18n.ts) exports `t(key, locale)` for strings, `tArr` for arrays, `tObj` for nested objects, and `getLocale(URLSearchParams)` which reads the `?lang=` query param and defaults to `es`.\n- Locale switcher UI: [`src/components/landing/LanguageSwitcher.astro`](./src/components/landing/LanguageSwitcher.astro), embedded in `Base.astro` and on `/community`.\n\nTo add a new string, add the key (matching the dotted path used in `t(...)`) to both `i18n/es.json` and `i18n/en.json`, then reference it from the component with `t('your.key', locale)`. Both catalogs must stay in structural sync.\n\n## Contributing\n\n- Branch from `main` and open a PR.\n- Commit messages follow Conventional Commits (`feat(scope): ...`, `fix(scope): ...`, `docs(scope): ...`). Match the existing `git log` style.\n- CI must be green: `npm test`, `npx astro check`, and `npm run build` all pass.\n- For UI changes, run `npm run dev` and smoke-test the affected flows before requesting review.\n- Never commit secrets or any `.env` file.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhelmcode%2Fnan","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fhelmcode%2Fnan","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fhelmcode%2Fnan/lists"}