Migrate project to Gitea
Some checks failed
CI / ci (push) Has been cancelled
CI / docker-build (push) Has been cancelled
Publish Docker image / docker (push) Has been cancelled
Upload sourcemaps / upload (push) Has been cancelled

This commit is contained in:
Developer 2026-09-08 21:08:29 +00:00
parent 3632f40852
commit aefbf86e08
7 changed files with 160 additions and 106 deletions

0
drizzle-kit Normal file
View File

View File

@ -10,6 +10,6 @@ export default defineConfig({
schema: "./src/db/pg/schema.ts", schema: "./src/db/pg/schema.ts",
out: "./drizzle-pg", out: "./drizzle-pg",
dbCredentials: { dbCredentials: {
url: process.env.POSTGRES_DATABASE_URL!, url: "postgres://openseo_user:Metatron2026@localhost:5432/openseo",
}, },
}); });

0
open-seo@0.1.7 Normal file
View File

View File

@ -7,6 +7,7 @@
"packageManager": "pnpm@10.30.1", "packageManager": "pnpm@10.30.1",
"scripts": { "scripts": {
"dev": "vite dev", "dev": "vite dev",
"start": " vite preview --port 3001",
"dev:clear-chat": "rm -rf .wrangler/state/v3/do/open-seo-OnboardingChatAgent", "dev:clear-chat": "rm -rf .wrangler/state/v3/do/open-seo-OnboardingChatAgent",
"dev:agents": "mkdir -p .logs && portless run vite dev 2>&1 | tee .logs/dev-server.log", "dev:agents": "mkdir -p .logs && portless run vite dev 2>&1 | tee .logs/dev-server.log",
"dev:agents:force": "mkdir -p .logs && portless --force run vite dev 2>&1 | tee .logs/dev-server.log", "dev:agents:force": "mkdir -p .logs && portless --force run vite dev 2>&1 | tee .logs/dev-server.log",

View File

@ -1,5 +1,5 @@
import { tanstackStart } from "@tanstack/react-start/plugin/vite"; import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import { defineConfig, loadEnv } from "vite"; import { defineConfig } from "vite";
import tsConfigPaths from "vite-tsconfig-paths"; import tsConfigPaths from "vite-tsconfig-paths";
import viteReact from "@vitejs/plugin-react"; import viteReact from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite"; import tailwindcss from "@tailwindcss/vite";
@ -7,19 +7,14 @@ import { cloudflare } from "@cloudflare/vite-plugin";
import { devtools } from "@tanstack/devtools-vite"; import { devtools } from "@tanstack/devtools-vite";
import { leanWorkerBundle } from "./vite-plugin-lean-worker-bundle"; import { leanWorkerBundle } from "./vite-plugin-lean-worker-bundle";
export default defineConfig(({ mode }) => { export default defineConfig(() => {
const env = loadEnv(mode, process.cwd(), ""); const port = 3001;
const port = process.env.PORT
? Number(process.env.PORT) const showDevtools = false;
: env.PORT
? Number(env.PORT)
: 3001;
const showDevtools = env.VITE_SHOW_DEVTOOLS !== "false";
const allowedHosts = [ const allowedHosts = [
env.ALLOWED_HOST, "seo.thedomainnest.com",
env.BETTER_AUTH_URL ? new URL(env.BETTER_AUTH_URL).hostname : undefined, ];
].filter((host): host is string => Boolean(host));
const emitSourcemaps = env.POSTHOG_SOURCEMAPS === "true";
return { return {
envPrefix: [ envPrefix: [
@ -30,20 +25,27 @@ export default defineConfig(({ mode }) => {
"POSTHOG_HOST", "POSTHOG_HOST",
"TURNSTILE_SITE_KEY", "TURNSTILE_SITE_KEY",
], ],
server: { server: {
allowedHosts, host: "0.0.0.0",
port, port,
allowedHosts,
}, },
preview: { preview: {
allowedHosts, host: "0.0.0.0",
port, port,
allowedHosts,
}, },
build: { build: {
sourcemap: emitSourcemaps, sourcemap: false,
outDir: emitSourcemaps ? "dist-sourcemaps" : "dist", outDir: "dist",
}, },
plugins: [ plugins: [
leanWorkerBundle(), leanWorkerBundle(),
showDevtools showDevtools
? devtools({ ? devtools({
consolePiping: { consolePiping: {
@ -52,18 +54,23 @@ export default defineConfig(({ mode }) => {
}, },
}) })
: null, : null,
cloudflare({ cloudflare({
inspectorPort: false, inspectorPort: false,
viteEnvironment: { name: "ssr" }, viteEnvironment: { name: "ssr" },
// The site-audit aux worker builds to dist/open_seo_audit/ and runs auxiliaryWorkers: [
// beside the main worker in dev and preview, with the app's {
// cross-script SITE_AUDIT_WORKFLOW / AUDIT_SCRATCHPAD bindings configPath: "./wrangler.audit.jsonc",
// resolved against it. },
auxiliaryWorkers: [{ configPath: "./wrangler.audit.jsonc" }], ],
}), }),
tsConfigPaths(), tsConfigPaths(),
tanstackStart(), tanstackStart(),
viteReact(), viteReact(),
tailwindcss(), tailwindcss(),
], ],
}; };

70
vite.config.ts.backup Normal file
View File

@ -0,0 +1,70 @@
import { tanstackStart } from "@tanstack/react-start/plugin/vite";
import { defineConfig, loadEnv } from "vite";
import tsConfigPaths from "vite-tsconfig-paths";
import viteReact from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
import { cloudflare } from "@cloudflare/vite-plugin";
import { devtools } from "@tanstack/devtools-vite";
import { leanWorkerBundle } from "./vite-plugin-lean-worker-bundle";
export default defineConfig(({ mode }) => {
const env = loadEnv(mode, process.cwd(), "");
const port = process.env.PORT
? Number(process.env.PORT)
: env.PORT
? Number(env.PORT)
: 3001;
const showDevtools = env.VITE_SHOW_DEVTOOLS !== "false";
const allowedHosts = [
env.ALLOWED_HOST,
env.BETTER_AUTH_URL ? new URL(env.BETTER_AUTH_URL).hostname : undefined,
].filter((host): host is string => Boolean(host));
const emitSourcemaps = env.POSTHOG_SOURCEMAPS === "true";
return {
envPrefix: [
"VITE_",
"AUTH_MODE",
"BYPASS_EMAIL_VERIFICATION",
"POSTHOG_PUBLIC_KEY",
"POSTHOG_HOST",
"TURNSTILE_SITE_KEY",
],
server: {
allowedHosts,
port,
},
preview: {
allowedHosts,
port,
},
build: {
sourcemap: emitSourcemaps,
outDir: emitSourcemaps ? "dist-sourcemaps" : "dist",
},
plugins: [
leanWorkerBundle(),
showDevtools
? devtools({
consolePiping: {
enabled: true,
levels: ["log", "warn", "error", "info", "debug"],
},
})
: null,
cloudflare({
inspectorPort: false,
viteEnvironment: { name: "ssr" },
// The site-audit aux worker builds to dist/open_seo_audit/ and runs
// beside the main worker in dev and preview, with the app's
// cross-script SITE_AUDIT_WORKFLOW / AUDIT_SCRATCHPAD bindings
// resolved against it.
auxiliaryWorkers: [{ configPath: "./wrangler.audit.jsonc" }],
}),
tsConfigPaths(),
tanstackStart(),
viteReact(),
tailwindcss(),
],
};
});

View File

@ -3,146 +3,122 @@
"name": "open-seo", "name": "open-seo",
"main": "src/server.ts", "main": "src/server.ts",
"compatibility_date": "2025-09-02", "compatibility_date": "2025-09-02",
"compatibility_flags": ["nodejs_compat", "global_fetch_strictly_public"], "compatibility_flags": [
"nodejs_compat",
"global_fetch_strictly_public"
],
"observability": { "observability": {
"enabled": true, "enabled": true,
// Spans are billed as observability events (free tier 200k/day); add a
// traces head_sampling_rate below 1 if span volume becomes a cost concern.
"traces": { "traces": {
"enabled": true, "enabled": true
}, }
}, },
// Smart Placement relocates only the `fetch` handler (cron + Workflow runs
// stay at the edge) toward external subrequests Postgres via Hyperdrive,
// SEO APIs not D1/KV/R2 bindings, so it's a DB no-op on the D1 default.
// Must live here: a dashboard-only toggle is wiped by `wrangler deploy`.
"placement": { "placement": {
"mode": "smart", "mode": "smart"
}, },
"workflows": [ "workflows": [
// The site-audit engine lives in the open-seo-audit aux worker
// (wrangler.audit.jsonc) its memory spikes (multi-MB Lighthouse
// payloads, in-flight HTML) OOMed this worker's near-limit baseline
// heap. This is a cross-script binding for starting audits and reading
// instance status.
{ {
"name": "site-audit-workflow", "name": "site-audit-workflow",
"binding": "SITE_AUDIT_WORKFLOW", "binding": "SITE_AUDIT_WORKFLOW",
"class_name": "SiteAuditWorkflow", "class_name": "SiteAuditWorkflow",
"script_name": "open-seo-audit", "script_name": "open-seo-audit"
}, },
{ {
"name": "rank-check-workflow", "name": "rank-check-workflow",
"binding": "RANK_CHECK_WORKFLOW", "binding": "RANK_CHECK_WORKFLOW",
"class_name": "RankCheckWorkflow", "class_name": "RankCheckWorkflow"
}, }
], ],
// Durable Object backing the onboarding strategy chat (Agents SDK
// AIChatAgent). One instance per project; messages persist in the DO's
// SQLite. SQLite-backed classes must be declared in `migrations` below for
// the wrangler/workerd surfaces (local dev, Docker self-host); Alchemy
// deploys derive SQLite backing on their own.
"durable_objects": { "durable_objects": {
"bindings": [ "bindings": [
{ {
"name": "ONBOARDING_CHAT", "name": "ONBOARDING_CHAT",
"class_name": "OnboardingChatAgent", "class_name": "OnboardingChatAgent"
}, },
// SAM in-app agent. One instance per chat session; messages persist in the
// DO's SQLite. SQLite-backed classes must be declared in `migrations`.
{ {
"name": "SAM_CHAT", "name": "SAM_CHAT",
"class_name": "SamChatAgent", "class_name": "SamChatAgent"
}, }
], ]
}, },
// The site-audit engine lives in the open-seo-audit aux worker
// (wrangler.audit.jsonc), including the scratchpad DO the DO cannot be
// bound cross-script here (the Cloudflare API rejects deleting the class
// below while any binding still references its name). Cancel + GDPR
// erasure go through this service binding's AuditEngine entrypoint.
"services": [ "services": [
{ {
"binding": "AUDIT_ENGINE", "binding": "AUDIT_ENGINE",
"service": "open-seo-audit", "service": "open-seo-audit"
}, }
], ],
"migrations": [ "migrations": [
{ {
"tag": "v1", "tag": "v1",
"new_sqlite_classes": ["OnboardingChatAgent"], "new_sqlite_classes": [
"OnboardingChatAgent"
]
}, },
{ {
"tag": "v2", "tag": "v2",
"new_sqlite_classes": ["SamChatAgent"], "new_sqlite_classes": [
"SamChatAgent"
]
}, },
{ {
"tag": "v3", "tag": "v3",
"new_sqlite_classes": ["AuditScratchpad"], "new_sqlite_classes": [
"AuditScratchpad"
]
}, },
// AuditScratchpad moved to the open-seo-audit worker (no binding may
// still reference the class name in the same upload see the services
// comment above). Deleting it here is safe: scratchpad state is
// disposable by design (destroyed at finalize, 7-day cleanup alarm)
// in-flight audits at the cutover fail once and the stale-audit
// reconciler reaps them.
{ {
"tag": "v4", "tag": "v4",
"deleted_classes": ["AuditScratchpad"], "deleted_classes": [
}, "AuditScratchpad"
]
}
], ],
"triggers": { "triggers": {
// Every 5 min: rank checks + stale-audit reconcile. Daily: OAuth KV GC. "crons": [
// Dispatched on controller.cron in src/server.ts `scheduled`. "*/5 * * * *",
"crons": ["*/5 * * * *", "17 3 * * *"], "17 3 * * *"
]
}, },
// This config serves local dev and Docker self-host only. All Cloudflare
// deployments previews, prod, self-host go through Alchemy
// (alchemy.run.ts), which provisions real resources per stage and never
// reads these ids.
//
// The ids below are NOT dead config: miniflare derives its on-disk storage
// filenames (.wrangler/state, a persistent volume in Docker self-hosts)
// from an HMAC of `id`/`database_id`. Changing them orphans every existing
// local and self-hosted database. Leave them as-is.
"kv_namespaces": [ "kv_namespaces": [
{ {
"binding": "KV", "binding": "KV",
"id": "4abd52f3f2c549ac83cc2cb4ceec8620", "id": "4abd52f3f2c549ac83cc2cb4ceec8620"
}, },
{ {
"binding": "OAUTH_KV", "binding": "OAUTH_KV",
"id": "bd1759494309474a9b423b029967b0db", "id": "bd1759494309474a9b423b029967b0db"
}, }
], ],
"d1_databases": [ "d1_databases": [
{ {
"binding": "DB", "binding": "DB",
"database_name": "open-seo", "database_name": "open-seo",
"database_id": "37bee90a-e1aa-404f-b01e-b0d1d479bda1", "database_id": "37bee90a-e1aa-404f-b01e-b0d1d479bda1",
"migrations_dir": "drizzle", "migrations_dir": "drizzle"
}, }
], ],
// Postgres scale path (opt-in; D1 is the default). Hyperdrive is the ONLY way
// the app connects to Postgres there is no direct-connection fallback. For "hyperdrive": [
// local dev, `localConnectionString` is the throwaway Docker Postgres from {
// docs/LOCAL_POSTGRES.md, and nothing connects to it unless "binding": "HYPERDRIVE",
// DATABASE_PROVIDER=postgres is set in .env.local. "id": "local",
// "localConnectionString": "postgres://openseo_user:Metatron2026@localhost:5432/openseo"
// Kept commented out: the id lives in OpenSEO's account, and only local }
// Postgres dev reads this block (Alchemy deploys and the Docker image never ],
// do). Uncomment when running local Postgres dev per docs/LOCAL_POSTGRES.md.
// "hyperdrive": [
// {
// "binding": "HYPERDRIVE",
// "id": "9d64ccfb559f44449ce52a143912f898",
// "localConnectionString": "postgres://openseo:openseo@localhost:5433/openseo",
// },
// ],
"r2_buckets": [ "r2_buckets": [
{ {
"bucket_name": "open-seo", "bucket_name": "open-seo",
"binding": "R2", "binding": "R2"
}, }
], ]
} }