diff --git a/.github/workflows/www.yaml b/.github/workflows/www.yaml index ee93cf00e..d4abfddaf 100644 --- a/.github/workflows/www.yaml +++ b/.github/workflows/www.yaml @@ -10,6 +10,10 @@ on: permissions: contents: read +env: + # name of the netlify site, used to predict the url of a preview deploy + NETLIFY_SITE_NAME: effection + jobs: deploy-preview: if: github.event_name == 'pull_request' @@ -17,7 +21,8 @@ jobs: timeout-minutes: 15 environment: name: Preview - url: ${{ steps.netlify.outputs.unique-url }} + # the alias deploy, the one this build's urls were written for + url: ${{ steps.netlify.outputs.stable-url }} permissions: contents: read pull-requests: write @@ -33,6 +38,23 @@ jobs: with: deno-version: v2.9.1 + - name: Compute Site URL + id: site + env: + IS_FORK: ${{ github.event.pull_request.head.repo.full_name != github.repository }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + # an alias deploy lands on a predictable url, so a preview can point + # at itself. a fork deploys anonymously to a url that is not known + # until after the deploy, so it points at the netlify site instead. + if [[ "$IS_FORK" == "true" ]]; then + URL="https://${NETLIFY_SITE_NAME}.netlify.app" + else + URL="https://pr-${PR_NUMBER}--${NETLIFY_SITE_NAME}.netlify.app" + fi + echo "url=$URL" >> "$GITHUB_OUTPUT" + echo "Preview will be served from $URL" >> "$GITHUB_STEP_SUMMARY" + - name: Serve Website run: | deno run -A main.tsx & @@ -48,7 +70,7 @@ jobs: - name: Download Staticalize run: | - wget https://github.com/thefrontside/staticalize/releases/download/v0.2.6/staticalize-linux.tar.gz \ + wget https://github.com/thefrontside/staticalize/releases/download/v0.3.0/staticalize-linux.tar.gz \ -O /tmp/staticalize-linux.tar.gz tar -xzf /tmp/staticalize-linux.tar.gz -C /usr/local/bin chmod +x /usr/local/bin/staticalize-linux @@ -58,7 +80,9 @@ jobs: staticalize-linux \ --site=http://127.0.0.1:8000 \ --output=www/built \ - --base=https://effection.netlify.app + --base=${{ steps.site.outputs.url }} \ + --concurrency=75 \ + --retries=3 - name: Deploy Preview to Netlify id: netlify @@ -90,6 +114,11 @@ jobs: DEPLOY_ID=$(echo "$DEPLOY_OUTPUT" | jq -er '.deploy_id') SITE_NAME=$(echo "$DEPLOY_OUTPUT" | jq -er '.site_name') + + if [[ "$SITE_NAME" != "$NETLIFY_SITE_NAME" ]]; then + echo "::warning::deployed to '$SITE_NAME' but urls were built for" \ + "'$NETLIFY_SITE_NAME'; update NETLIFY_SITE_NAME in this workflow" + fi UNIQUE_URL="https://${DEPLOY_ID}--${SITE_NAME}.netlify.app" STABLE_URL="https://pr-${PR_NUMBER}--${SITE_NAME}.netlify.app" fi @@ -144,7 +173,7 @@ jobs: - name: Download Staticalize run: | - wget https://github.com/thefrontside/staticalize/releases/download/v0.2.6/staticalize-linux.tar.gz \ + wget https://github.com/thefrontside/staticalize/releases/download/v0.3.0/staticalize-linux.tar.gz \ -O /tmp/staticalize-linux.tar.gz tar -xzf /tmp/staticalize-linux.tar.gz -C /usr/local/bin chmod +x /usr/local/bin/staticalize-linux @@ -154,7 +183,9 @@ jobs: staticalize-linux \ --site=http://127.0.0.1:8000 \ --output=www/built \ - --base=https://effection.netlify.app + --base=https://frontside.com/effection \ + --concurrency=75 \ + --retries=3 - name: Deploy to Production run: | diff --git a/www/deno.json b/www/deno.json index bae4ccd87..a31e4c3cf 100644 --- a/www/deno.json +++ b/www/deno.json @@ -1,7 +1,7 @@ { "tasks": { "dev": "deno run -A @effectionx/watch deno run -A main.tsx", - "staticalize": "deno run -A jsr:@frontside/staticalize@0.2.2/cli --site http://localhost:8000 --output=built --base=http://localhost:8000", + "staticalize": "deno run -A jsr:@frontside/staticalize@0.3.0/cli --site http://localhost:8000 --output=built --base=http://localhost:8000 --concurrency=75 --retries=3", "test": "deno test --allow-run --allow-write --allow-read --allow-env" }, "lint": { diff --git a/www/routes/blog-feed-route.tsx b/www/routes/blog-feed-route.tsx index 47921e54e..acb6c4428 100644 --- a/www/routes/blog-feed-route.tsx +++ b/www/routes/blog-feed-route.tsx @@ -1,7 +1,8 @@ -import type { Operation } from "effection"; +import { all, type Operation } from "effection"; import { stringify } from "@libs/xml"; import { useBlog } from "../resources/blog.ts"; +import { url } from "../context/url.ts"; /** * RSS 2.0 feed for the blog @@ -11,8 +12,26 @@ export function blogFeedRoute() { *handler(): Operation { let blog = yield* useBlog(); let posts = blog.getPosts(); + let blogUrl = yield* url("/blog"); + let feed = yield* url("/blog/feed.xml"); + let items = yield* all( + posts.slice(0, 20).map(function* (post) { + let postUrl = yield* url(`/blog/${post.id}/`); - let baseUrl = "https://frontside.com/effection"; + return { + title: post.title, + link: postUrl, + guid: { + "@isPermaLink": "true", + "#text": postUrl, + }, + description: post.description, + pubDate: post.date.toUTCString(), + author: post.author, + category: post.tags, + }; + }), + ); let xml = stringify({ "@version": "1.0", @@ -22,31 +41,17 @@ export function blogFeedRoute() { "@xmlns:atom": "http://www.w3.org/2005/Atom", channel: { title: "Effection Blog", - link: `${baseUrl}/blog`, + link: blogUrl, description: "Tutorials, announcements, and insights about structured concurrency in JavaScript with Effection.", language: "en-us", lastBuildDate: new Date().toUTCString(), "atom:link": { - "@href": `${baseUrl}/blog/feed.xml`, + "@href": feed, "@rel": "self", "@type": "application/rss+xml", }, - item: posts.slice(0, 20).map((post) => { - let postUrl = `${baseUrl}/blog/${post.id}/`; - return { - title: post.title, - link: postUrl, - guid: { - "@isPermaLink": "true", - "#text": postUrl, - }, - description: post.description, - pubDate: post.date.toUTCString(), - author: post.author, - category: post.tags, - }; - }), + item: items, }, }, }); diff --git a/www/routes/llms-txt-route.ts b/www/routes/llms-txt-route.ts index dd7c1cd00..a9c2a10c8 100644 --- a/www/routes/llms-txt-route.ts +++ b/www/routes/llms-txt-route.ts @@ -2,6 +2,7 @@ import type { Operation } from "effection"; import { all } from "effection"; import { useWorkspaces } from "../lib/workspaces/mod.ts"; import type { SitemapRoute } from "../plugins/sitemap.ts"; +import { url } from "../context/url.ts"; import type { Package } from "../lib/package/types.ts"; import { groupPackagesByCategory, @@ -45,24 +46,30 @@ export function llmsTxtRoute(): SitemapRoute { ); // Group packages by category - let categorizedContent = groupPackagesByCategory( - categories, - packageEntries, - ).map( - (category) => { - let packageLines = category.packages.map((pkg) => { - let shortDesc = truncateToFirstSentence(pkg.description, 120); - return `- [${pkg.name}](https://frontside.com/effection/x/${pkg.workspaceName}): ${shortDesc}`; - }); - - return [ - `### ${category.label}`, - "", - category.description, - "", - ...packageLines, - ].join("\n"); - }, + let categorizedContent = yield* all( + groupPackagesByCategory( + categories, + packageEntries, + ).map( + function* (category) { + let packageLines = yield* all( + category.packages.map(function* (pkg) { + let shortDesc = truncateToFirstSentence(pkg.description, 120); + let href = yield* url(`/x/${pkg.workspaceName}`); + + return `- [${pkg.name}](${href}): ${shortDesc}`; + }), + ); + + return [ + `### ${category.label}`, + "", + category.description, + "", + ...packageLines, + ].join("\n"); + }, + ), ); let content = [ @@ -73,7 +80,7 @@ export function llmsTxtRoute(): SitemapRoute { "", ...categorizedContent, "", - LLMS_TXT_FOOTER, + yield* llmsTxtFooter(), ].join("\n"); return new Response(content, { @@ -146,16 +153,24 @@ If any other document conflicts with AGENTS.md, **AGENTS.md takes precedence**. --- `; -const LLMS_TXT_FOOTER = `## Optional +function* llmsTxtFooter(): Operation { + let [catalog, blog, api, guides] = yield* all([ + url("/x/"), + url("/blog"), + url("/api/"), + url("/guides/v4"), + ]); + + return `## Optional -- [Full EffectionX catalog with documentation](https://frontside.com/effection/x/) -- [Effection Blog](https://frontside.com/effection/blog) +- [Full EffectionX catalog with documentation](${catalog}) +- [Effection Blog](${blog}) --- [AGENTS.md]: https://raw.githubusercontent.com/thefrontside/effection/v4/AGENTS.md -[API]: https://frontside.com/effection/api/ -[Guides]: https://frontside.com/effection/guides/v4 +[API]: ${api} +[Guides]: ${guides} [Thinking in Effection]: https://raw.githubusercontent.com/thefrontside/effection/v4/docs/thinking-in-effection.mdx [Async Rosetta Stone]: https://raw.githubusercontent.com/thefrontside/effection/v4/docs/async-rosetta-stone.mdx [Operations]: https://raw.githubusercontent.com/thefrontside/effection/v4/docs/operations.mdx @@ -164,3 +179,4 @@ const LLMS_TXT_FOOTER = `## Optional [Spawn]: https://raw.githubusercontent.com/thefrontside/effection/v4/docs/spawn.mdx [Collections]: https://raw.githubusercontent.com/thefrontside/effection/v4/docs/collections.mdx `; +}