Initial commit

This commit is contained in:
Zhongwei Li
2025-11-30 08:25:40 +08:00
commit 69df674920
25 changed files with 4327 additions and 0 deletions

View File

@@ -0,0 +1,148 @@
/**
* Cloudflare Worker Backend for TinaCMS
*
* This Worker provides a self-hosted TinaCMS backend on Cloudflare's edge network.
*
* Features:
* - GraphQL API for content management
* - Authentication via Auth.js or custom providers
* - Local development mode
* - Global edge deployment
*
* Setup:
* 1. Install dependencies: npm install @tinacms/datalayer tinacms-authjs
* 2. Generate database client: npx @tinacms/cli@latest init backend
* 3. Configure wrangler.jsonc
* 4. Deploy: npx wrangler deploy
*
* Environment Variables:
* - TINA_PUBLIC_IS_LOCAL: "true" for local dev, "false" for production
* - NEXTAUTH_SECRET: Secret key for Auth.js (production only)
*/
import { TinaNodeBackend, LocalBackendAuthProvider } from '@tinacms/datalayer'
import { AuthJsBackendAuthProvider, TinaAuthJSOptions } from 'tinacms-authjs'
// @ts-ignore - Generated by TinaCMS CLI
import databaseClient from '../../tina/__generated__/databaseClient'
/**
* Cloudflare Workers Environment
*
* Extend this interface to add your environment variables and bindings
*/
interface Env {
// Environment variables
TINA_PUBLIC_IS_LOCAL?: string
NEXTAUTH_SECRET?: string
// Optional: KV namespace for session storage
// SESSION_KV?: KVNamespace
// Optional: D1 database for user management
// DB?: D1Database
}
/**
* Main Worker Handler
*
* Processes incoming requests and routes them to the TinaCMS backend
*/
export default {
async fetch(request: Request, env: Env, ctx: ExecutionContext): Promise<Response> {
// Determine if we're in local development mode
const isLocal = env.TINA_PUBLIC_IS_LOCAL === 'true'
// Initialize TinaCMS backend
const handler = TinaNodeBackend({
authProvider: isLocal
? LocalBackendAuthProvider()
: AuthJsBackendAuthProvider({
authOptions: TinaAuthJSOptions({
databaseClient,
secret: env.NEXTAUTH_SECRET || '',
// Add OAuth providers here:
// providers: [
// DiscordProvider({
// clientId: env.DISCORD_CLIENT_ID,
// clientSecret: env.DISCORD_CLIENT_SECRET,
// }),
// ],
}),
}),
databaseClient,
})
try {
// Handle CORS preflight requests
if (request.method === 'OPTIONS') {
return new Response(null, {
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, OPTIONS',
'Access-Control-Allow-Headers': 'Content-Type, Authorization',
},
})
}
// Process the request through TinaCMS
const response = await handler(request)
// Add CORS headers to response
const corsResponse = new Response(response.body, response)
corsResponse.headers.set('Access-Control-Allow-Origin': '*')
corsResponse.headers.set('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS')
corsResponse.headers.set('Access-Control-Allow-Headers', 'Content-Type, Authorization')
return corsResponse
} catch (error) {
console.error('TinaCMS Backend Error:', error)
return new Response(
JSON.stringify({
error: 'Internal Server Error',
message: error instanceof Error ? error.message : 'Unknown error',
}),
{
status: 500,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*',
},
}
)
}
},
}
/**
* Alternative: Hono-based Implementation (Recommended)
*
* For more flexibility, use Hono framework:
*
* import { Hono } from 'hono'
* import { cors } from 'hono/cors'
*
* const app = new Hono()
*
* app.use('/*', cors())
*
* app.all('/api/tina/*', async (c) => {
* const isLocal = c.env.TINA_PUBLIC_IS_LOCAL === 'true'
*
* const handler = TinaNodeBackend({
* authProvider: isLocal
* ? LocalBackendAuthProvider()
* : AuthJsBackendAuthProvider({
* authOptions: TinaAuthJSOptions({
* databaseClient,
* secret: c.env.NEXTAUTH_SECRET,
* }),
* }),
* databaseClient,
* })
*
* return handler(c.req.raw)
* })
*
* export default app
*/

View File

@@ -0,0 +1,55 @@
{
"$schema": "https://raw.githubusercontent.com/cloudflare/wrangler/main/npm/wrangler/wrangler-schema.json",
"name": "tina-backend",
"main": "src/index.ts",
"compatibility_date": "2025-10-24",
"compatibility_flags": ["nodejs_compat"],
// Environment variables for development
"vars": {
"TINA_PUBLIC_IS_LOCAL": "false"
},
// Environment-specific configurations
"env": {
"development": {
"vars": {
"TINA_PUBLIC_IS_LOCAL": "true"
}
},
"production": {
"vars": {
"TINA_PUBLIC_IS_LOCAL": "false"
},
// Add secrets via: wrangler secret put NEXTAUTH_SECRET
"secrets": [
"NEXTAUTH_SECRET"
]
}
},
// Optional: Add KV for session storage
// "kv_namespaces": [
// {
// "binding": "SESSION_KV",
// "id": "your-kv-namespace-id"
// }
// ],
// Optional: Add D1 for user management
// "d1_databases": [
// {
// "binding": "DB",
// "database_name": "tina-users",
// "database_id": "your-d1-database-id"
// }
// ],
// Routes configuration (adjust based on your setup)
"routes": [
{
"pattern": "yourdomain.com/api/tina/*",
"zone_name": "yourdomain.com"
}
]
}