[READ-ONLY] Mirror of https://github.com/flo-bit/bluesky-website-generator. bluesky-website-generator.vercel.app
0

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #3 from flo-bit/cloudflar_pages

Cloudflar pages

author
Florian
committer
GitHub
date (May 5, 2025, 2:07 AM +0200) commit 127205c8 parent 7428a107
+157 -1
+20 -1
src/routes/+page.svelte
··· 20 20 import type { FeedViewPost } from '@atproto/api/dist/client/types/app/bsky/feed/defs.js'; 21 21 import Navbar from '$lib/Navbar.svelte'; 22 22 23 + let value = $state(''); 24 + 23 25 let { data } = $props(); 26 + let form = $state<HTMLFormElement | null>(null); 24 27 25 - let form = $state<HTMLFormElement | null>(null); 28 + async function deploy() { 29 + const res = await fetch('/api/cloudflare', { 30 + method: 'POST', 31 + headers: { 'Content-Type': 'application/json' }, 32 + body: JSON.stringify({ 33 + projectName: data.user.handle.replace(/\./g, '-'), 34 + domain: value + '.polijn.com', 35 + profileHandle: data.user.handle 36 + }) 37 + }); 26 38 39 + // const data = await res.json(); 40 + // if (!res.ok) { 41 + // alert('Error: ' + data.error); 42 + // } else { 43 + // alert('Success!); 44 + // } 45 + } 27 46 onMount(async () => { 28 47 editingState.links = JSON.parse(localStorage.getItem('links') ?? '[]'); 29 48
+137
src/routes/api/cloudflare/+server.ts
··· 1 + import type { RequestEvent } from '@sveltejs/kit'; 2 + import { env } from '$env/dynamic/private'; 3 + 4 + const ACCOUNT_ID = env.CLOUDFLARE_ACCOUNT_ID; 5 + const ZONE_ID = env.CLOUDFLARE_ZONE_ID; 6 + const PAGES_TOKEN = env.CLOUDFLARE_API_TOKEN_PAGES; 7 + const ZONES_TOKEN = env.CLOUDFLARE_API_TOKEN_ZONES; 8 + 9 + async function createPagesProject(projectName: string, profileHandle: string) { 10 + const url = `https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/pages/projects`; 11 + const payload = { 12 + name: projectName, 13 + production_branch: 'main', 14 + build_config: { 15 + build_caching: true, 16 + build_command: 'npm run build', 17 + destination_dir: 'dist' 18 + }, 19 + deployment_configs: { 20 + production: { 21 + env_vars: { 22 + HANDLE: { type: 'plain_text', value: profileHandle } 23 + } 24 + } 25 + }, 26 + source: { 27 + type: 'github', 28 + config: { 29 + owner: 'polijn', 30 + repo_name: 'bluesky-home', 31 + deployments_enabled: false 32 + } 33 + } 34 + }; 35 + console.log('payload:'); 36 + console.log(payload.deployment_configs); 37 + const res = await fetch(url, { 38 + method: 'POST', 39 + headers: { 40 + 'Content-Type': 'application/json', 41 + Authorization: `Bearer ${PAGES_TOKEN}` 42 + }, 43 + body: JSON.stringify(payload) 44 + }); 45 + 46 + const data = await res.json(); 47 + console.log('createPagesProject:'); 48 + console.log(data); 49 + if (!data.success) throw new Error(JSON.stringify(data.errors)); 50 + return data.result; 51 + } 52 + 53 + async function triggerDeployment(projectName: string) { 54 + const url = `https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/pages/projects/${projectName}/deployments`; 55 + const form = new FormData(); 56 + form.append('branch', 'main'); 57 + 58 + const res = await fetch(url, { 59 + method: 'POST', 60 + headers: { Authorization: `Bearer ${PAGES_TOKEN}` }, 61 + body: form 62 + }); 63 + 64 + const data = await res.json(); 65 + console.log('triggerDeployment:'); 66 + console.log(data); 67 + if (!data.success) throw new Error(JSON.stringify(data.errors)); 68 + return data.result; 69 + } 70 + 71 + async function addCustomDomain(projectName: string, domain: string) { 72 + const url = `https://api.cloudflare.com/client/v4/accounts/${ACCOUNT_ID}/pages/projects/${projectName}/domains`; 73 + const res = await fetch(url, { 74 + method: 'POST', 75 + headers: { 76 + 'Content-Type': 'application/json', 77 + Authorization: `Bearer ${PAGES_TOKEN}` 78 + }, 79 + body: JSON.stringify({ name: domain }) 80 + }); 81 + 82 + const data = await res.json(); 83 + console.log('addCustomDomain:'); 84 + console.log(data); 85 + if (!data.success) throw new Error(JSON.stringify(data.errors)); 86 + return data.result; 87 + } 88 + 89 + async function createDNSRecord(name: string, target: string) { 90 + const url = `https://api.cloudflare.com/client/v4/zones/${ZONE_ID}/dns_records`; 91 + const payload = { 92 + type: 'CNAME', 93 + name, 94 + content: target, 95 + ttl: 3600, 96 + proxied: true, 97 + comment: 'personal subdomain' 98 + }; 99 + 100 + const res = await fetch(url, { 101 + method: 'POST', 102 + headers: { 103 + 'Content-Type': 'application/json', 104 + Authorization: `Bearer ${ZONES_TOKEN}` 105 + }, 106 + body: JSON.stringify(payload) 107 + }); 108 + 109 + const data = await res.json(); 110 + console.log('createDNSRecord:'); 111 + console.log(data); 112 + if (!data.success) throw new Error(JSON.stringify(data.errors)); 113 + return data.result; 114 + } 115 + 116 + export async function POST(event: RequestEvent) { 117 + const { projectName, domain, profileHandle } = await event.request.json(); 118 + 119 + try { 120 + const project = await createPagesProject(projectName, profileHandle); 121 + const devSubdomain = project.subdomain; 122 + await new Promise((resolve) => setTimeout(resolve, 2000)); 123 + const domainResult = await addCustomDomain(projectName, domain); 124 + await new Promise((resolve) => setTimeout(resolve, 2000)); 125 + const dnsRecordId = await createDNSRecord(domain, devSubdomain); 126 + await new Promise((resolve) => setTimeout(resolve, 2000)); 127 + const deploymentResult = await triggerDeployment(projectName); 128 + 129 + // , devSubdomain, bindingId, dnsRecordId 130 + return new Response(JSON.stringify({ project }), { 131 + status: 200, 132 + headers: { 'Content-Type': 'application/json' } 133 + }); 134 + } catch (error) { 135 + return new Response(JSON.stringify({ error: error.message }), { status: 500 }); 136 + } 137 + }